-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extcon: support generic GPIO extcon driver
The generic GPIO extcon driver (an external connector device based on GPIO control) and imported from Android kernel. switch: switch class and GPIO drivers. (splitted) Author: Mike Lockwood <lockwood@android.com> switch: gpio: Don't call request_irq with interrupts disabled Author: Arve Hjønnevåg <arve@android.com> switch_gpio: Add missing #include <linux/interrupt.h> Author: Mike Lockwood <lockwood@android.com> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> -- Changed from v7: - Style updates mentioned by Stephen Boyd and Mark Brown Changed from v5: - Splitted at v5 from the main extcon patch. - Added debounce time for irq handlers. - Use request_any_context_irq instead of request_irq - User needs to specify irq flags for GPIO interrupts (was fixed to IRQF_TRIGGER_LOW before) - Use module_platform_driver(). Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- Loading branch information
MyungJoo Ham
authored and
Greg Kroah-Hartman
committed
Apr 20, 2012
1 parent
de55d87
commit be48308
Showing
4 changed files
with
229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
# | ||
|
||
obj-$(CONFIG_EXTCON) += extcon_class.o | ||
obj-$(CONFIG_EXTCON_GPIO) += extcon_gpio.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/* | ||
* drivers/extcon/extcon_gpio.c | ||
* | ||
* Single-state GPIO extcon driver based on extcon class | ||
* | ||
* Copyright (C) 2008 Google, Inc. | ||
* Author: Mike Lockwood <lockwood@android.com> | ||
* | ||
* Modified by MyungJoo Ham <myungjoo.ham@samsung.com> to support extcon | ||
* (originally switch class is supported) | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* 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/module.h> | ||
#include <linux/kernel.h> | ||
#include <linux/init.h> | ||
#include <linux/interrupt.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/slab.h> | ||
#include <linux/extcon.h> | ||
#include <linux/workqueue.h> | ||
#include <linux/gpio.h> | ||
#include <linux/extcon.h> | ||
#include <linux/extcon/extcon_gpio.h> | ||
|
||
struct gpio_extcon_data { | ||
struct extcon_dev edev; | ||
unsigned gpio; | ||
const char *state_on; | ||
const char *state_off; | ||
int irq; | ||
struct delayed_work work; | ||
unsigned long debounce_jiffies; | ||
}; | ||
|
||
static void gpio_extcon_work(struct work_struct *work) | ||
{ | ||
int state; | ||
struct gpio_extcon_data *data = | ||
container_of(to_delayed_work(work), struct gpio_extcon_data, | ||
work); | ||
|
||
state = gpio_get_value(data->gpio); | ||
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; | ||
|
||
schedule_delayed_work(&extcon_data->work, | ||
extcon_data->debounce_jiffies); | ||
return IRQ_HANDLED; | ||
} | ||
|
||
static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf) | ||
{ | ||
struct gpio_extcon_data *extcon_data = | ||
container_of(edev, struct gpio_extcon_data, edev); | ||
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; | ||
} | ||
|
||
static int __devinit gpio_extcon_probe(struct platform_device *pdev) | ||
{ | ||
struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data; | ||
struct gpio_extcon_data *extcon_data; | ||
int ret = 0; | ||
|
||
if (!pdata) | ||
return -EBUSY; | ||
if (!pdata->irq_flags) { | ||
dev_err(&pdev->dev, "IRQ flag is not specified.\n"); | ||
return -EINVAL; | ||
} | ||
|
||
extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data), | ||
GFP_KERNEL); | ||
if (!extcon_data) | ||
return -ENOMEM; | ||
|
||
extcon_data->edev.name = pdata->name; | ||
extcon_data->gpio = pdata->gpio; | ||
extcon_data->state_on = pdata->state_on; | ||
extcon_data->state_off = pdata->state_off; | ||
if (pdata->state_on && pdata->state_off) | ||
extcon_data->edev.print_state = extcon_gpio_print_state; | ||
extcon_data->debounce_jiffies = msecs_to_jiffies(pdata->debounce); | ||
|
||
ret = extcon_dev_register(&extcon_data->edev, &pdev->dev); | ||
if (ret < 0) | ||
goto err_extcon_dev_register; | ||
|
||
ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name); | ||
if (ret < 0) | ||
goto err_request_gpio; | ||
|
||
INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work); | ||
|
||
extcon_data->irq = gpio_to_irq(extcon_data->gpio); | ||
if (extcon_data->irq < 0) { | ||
ret = extcon_data->irq; | ||
goto err_detect_irq_num_failed; | ||
} | ||
|
||
ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler, | ||
pdata->irq_flags, pdev->name, | ||
extcon_data); | ||
if (ret < 0) | ||
goto err_request_irq; | ||
|
||
/* Perform initial detection */ | ||
gpio_extcon_work(&extcon_data->work.work); | ||
|
||
return 0; | ||
|
||
err_request_irq: | ||
err_detect_irq_num_failed: | ||
gpio_free(extcon_data->gpio); | ||
err_request_gpio: | ||
extcon_dev_unregister(&extcon_data->edev); | ||
err_extcon_dev_register: | ||
devm_kfree(&pdev->dev, extcon_data); | ||
|
||
return ret; | ||
} | ||
|
||
static int __devexit gpio_extcon_remove(struct platform_device *pdev) | ||
{ | ||
struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev); | ||
|
||
cancel_delayed_work_sync(&extcon_data->work); | ||
gpio_free(extcon_data->gpio); | ||
extcon_dev_unregister(&extcon_data->edev); | ||
devm_kfree(&pdev->dev, extcon_data); | ||
|
||
return 0; | ||
} | ||
|
||
static struct platform_driver gpio_extcon = { | ||
.probe = gpio_extcon_probe, | ||
.remove = __devexit_p(gpio_extcon_remove), | ||
.driver = { | ||
.name = "extcon-gpio", | ||
.owner = THIS_MODULE, | ||
}, | ||
}; | ||
|
||
module_platform_driver(gpio_extcon); | ||
|
||
MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | ||
MODULE_DESCRIPTION("GPIO extcon driver"); | ||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
* External connector (extcon) class generic GPIO driver | ||
* | ||
* Copyright (C) 2012 Samsung Electronics | ||
* Author: MyungJoo Ham <myungjoo.ham@samsung.com> | ||
* | ||
* based on switch class driver | ||
* Copyright (C) 2008 Google, Inc. | ||
* Author: Mike Lockwood <lockwood@android.com> | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* 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. | ||
* | ||
*/ | ||
#ifndef __EXTCON_GPIO_H__ | ||
#define __EXTCON_GPIO_H__ __FILE__ | ||
|
||
#include <linux/extcon.h> | ||
|
||
/** | ||
* struct gpio_extcon_platform_data - A simple GPIO-controlled extcon device. | ||
* @name The name of this GPIO extcon device. | ||
* @gpio Corresponding GPIO. | ||
* @debounce Debounce time for GPIO IRQ in ms. | ||
* @irq_flags IRQ Flags (e.g., IRQF_TRIGGER_LOW). | ||
* @state_on print_state is overriden with state_on if attached. If Null, | ||
* default method of extcon class is used. | ||
* @state_off print_state is overriden with state_on if dettached. If Null, | ||
* default method of extcon class is used. | ||
* | ||
* Note that in order for state_on or state_off to be valid, both state_on | ||
* and state_off should be not NULL. If at least one of them is NULL, | ||
* the print_state is not overriden. | ||
*/ | ||
struct gpio_extcon_platform_data { | ||
const char *name; | ||
unsigned gpio; | ||
unsigned long debounce; | ||
unsigned long irq_flags; | ||
|
||
/* if NULL, "0" or "1" will be printed */ | ||
const char *state_on; | ||
const char *state_off; | ||
}; | ||
|
||
#endif /* __EXTCON_GPIO_H__ */ |