2 * drivers/extcon/extcon-gpio-states.c
4 * Multiple GPIO state based based on extcon class driver.
6 * Author: Laxman Dewangan <ldewangan@nvidia.com>
8 * Based on extcon-gpio driver by
9 * Copyright (C) 2008 Google, Inc.
10 * Author: Mike Lockwood <lockwood@android.com>
12 * This software is licensed under the terms of the GNU General Public
13 * License version 2, as published by the Free Software Foundation, and
14 * may be copied, distributed, and modified under those terms.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/init.h>
25 #include <linux/interrupt.h>
26 #include <linux/platform_device.h>
27 #include <linux/slab.h>
28 #include <linux/workqueue.h>
29 #include <linux/gpio.h>
30 #include <linux/extcon.h>
32 #include <linux/of_gpio.h>
33 #include <linux/spinlock.h>
34 #include <linux/wakelock.h>
36 #define EXTCON_GPIO_STATE_WAKEUP_TIME 5000
38 struct gpio_extcon_cables {
48 struct gpio_extcon_platform_data {
50 unsigned long debounce;
51 unsigned long irq_flags;
52 struct gpio_info *gpios;
54 const char **out_cable_name;
56 struct gpio_extcon_cables *cable_states;
58 int cable_detect_delay;
61 struct gpio_extcon_info {
63 struct extcon_dev edev;
64 struct delayed_work work;
65 unsigned long debounce_jiffies;
66 struct timer_list timer;
67 int timer_to_work_jiffies;
70 struct gpio_extcon_platform_data *pdata;
71 struct wake_lock wake_lock;
72 int cable_detect_jiffies;
75 static void gpio_extcon_work(struct work_struct *work)
79 struct gpio_extcon_info *gpex = container_of(to_delayed_work(work),
80 struct gpio_extcon_info, work);
84 for (i = 0; i < gpex->pdata->n_gpio; ++i) {
85 state = gpio_get_value_cansleep(gpex->pdata->gpios[i].gpio);
90 for (i = 0; i < gpex->pdata->n_cable_states; ++i) {
91 if (gpex->pdata->cable_states[i].gstate == gstate) {
92 cstate = gpex->pdata->cable_states[i].cstate;
98 dev_info(gpex->dev, "Cable state not found 0x%02x\n", gstate);
102 dev_info(gpex->dev, "Cable state %d\n", cstate);
103 extcon_set_state(&gpex->edev, cstate);
106 static void gpio_extcon_notifier_timer(unsigned long _data)
108 struct gpio_extcon_info *gpex = (struct gpio_extcon_info *)_data;
110 /*take wakelock to complete cable detection */
111 if (!wake_lock_active(&gpex->wake_lock))
112 wake_lock_timeout(&gpex->wake_lock, gpex->cable_detect_jiffies);
114 schedule_delayed_work(&gpex->work, gpex->timer_to_work_jiffies);
117 static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
119 struct gpio_extcon_info *gpex = dev_id;
122 spin_lock_irqsave(&gpex->lock, flags);
123 mod_timer(&gpex->timer, jiffies + gpex->debounce_jiffies);
124 spin_unlock_irqrestore(&gpex->lock, flags);
129 static struct gpio_extcon_platform_data *of_get_platform_data(
130 struct platform_device *pdev)
132 struct gpio_extcon_platform_data *pdata;
133 struct device_node *np = pdev->dev.of_node;
139 struct property *prop;
142 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
144 return ERR_PTR(-ENOMEM);
146 of_property_read_string(np, "extcon-gpio,name", &pdata->name);
148 pdata->name = np->name;
150 n_gpio = of_gpio_named_count(np, "gpios");
152 dev_err(&pdev->dev, "Not sufficient gpios\n");
153 return ERR_PTR(-EINVAL);
156 pdata->n_gpio = n_gpio;
157 pdata->gpios = devm_kzalloc(&pdev->dev,
158 sizeof(*pdata->gpios) * n_gpio, GFP_KERNEL);
160 return ERR_PTR(-ENOMEM);
161 for (count = 0; count < n_gpio; ++count) {
162 gpio = of_get_named_gpio(np, "gpios", count);
163 if ((gpio < 0) && (gpio != -ENOENT))
164 return ERR_PTR(gpio);
165 pdata->gpios[count].gpio = gpio;
168 ret = of_property_read_u32(np, "extcon-gpio,irq-flags", &pval);
170 pdata->irq_flags = pval;
172 pdata->irq_flags = IRQF_TRIGGER_RISING |
173 IRQF_TRIGGER_FALLING;
175 ret = of_property_read_u32(np, "extcon-gpio,debounce", &pval);
177 pdata->debounce = pval;
179 pdata->debounce = 10;
181 ret = of_property_read_u32(np, "cable-detect-delay", &pval);
183 pdata->cable_detect_delay = pval;
185 pdata->cable_detect_delay = EXTCON_GPIO_STATE_WAKEUP_TIME;
187 pdata->n_out_cables = of_property_count_strings(np,
188 "extcon-gpio,out-cable-names");
189 if (pdata->n_out_cables <= 0) {
190 dev_err(&pdev->dev, "not found out cable names\n");
191 return ERR_PTR(-EINVAL);
194 pdata->out_cable_name = devm_kzalloc(&pdev->dev,
195 (pdata->n_out_cables + 1) *
196 sizeof(*pdata->out_cable_name), GFP_KERNEL);
197 if (!pdata->out_cable_name)
198 return ERR_PTR(-ENOMEM);
200 of_property_for_each_string(np, "extcon-gpio,out-cable-names",
202 pdata->out_cable_name[count++] = names;
203 pdata->out_cable_name[count] = NULL;
205 pdata->n_cable_states = of_property_count_u32(np,
206 "extcon-gpio,cable-states");
207 if (pdata->n_cable_states < 2) {
208 dev_err(&pdev->dev, "not found proper cable state\n");
209 return ERR_PTR(-EINVAL);
211 pdata->n_cable_states /= 2;
212 pdata->cable_states = devm_kzalloc(&pdev->dev,
213 (pdata->n_cable_states) *
214 sizeof(*pdata->cable_states), GFP_KERNEL);
215 if (!pdata->cable_states)
216 return ERR_PTR(-ENOMEM);
217 for (count = 0; count < pdata->n_cable_states; ++count) {
218 ret = of_property_read_u32_index(np, "extcon-gpio,cable-states",
221 pdata->cable_states[count].gstate = pval;
223 ret = of_property_read_u32_index(np, "extcon-gpio,cable-states",
224 count * 2 + 1, &pval);
226 pdata->cable_states[count].cstate = pval;
232 static int gpio_extcon_probe(struct platform_device *pdev)
234 struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data;
235 struct gpio_extcon_info *gpex;
239 if (!pdata && pdev->dev.of_node) {
240 pdata = of_get_platform_data(pdev);
242 return PTR_ERR(pdata);
247 if (!pdata->irq_flags) {
248 dev_err(&pdev->dev, "IRQ flag is not specified.\n");
252 gpex = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_info),
257 gpex->dev = &pdev->dev;
258 gpex->edev.name = pdata->name;
259 gpex->edev.dev.parent = &pdev->dev;
260 gpex->debounce_jiffies = msecs_to_jiffies(pdata->debounce);
261 gpex->timer_to_work_jiffies = msecs_to_jiffies(100);
262 gpex->edev.supported_cable = pdata->out_cable_name;
263 gpex->cable_detect_jiffies =
264 msecs_to_jiffies(pdata->cable_detect_delay);
266 spin_lock_init(&gpex->lock);
268 for (i = 0; i < gpex->pdata->n_gpio; ++i) {
271 irq = gpio_to_irq(gpex->pdata->gpios[i].gpio);
273 dev_err(&pdev->dev, "gpio %d to irq failed: %d\n",
274 gpex->pdata->gpios[i].gpio, irq);
277 gpex->pdata->gpios[i].irq = irq;
280 wake_lock_init(&gpex->wake_lock, WAKE_LOCK_SUSPEND,
281 "extcon-suspend-lock");
283 ret = extcon_dev_register(&gpex->edev);
287 INIT_DELAYED_WORK(&gpex->work, gpio_extcon_work);
288 setup_timer(&gpex->timer, gpio_extcon_notifier_timer,
289 (unsigned long)gpex);
291 for (i = 0; i < gpex->pdata->n_gpio; ++i) {
292 int gpio = gpex->pdata->gpios[i].gpio;
293 int irq = gpex->pdata->gpios[i].irq;
295 ret = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_DIR_IN,
300 ret = devm_request_any_context_irq(&pdev->dev, irq,
301 gpio_irq_handler, pdata->irq_flags,
307 platform_set_drvdata(pdev, gpex);
308 device_set_wakeup_capable(gpex->dev, true);
310 /* Enable wake default */
311 device_wakeup_enable(gpex->dev);
313 /* Perform initial detection */
314 gpio_extcon_work(&gpex->work.work);
318 extcon_dev_unregister(&gpex->edev);
322 static int gpio_extcon_remove(struct platform_device *pdev)
324 struct gpio_extcon_info *gpex = platform_get_drvdata(pdev);
326 del_timer_sync(&gpex->timer);
327 cancel_delayed_work_sync(&gpex->work);
328 extcon_dev_unregister(&gpex->edev);
332 #ifdef CONFIG_PM_SLEEP
333 static int gpio_extcon_suspend(struct device *dev)
335 struct gpio_extcon_info *gpex = dev_get_drvdata(dev);
338 cancel_delayed_work_sync(&gpex->work);
339 if (device_may_wakeup(gpex->dev)) {
340 for (i = 0; i < gpex->pdata->n_gpio; ++i)
341 enable_irq_wake(gpex->pdata->gpios[i].irq);
347 static int gpio_extcon_resume(struct device *dev)
349 struct gpio_extcon_info *gpex = dev_get_drvdata(dev);
352 if (device_may_wakeup(gpex->dev)) {
353 for (i = 0; i < gpex->pdata->n_gpio; ++i)
354 disable_irq_wake(gpex->pdata->gpios[i].irq);
356 gpio_extcon_work(&gpex->work.work);
360 #endif /* CONFIG_PM_SLEEP */
362 static SIMPLE_DEV_PM_OPS(gpio_extcon_pm_ops, gpio_extcon_suspend,
365 static struct of_device_id of_extcon_gpio_tbl[] = {
366 { .compatible = "extcon-gpio-states", },
369 MODULE_DEVICE_TABLE(of, of_extcon_gpio_tbl);
371 static struct platform_driver gpio_extcon_driver = {
372 .probe = gpio_extcon_probe,
373 .remove = gpio_extcon_remove,
375 .name = "extcon-gpio-states",
376 .owner = THIS_MODULE,
377 .of_match_table = of_extcon_gpio_tbl,
378 .pm = &gpio_extcon_pm_ops,
382 static int __init gpio_extcon_driver_init(void)
384 return platform_driver_register(&gpio_extcon_driver);
386 subsys_initcall_sync(gpio_extcon_driver_init);
388 static void __exit gpio_extcon_driver_exit(void)
390 platform_driver_unregister(&gpio_extcon_driver);
392 module_exit(gpio_extcon_driver_exit);
394 MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
395 MODULE_DESCRIPTION("GPIO state based extcon driver");
396 MODULE_LICENSE("GPL v2");