diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/extcon/extcon-gpio.c | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/extcon/extcon-gpio.c')
-rw-r--r-- | kernel/drivers/extcon/extcon-gpio.c | 143 |
1 files changed, 67 insertions, 76 deletions
diff --git a/kernel/drivers/extcon/extcon-gpio.c b/kernel/drivers/extcon/extcon-gpio.c index 7af33fc43..279ff8f66 100644 --- a/kernel/drivers/extcon/extcon-gpio.c +++ b/kernel/drivers/extcon/extcon-gpio.c @@ -1,7 +1,5 @@ /* - * drivers/extcon/extcon_gpio.c - * - * Single-state GPIO extcon driver based on extcon class + * extcon_gpio.c - Single-state GPIO extcon driver based on extcon class * * Copyright (C) 2008 Google, Inc. * Author: Mike Lockwood <lockwood@android.com> @@ -17,12 +15,12 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * -*/ + */ #include <linux/extcon.h> #include <linux/extcon/extcon-gpio.h> #include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -33,14 +31,12 @@ struct gpio_extcon_data { struct extcon_dev *edev; - unsigned gpio; - bool gpio_active_low; - const char *state_on; - const char *state_off; int irq; struct delayed_work work; unsigned long debounce_jiffies; - bool check_on_resume; + + struct gpio_desc *id_gpiod; + struct gpio_extcon_pdata *pdata; }; static void gpio_extcon_work(struct work_struct *work) @@ -50,112 +46,107 @@ static void gpio_extcon_work(struct work_struct *work) container_of(to_delayed_work(work), struct gpio_extcon_data, work); - state = gpio_get_value(data->gpio); - if (data->gpio_active_low) + state = gpiod_get_value_cansleep(data->id_gpiod); + if (data->pdata->gpio_active_low) state = !state; extcon_set_state(data->edev, state); } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) { - struct gpio_extcon_data *extcon_data = dev_id; + struct gpio_extcon_data *data = dev_id; - queue_delayed_work(system_power_efficient_wq, &extcon_data->work, - extcon_data->debounce_jiffies); + queue_delayed_work(system_power_efficient_wq, &data->work, + data->debounce_jiffies); return IRQ_HANDLED; } -static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf) +static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data) { - struct device *dev = edev->dev.parent; - struct gpio_extcon_data *extcon_data = dev_get_drvdata(dev); - const char *state; - - if (extcon_get_state(edev)) - state = extcon_data->state_on; - else - state = extcon_data->state_off; - - if (state) - return sprintf(buf, "%s\n", state); - return -EINVAL; + struct gpio_extcon_pdata *pdata = data->pdata; + int ret; + + ret = devm_gpio_request_one(dev, pdata->gpio, GPIOF_DIR_IN, + dev_name(dev)); + if (ret < 0) + return ret; + + data->id_gpiod = gpio_to_desc(pdata->gpio); + if (!data->id_gpiod) + return -EINVAL; + + if (pdata->debounce) { + ret = gpiod_set_debounce(data->id_gpiod, + pdata->debounce * 1000); + if (ret < 0) + data->debounce_jiffies = + msecs_to_jiffies(pdata->debounce); + } + + data->irq = gpiod_to_irq(data->id_gpiod); + if (data->irq < 0) + return data->irq; + + return 0; } static int gpio_extcon_probe(struct platform_device *pdev) { - struct gpio_extcon_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct gpio_extcon_data *extcon_data; + struct gpio_extcon_pdata *pdata = dev_get_platdata(&pdev->dev); + struct gpio_extcon_data *data; int ret; if (!pdata) return -EBUSY; - if (!pdata->irq_flags) { - dev_err(&pdev->dev, "IRQ flag is not specified.\n"); + if (!pdata->irq_flags || pdata->extcon_id > EXTCON_NONE) return -EINVAL; - } - extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data), + data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data), GFP_KERNEL); - if (!extcon_data) + if (!data) return -ENOMEM; + data->pdata = pdata; - extcon_data->edev = devm_extcon_dev_allocate(&pdev->dev, NULL); - if (IS_ERR(extcon_data->edev)) { - dev_err(&pdev->dev, "failed to allocate extcon device\n"); - return -ENOMEM; - } - extcon_data->edev->name = pdata->name; - - extcon_data->gpio = pdata->gpio; - extcon_data->gpio_active_low = pdata->gpio_active_low; - extcon_data->state_on = pdata->state_on; - extcon_data->state_off = pdata->state_off; - extcon_data->check_on_resume = pdata->check_on_resume; - if (pdata->state_on && pdata->state_off) - extcon_data->edev->print_state = extcon_gpio_print_state; - - ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN, - pdev->name); + /* Initialize the gpio */ + ret = gpio_extcon_init(&pdev->dev, data); if (ret < 0) return ret; - if (pdata->debounce) { - ret = gpio_set_debounce(extcon_data->gpio, - pdata->debounce * 1000); - if (ret < 0) - extcon_data->debounce_jiffies = - msecs_to_jiffies(pdata->debounce); + /* Allocate the memory of extcon devie and register extcon device */ + data->edev = devm_extcon_dev_allocate(&pdev->dev, &pdata->extcon_id); + if (IS_ERR(data->edev)) { + dev_err(&pdev->dev, "failed to allocate extcon device\n"); + return -ENOMEM; } - ret = devm_extcon_dev_register(&pdev->dev, extcon_data->edev); + ret = devm_extcon_dev_register(&pdev->dev, data->edev); if (ret < 0) return ret; - INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work); - - extcon_data->irq = gpio_to_irq(extcon_data->gpio); - if (extcon_data->irq < 0) - return extcon_data->irq; + INIT_DELAYED_WORK(&data->work, gpio_extcon_work); - ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler, - pdata->irq_flags, pdev->name, - extcon_data); + /* + * Request the interrput of gpio to detect whether external connector + * is attached or detached. + */ + ret = devm_request_any_context_irq(&pdev->dev, data->irq, + gpio_irq_handler, pdata->irq_flags, + pdev->name, data); if (ret < 0) return ret; - platform_set_drvdata(pdev, extcon_data); + platform_set_drvdata(pdev, data); /* Perform initial detection */ - gpio_extcon_work(&extcon_data->work.work); + gpio_extcon_work(&data->work.work); return 0; } static int gpio_extcon_remove(struct platform_device *pdev) { - struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev); + struct gpio_extcon_data *data = platform_get_drvdata(pdev); - cancel_delayed_work_sync(&extcon_data->work); - free_irq(extcon_data->irq, extcon_data); + cancel_delayed_work_sync(&data->work); return 0; } @@ -163,12 +154,12 @@ static int gpio_extcon_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int gpio_extcon_resume(struct device *dev) { - struct gpio_extcon_data *extcon_data; + struct gpio_extcon_data *data; - extcon_data = dev_get_drvdata(dev); - if (extcon_data->check_on_resume) + data = dev_get_drvdata(dev); + if (data->pdata->check_on_resume) queue_delayed_work(system_power_efficient_wq, - &extcon_data->work, extcon_data->debounce_jiffies); + &data->work, data->debounce_jiffies); return 0; } |