From 370ed7a9b9176d68c7b13e6cef32efa6ac5b2d97 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 27 Feb 2018 13:22:07 +0100 Subject: extcon: add possibility to get extcon device by OF node Since extcon property is not allowed in DT, extcon subsystem requires another way to get extcon device. Lets try the simplest approach - get edev by of_node. Signed-off-by: Andrzej Hajda Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index cb38c2747684..8bff5fd18185 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1336,6 +1336,28 @@ void extcon_dev_unregister(struct extcon_dev *edev) EXPORT_SYMBOL_GPL(extcon_dev_unregister); #ifdef CONFIG_OF + +/* + * extcon_find_edev_by_node - Find the extcon device from devicetree. + * @node : OF node identifying edev + * + * Return the pointer of extcon device if success or ERR_PTR(err) if fail. + */ +struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) +{ + struct extcon_dev *edev; + + mutex_lock(&extcon_dev_list_lock); + list_for_each_entry(edev, &extcon_dev_list, entry) + if (edev->dev.parent && edev->dev.parent->of_node == node) + goto out; + edev = ERR_PTR(-EPROBE_DEFER); +out: + mutex_unlock(&extcon_dev_list_lock); + + return edev; +} + /* * extcon_get_edev_by_phandle - Get the extcon device from devicetree. * @dev : the instance to the given device @@ -1363,25 +1385,27 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) return ERR_PTR(-ENODEV); } - mutex_lock(&extcon_dev_list_lock); - list_for_each_entry(edev, &extcon_dev_list, entry) { - if (edev->dev.parent && edev->dev.parent->of_node == node) { - mutex_unlock(&extcon_dev_list_lock); - of_node_put(node); - return edev; - } - } - mutex_unlock(&extcon_dev_list_lock); + edev = extcon_find_edev_by_node(node); of_node_put(node); - return ERR_PTR(-EPROBE_DEFER); + return edev; } + #else + +struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) +{ + return ERR_PTR(-ENOSYS); +} + struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) { return ERR_PTR(-ENOSYS); } + #endif /* CONFIG_OF */ + +EXPORT_SYMBOL_GPL(extcon_find_edev_by_node); EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle); /** -- cgit From ad49aee401dd1997ec71360df6e51a91ad3cf516 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Feb 2018 14:20:46 +0100 Subject: extcon: intel-cht-wc: Set direction and drv flags for V5 boost GPIO Sometimes (firmware bug?) the V5 boost GPIO is not configured as output by the BIOS, leading to the 5V boost convertor being permanently on, Explicitly set the direction and drv flags rather then inheriting them from the firmware to fix this. Fixes: 585cb239f4de ("extcon: intel-cht-wc: Disable external 5v boost ...") Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-cht-wc.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 7c4bc8c44c3f..b7e9ea377d70 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -66,6 +66,8 @@ #define CHT_WC_VBUS_GPIO_CTLO 0x6e2d #define CHT_WC_VBUS_GPIO_CTLO_OUTPUT BIT(0) +#define CHT_WC_VBUS_GPIO_CTLO_DRV_OD BIT(4) +#define CHT_WC_VBUS_GPIO_CTLO_DIR_OUT BIT(5) enum cht_wc_usb_id { USB_ID_OTG, @@ -183,14 +185,15 @@ static void cht_wc_extcon_set_5v_boost(struct cht_wc_extcon_data *ext, { int ret, val; - val = enable ? CHT_WC_VBUS_GPIO_CTLO_OUTPUT : 0; - /* * The 5V boost converter is enabled through a gpio on the PMIC, since * there currently is no gpio driver we access the gpio reg directly. */ - ret = regmap_update_bits(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, - CHT_WC_VBUS_GPIO_CTLO_OUTPUT, val); + val = CHT_WC_VBUS_GPIO_CTLO_DRV_OD | CHT_WC_VBUS_GPIO_CTLO_DIR_OUT; + if (enable) + val |= CHT_WC_VBUS_GPIO_CTLO_OUTPUT; + + ret = regmap_write(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, val); if (ret) dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret); } -- cgit From eca0f13c836a0d29fc2a713330698f08b743e86a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 28 Feb 2018 18:22:08 +0200 Subject: extcon: int3496: Ignore incorrect IoRestriction for ID pin The commit 70216fd937fe ("extcon: int3496: Set the id pin to direction-input if necessary") introduced a workaround for incorrect IoRestriction mode in ACPI table. Now, when GPIO ACPI library does it in generic way, see the commit 1b2ca32ab0b8 ("gpiolib: acpi: Introduce NO_RESTRICTION quirk") for the details, just set an appropriate quirk flag instead. Reviewed-by: Hans de Goede Tested-by: Hans de Goede Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-intel-int3496.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c index 191e99f06a9a..acaccb128fc4 100644 --- a/drivers/extcon/extcon-intel-int3496.c +++ b/drivers/extcon/extcon-intel-int3496.c @@ -50,7 +50,11 @@ static const struct acpi_gpio_params vbus_gpios = { INT3496_GPIO_VBUS_EN, 0, fal static const struct acpi_gpio_params mux_gpios = { INT3496_GPIO_USB_MUX, 0, false }; static const struct acpi_gpio_mapping acpi_int3496_default_gpios[] = { - { "id-gpios", &id_gpios, 1 }, + /* + * Some platforms have a bug in ACPI GPIO description making IRQ + * GPIO to be output only. Ask the GPIO core to ignore this limit. + */ + { "id-gpios", &id_gpios, 1, ACPI_GPIO_QUIRK_NO_IO_RESTRICTION }, { "vbus-gpios", &vbus_gpios, 1 }, { "mux-gpios", &mux_gpios, 1 }, { }, @@ -112,9 +116,6 @@ static int int3496_probe(struct platform_device *pdev) ret = PTR_ERR(data->gpio_usb_id); dev_err(dev, "can't request USB ID GPIO: %d\n", ret); return ret; - } else if (gpiod_get_direction(data->gpio_usb_id) != GPIOF_DIR_IN) { - dev_warn(dev, FW_BUG "USB ID GPIO not in input mode, fixing\n"); - gpiod_direction_input(data->gpio_usb_id); } data->usb_id_irq = gpiod_to_irq(data->gpio_usb_id); -- cgit From 66afdedf269cf485efb5affb30c34e1f37705445 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Feb 2018 09:53:12 +0100 Subject: extcon: gpio: Localize platform data Nothing in the entire kernel #includes so move the platform data declaration inside of the driver. Signed-off-by: Linus Walleij Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-gpio.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index ab770adcca7e..5f88f36cc54e 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -29,6 +28,27 @@ #include #include +/** + * struct gpio_extcon_pdata - A simple GPIO-controlled extcon device. + * @extcon_id: The unique id of specific external connector. + * @gpio: Corresponding GPIO. + * @gpio_active_low: Boolean describing whether gpio active state is 1 or 0 + * If true, low state of gpio means active. + * If false, high state of gpio means active. + * @debounce: Debounce time for GPIO IRQ in ms. + * @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW). + * @check_on_resume: Boolean describing whether to check the state of gpio + * while resuming from sleep. + */ +struct gpio_extcon_pdata { + unsigned int extcon_id; + unsigned gpio; + bool gpio_active_low; + unsigned long debounce; + unsigned long irq_flags; + bool check_on_resume; +}; + struct gpio_extcon_data { struct extcon_dev *edev; int irq; -- cgit From a62300d99f15c4be7edafbbc2ade0246ec853778 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Feb 2018 09:53:13 +0100 Subject: extcon: gpio: Move platform data into state container This moves the platform data settings from the platform data struct and into the state container, saving some unnecessary references and simplifying things a bit. Signed-off-by: Linus Walleij [cw00.choi: Add FIXME comment of extcon_id] Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-gpio.c | 63 +++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 30 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index 5f88f36cc54e..b54499771e2b 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -29,7 +29,13 @@ #include /** - * struct gpio_extcon_pdata - A simple GPIO-controlled extcon device. + * struct gpio_extcon_data - A simple GPIO-controlled extcon device state container. + * @edev: Extcon device. + * @irq: Interrupt line for the external connector. + * @work: Work fired by the interrupt. + * @debounce_jiffies: Number of jiffies to wait for the GPIO to stabilize, from the debounce + * value. + * @id_gpiod: GPIO descriptor for this external connector. * @extcon_id: The unique id of specific external connector. * @gpio: Corresponding GPIO. * @gpio_active_low: Boolean describing whether gpio active state is 1 or 0 @@ -40,23 +46,18 @@ * @check_on_resume: Boolean describing whether to check the state of gpio * while resuming from sleep. */ -struct gpio_extcon_pdata { - unsigned int extcon_id; - unsigned gpio; - bool gpio_active_low; - unsigned long debounce; - unsigned long irq_flags; - bool check_on_resume; -}; - struct gpio_extcon_data { struct extcon_dev *edev; int irq; struct delayed_work work; unsigned long debounce_jiffies; - struct gpio_desc *id_gpiod; - struct gpio_extcon_pdata *pdata; + unsigned int extcon_id; + unsigned gpio; + bool gpio_active_low; + unsigned long debounce; + unsigned long irq_flags; + bool check_on_resume; }; static void gpio_extcon_work(struct work_struct *work) @@ -67,10 +68,10 @@ static void gpio_extcon_work(struct work_struct *work) work); state = gpiod_get_value_cansleep(data->id_gpiod); - if (data->pdata->gpio_active_low) + if (data->gpio_active_low) state = !state; - extcon_set_state_sync(data->edev, data->pdata->extcon_id, state); + extcon_set_state_sync(data->edev, data->extcon_id, state); } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) @@ -84,24 +85,23 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id) static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data) { - struct gpio_extcon_pdata *pdata = data->pdata; int ret; - ret = devm_gpio_request_one(dev, pdata->gpio, GPIOF_DIR_IN, + ret = devm_gpio_request_one(dev, data->gpio, GPIOF_DIR_IN, dev_name(dev)); if (ret < 0) return ret; - data->id_gpiod = gpio_to_desc(pdata->gpio); + data->id_gpiod = gpio_to_desc(data->gpio); if (!data->id_gpiod) return -EINVAL; - if (pdata->debounce) { + if (data->debounce) { ret = gpiod_set_debounce(data->id_gpiod, - pdata->debounce * 1000); + data->debounce * 1000); if (ret < 0) data->debounce_jiffies = - msecs_to_jiffies(pdata->debounce); + msecs_to_jiffies(data->debounce); } data->irq = gpiod_to_irq(data->id_gpiod); @@ -113,20 +113,23 @@ static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data) static int gpio_extcon_probe(struct platform_device *pdev) { - 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 || pdata->extcon_id > EXTCON_NONE) - return -EINVAL; - data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data), GFP_KERNEL); if (!data) return -ENOMEM; - data->pdata = pdata; + + /* + * FIXME: extcon_id represents the unique identifier of external + * connectors such as EXTCON_USB, EXTCON_DISP_HDMI and so on. extcon_id + * is necessary to register the extcon device. But, it's not yet + * developed to get the extcon id from device-tree or others. + * On later, it have to be solved. + */ + if (!data->irq_flags || data->extcon_id > EXTCON_NONE) + return -EINVAL; /* Initialize the gpio */ ret = gpio_extcon_init(&pdev->dev, data); @@ -134,7 +137,7 @@ static int gpio_extcon_probe(struct platform_device *pdev) return ret; /* Allocate the memory of extcon devie and register extcon device */ - data->edev = devm_extcon_dev_allocate(&pdev->dev, &pdata->extcon_id); + data->edev = devm_extcon_dev_allocate(&pdev->dev, &data->extcon_id); if (IS_ERR(data->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); return -ENOMEM; @@ -151,7 +154,7 @@ static int gpio_extcon_probe(struct platform_device *pdev) * is attached or detached. */ ret = devm_request_any_context_irq(&pdev->dev, data->irq, - gpio_irq_handler, pdata->irq_flags, + gpio_irq_handler, data->irq_flags, pdev->name, data); if (ret < 0) return ret; @@ -178,7 +181,7 @@ static int gpio_extcon_resume(struct device *dev) struct gpio_extcon_data *data; data = dev_get_drvdata(dev); - if (data->pdata->check_on_resume) + if (data->check_on_resume) queue_delayed_work(system_power_efficient_wq, &data->work, data->debounce_jiffies); -- cgit From d368e7de5e8bac32a9121608a7d4c96a229d5af2 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 12 Feb 2018 09:53:14 +0100 Subject: extcon: gpio: Convert to fully use GPIO descriptor Since we are not getting the GPIO from any platform data and global GPIO numberspace, we simply get the named "extcon" GPIO directly from the device. Cut away "active low" since GPIO descriptors already know if the line is active high or low. Simplify a bit with a struct device *dev helper variable in probe() and cut the complex init() function. Signed-off-by: Linus Walleij Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-gpio.c | 66 ++++++++++---------------------------------- 1 file changed, 15 insertions(+), 51 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index b54499771e2b..13ba3a6e81d5 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -35,12 +34,8 @@ * @work: Work fired by the interrupt. * @debounce_jiffies: Number of jiffies to wait for the GPIO to stabilize, from the debounce * value. - * @id_gpiod: GPIO descriptor for this external connector. + * @gpiod: GPIO descriptor for this external connector. * @extcon_id: The unique id of specific external connector. - * @gpio: Corresponding GPIO. - * @gpio_active_low: Boolean describing whether gpio active state is 1 or 0 - * If true, low state of gpio means active. - * If false, high state of gpio means active. * @debounce: Debounce time for GPIO IRQ in ms. * @irq_flags: IRQ Flags (e.g., IRQF_TRIGGER_LOW). * @check_on_resume: Boolean describing whether to check the state of gpio @@ -51,10 +46,8 @@ struct gpio_extcon_data { int irq; struct delayed_work work; unsigned long debounce_jiffies; - struct gpio_desc *id_gpiod; + struct gpio_desc *gpiod; unsigned int extcon_id; - unsigned gpio; - bool gpio_active_low; unsigned long debounce; unsigned long irq_flags; bool check_on_resume; @@ -67,10 +60,7 @@ static void gpio_extcon_work(struct work_struct *work) container_of(to_delayed_work(work), struct gpio_extcon_data, work); - state = gpiod_get_value_cansleep(data->id_gpiod); - if (data->gpio_active_low) - state = !state; - + state = gpiod_get_value_cansleep(data->gpiod); extcon_set_state_sync(data->edev, data->extcon_id, state); } @@ -83,41 +73,13 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int gpio_extcon_init(struct device *dev, struct gpio_extcon_data *data) -{ - int ret; - - ret = devm_gpio_request_one(dev, data->gpio, GPIOF_DIR_IN, - dev_name(dev)); - if (ret < 0) - return ret; - - data->id_gpiod = gpio_to_desc(data->gpio); - if (!data->id_gpiod) - return -EINVAL; - - if (data->debounce) { - ret = gpiod_set_debounce(data->id_gpiod, - data->debounce * 1000); - if (ret < 0) - data->debounce_jiffies = - msecs_to_jiffies(data->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_data *data; + struct device *dev = &pdev->dev; int ret; - data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data), - GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct gpio_extcon_data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -131,19 +93,21 @@ static int gpio_extcon_probe(struct platform_device *pdev) if (!data->irq_flags || data->extcon_id > EXTCON_NONE) return -EINVAL; - /* Initialize the gpio */ - ret = gpio_extcon_init(&pdev->dev, data); - if (ret < 0) - return ret; + data->gpiod = devm_gpiod_get(dev, "extcon", GPIOD_IN); + if (IS_ERR(data->gpiod)) + return PTR_ERR(data->gpiod); + data->irq = gpiod_to_irq(data->gpiod); + if (data->irq <= 0) + return data->irq; /* Allocate the memory of extcon devie and register extcon device */ - data->edev = devm_extcon_dev_allocate(&pdev->dev, &data->extcon_id); + data->edev = devm_extcon_dev_allocate(dev, &data->extcon_id); if (IS_ERR(data->edev)) { - dev_err(&pdev->dev, "failed to allocate extcon device\n"); + dev_err(dev, "failed to allocate extcon device\n"); return -ENOMEM; } - ret = devm_extcon_dev_register(&pdev->dev, data->edev); + ret = devm_extcon_dev_register(dev, data->edev); if (ret < 0) return ret; @@ -153,7 +117,7 @@ static int gpio_extcon_probe(struct platform_device *pdev) * Request the interrupt of gpio to detect whether external connector * is attached or detached. */ - ret = devm_request_any_context_irq(&pdev->dev, data->irq, + ret = devm_request_any_context_irq(dev, data->irq, gpio_irq_handler, data->irq_flags, pdev->name, data); if (ret < 0) -- cgit