2 * drivers/extcon/extcon-adc-jack.c
4 * Analog Jack extcon driver with ADC-based detection capability.
6 * Copyright (C) 2016 Samsung Electronics
7 * Chanwoo Choi <cw00.choi@samsung.com>
9 * Copyright (C) 2012 Samsung Electronics
10 * MyungJoo Ham <myungjoo.ham@samsung.com>
12 * Modified for calling to IIO to get adc by <anish.singh@samsung.com>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
20 #include <linux/module.h>
21 #include <linux/slab.h>
22 #include <linux/device.h>
23 #include <linux/platform_device.h>
24 #include <linux/err.h>
25 #include <linux/interrupt.h>
26 #include <linux/workqueue.h>
27 #include <linux/iio/consumer.h>
28 #include <linux/extcon/extcon-adc-jack.h>
29 #include <linux/extcon-provider.h>
32 * struct adc_jack_data - internal data for adc_jack device driver
33 * @edev: extcon device.
34 * @cable_names: list of supported cables.
35 * @adc_conditions: list of adc value conditions.
36 * @num_conditions: size of adc_conditions.
37 * @irq: irq number of attach/detach event (0 if not exist).
38 * @handling_delay: interrupt handler will schedule extcon event
39 * handling at handling_delay jiffies.
40 * @handler: extcon event handler called by interrupt handler.
41 * @chan: iio channel being queried.
43 struct adc_jack_data
{
45 struct extcon_dev
*edev
;
47 const unsigned int **cable_names
;
48 struct adc_jack_cond
*adc_conditions
;
52 unsigned long handling_delay
; /* in jiffies */
53 struct delayed_work handler
;
55 struct iio_channel
*chan
;
59 static void adc_jack_handler(struct work_struct
*work
)
61 struct adc_jack_data
*data
= container_of(to_delayed_work(work
),
64 struct adc_jack_cond
*def
;
68 ret
= iio_read_channel_raw(data
->chan
, &adc_val
);
70 dev_err(data
->dev
, "read channel() error: %d\n", ret
);
74 /* Get state from adc value with adc_conditions */
75 for (i
= 0; i
< data
->num_conditions
; i
++) {
76 def
= &data
->adc_conditions
[i
];
77 if (def
->min_adc
<= adc_val
&& def
->max_adc
>= adc_val
) {
78 extcon_set_state_sync(data
->edev
, def
->id
, true);
83 /* Set the detached state if adc value is not included in the range */
84 for (i
= 0; i
< data
->num_conditions
; i
++) {
85 def
= &data
->adc_conditions
[i
];
86 extcon_set_state_sync(data
->edev
, def
->id
, false);
90 static irqreturn_t
adc_jack_irq_thread(int irq
, void *_data
)
92 struct adc_jack_data
*data
= _data
;
94 queue_delayed_work(system_power_efficient_wq
,
95 &data
->handler
, data
->handling_delay
);
99 static int adc_jack_probe(struct platform_device
*pdev
)
101 struct adc_jack_data
*data
;
102 struct adc_jack_pdata
*pdata
= dev_get_platdata(&pdev
->dev
);
105 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
109 if (!pdata
->cable_names
) {
110 dev_err(&pdev
->dev
, "error: cable_names not defined.\n");
114 data
->dev
= &pdev
->dev
;
115 data
->edev
= devm_extcon_dev_allocate(&pdev
->dev
, pdata
->cable_names
);
116 if (IS_ERR(data
->edev
)) {
117 dev_err(&pdev
->dev
, "failed to allocate extcon device\n");
121 if (!pdata
->adc_conditions
) {
122 dev_err(&pdev
->dev
, "error: adc_conditions not defined.\n");
125 data
->adc_conditions
= pdata
->adc_conditions
;
127 /* Check the length of array and set num_conditions */
128 for (i
= 0; data
->adc_conditions
[i
].id
!= EXTCON_NONE
; i
++);
129 data
->num_conditions
= i
;
131 data
->chan
= iio_channel_get(&pdev
->dev
, pdata
->consumer_channel
);
132 if (IS_ERR(data
->chan
))
133 return PTR_ERR(data
->chan
);
135 data
->handling_delay
= msecs_to_jiffies(pdata
->handling_delay_ms
);
136 data
->wakeup_source
= pdata
->wakeup_source
;
138 INIT_DEFERRABLE_WORK(&data
->handler
, adc_jack_handler
);
140 platform_set_drvdata(pdev
, data
);
142 err
= devm_extcon_dev_register(&pdev
->dev
, data
->edev
);
146 data
->irq
= platform_get_irq(pdev
, 0);
148 dev_err(&pdev
->dev
, "platform_get_irq failed\n");
152 err
= request_any_context_irq(data
->irq
, adc_jack_irq_thread
,
153 pdata
->irq_flags
, pdata
->name
, data
);
156 dev_err(&pdev
->dev
, "error: irq %d\n", data
->irq
);
160 if (data
->wakeup_source
)
161 device_init_wakeup(&pdev
->dev
, 1);
163 adc_jack_handler(&data
->handler
.work
);
167 static int adc_jack_remove(struct platform_device
*pdev
)
169 struct adc_jack_data
*data
= platform_get_drvdata(pdev
);
171 free_irq(data
->irq
, data
);
172 cancel_work_sync(&data
->handler
.work
);
173 iio_channel_release(data
->chan
);
178 #ifdef CONFIG_PM_SLEEP
179 static int adc_jack_suspend(struct device
*dev
)
181 struct adc_jack_data
*data
= dev_get_drvdata(dev
);
183 cancel_delayed_work_sync(&data
->handler
);
184 if (device_may_wakeup(data
->dev
))
185 enable_irq_wake(data
->irq
);
190 static int adc_jack_resume(struct device
*dev
)
192 struct adc_jack_data
*data
= dev_get_drvdata(dev
);
194 if (device_may_wakeup(data
->dev
))
195 disable_irq_wake(data
->irq
);
199 #endif /* CONFIG_PM_SLEEP */
201 static SIMPLE_DEV_PM_OPS(adc_jack_pm_ops
,
202 adc_jack_suspend
, adc_jack_resume
);
204 static struct platform_driver adc_jack_driver
= {
205 .probe
= adc_jack_probe
,
206 .remove
= adc_jack_remove
,
209 .pm
= &adc_jack_pm_ops
,
213 module_platform_driver(adc_jack_driver
);
215 MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
216 MODULE_DESCRIPTION("ADC Jack extcon driver");
217 MODULE_LICENSE("GPL v2");