From b396cff519da6ab9094d5d9cd95e2849701ef9de Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 21 Mar 2016 10:36:26 +0900 Subject: [PATCH 01/15] power: axp288_charger: Replace deprecatd API of extcon This patch removes the deprecated notifier API of extcon framework and then use the new extcon API[2] with the unique id[1] to indicate the each external connector. Alter deprecated API as following: - extcon_register_interest() -> extcon_register_notifier() - extcon_unregister_interest() -> extcon_unregister_notifier() - extcon_get_cable_state() -> extcon_get_cable_state_() And, extcon alters the name of USB charger connector in patch[3] as following: - EXTCON_CHG_USB_SDP /* Standard Downstream Port */ - EXTCON_CHG_USB_DCP /* Dedicated Charging Port */ - EXTCON_CHG_USB_CDP /* Charging Downstream Port */ - EXTCON_CHG_USB_ACA /* Accessory Charger Adapter */ [1] Commit 2a9de9c0f08d61 - ("extcon: Use the unique id for external connector instead of string) [2] Commit 046050f6e623e4 - ("extcon: Update the prototype of extcon_register_notifier() with enum extcon [3] Commit 11eecf910bd81d - ("extcon: Modify the id and name of external connector") Signed-off-by: Chanwoo Choi Acked-By: Sebastian Reichel --- drivers/power/axp288_charger.c | 77 +++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/drivers/power/axp288_charger.c b/drivers/power/axp288_charger.c index e4d569f57acc..4030eeb7cf65 100644 --- a/drivers/power/axp288_charger.c +++ b/drivers/power/axp288_charger.c @@ -129,10 +129,6 @@ #define AXP288_EXTCON_DEV_NAME "axp288_extcon" -#define AXP288_EXTCON_SLOW_CHARGER "SLOW-CHARGER" -#define AXP288_EXTCON_DOWNSTREAM_CHARGER "CHARGE-DOWNSTREAM" -#define AXP288_EXTCON_FAST_CHARGER "FAST-CHARGER" - enum { VBUS_OV_IRQ = 0, CHARGE_DONE_IRQ, @@ -158,7 +154,7 @@ struct axp288_chrg_info { /* OTG/Host mode */ struct { struct work_struct work; - struct extcon_specific_cable_nb cable; + struct extcon_dev *cable; struct notifier_block id_nb; bool id_short; } otg; @@ -586,17 +582,15 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work) bool old_connected = info->cable.connected; /* Determine cable/charger type */ - if (extcon_get_cable_state(edev, AXP288_EXTCON_SLOW_CHARGER) > 0) { + if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_SDP) > 0) { dev_dbg(&info->pdev->dev, "USB SDP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB; - } else if (extcon_get_cable_state(edev, - AXP288_EXTCON_DOWNSTREAM_CHARGER) > 0) { + } else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_CDP) > 0) { dev_dbg(&info->pdev->dev, "USB CDP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB_CDP; - } else if (extcon_get_cable_state(edev, - AXP288_EXTCON_FAST_CHARGER) > 0) { + } else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_DCP) > 0) { dev_dbg(&info->pdev->dev, "USB DCP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB_DCP; @@ -692,8 +686,8 @@ static int axp288_charger_handle_otg_evt(struct notifier_block *nb, { struct axp288_chrg_info *info = container_of(nb, struct axp288_chrg_info, otg.id_nb); - struct extcon_dev *edev = param; - int usb_host = extcon_get_cable_state(edev, "USB-Host"); + struct extcon_dev *edev = info->otg.cable; + int usb_host = extcon_get_cable_state_(edev, EXTCON_USB_HOST); dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n", usb_host ? "attached" : "detached"); @@ -848,10 +842,33 @@ static int axp288_charger_probe(struct platform_device *pdev) /* Register for extcon notification */ INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker); info->cable.nb.notifier_call = axp288_charger_handle_cable_evt; - ret = extcon_register_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb); + ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, + &info->cable.nb); if (ret) { dev_err(&info->pdev->dev, - "failed to register extcon notifier %d\n", ret); + "failed to register extcon notifier for SDP %d\n", ret); + return ret; + } + + ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, + &info->cable.nb); + if (ret) { + dev_err(&info->pdev->dev, + "failed to register extcon notifier for CDP %d\n", ret); + extcon_unregister_notifier(info->cable.edev, + EXTCON_CHG_USB_SDP, &info->cable.nb); + return ret; + } + + ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, + &info->cable.nb); + if (ret) { + dev_err(&info->pdev->dev, + "failed to register extcon notifier for DCP %d\n", ret); + extcon_unregister_notifier(info->cable.edev, + EXTCON_CHG_USB_SDP, &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, + EXTCON_CHG_USB_CDP, &info->cable.nb); return ret; } @@ -871,14 +888,14 @@ static int axp288_charger_probe(struct platform_device *pdev) /* Register for OTG notification */ INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker); info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt; - ret = extcon_register_interest(&info->otg.cable, NULL, "USB-Host", + ret = extcon_register_notifier(info->otg.cable, EXTCON_USB_HOST, &info->otg.id_nb); if (ret) dev_warn(&pdev->dev, "failed to register otg notifier\n"); - if (info->otg.cable.edev) - info->otg.id_short = extcon_get_cable_state( - info->otg.cable.edev, "USB-Host"); + if (info->otg.cable) + info->otg.id_short = extcon_get_cable_state_( + info->otg.cable, EXTCON_USB_HOST); /* Register charger interrupts */ for (i = 0; i < CHRG_INTR_END; i++) { @@ -905,11 +922,17 @@ static int axp288_charger_probe(struct platform_device *pdev) return 0; intr_reg_failed: - if (info->otg.cable.edev) - extcon_unregister_interest(&info->otg.cable); + if (info->otg.cable) + extcon_unregister_notifier(info->otg.cable, EXTCON_USB_HOST, + &info->otg.id_nb); power_supply_unregister(info->psy_usb); psy_reg_failed: - extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, + &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, + &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, + &info->cable.nb); return ret; } @@ -917,10 +940,16 @@ static int axp288_charger_remove(struct platform_device *pdev) { struct axp288_chrg_info *info = dev_get_drvdata(&pdev->dev); - if (info->otg.cable.edev) - extcon_unregister_interest(&info->otg.cable); + if (info->otg.cable) + extcon_unregister_notifier(info->otg.cable, EXTCON_USB_HOST, + &info->otg.id_nb); - extcon_unregister_notifier(info->cable.edev, EXTCON_NONE, &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, + &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, + &info->cable.nb); + extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, + &info->cable.nb); power_supply_unregister(info->psy_usb); return 0; From 830ae442202e314c2bdf7cb4c7cc64d76db0e197 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 31 May 2016 17:32:30 +0900 Subject: [PATCH 02/15] extcon: Remove the deprecated extcon functions This patch removes the deprecated extcon functions using string type to identify the type of external connector. The Commit 2a9de9c0f08d61 ("extcon: Use the unique id for external connector instead of string) uses the unique id to separate the type of external connector instead of string name. - extcon_register_interest() - extcon_unregister_interest() - extcon_set_cable_state() - extcon_get_cable_state() And, extcon_register_interest() finds the first extcon device to include the requested external connector from extcon client device and then register the notifier if extcon device argument is NULL. Instead, extcon_register_notifier() supports this feature. But, this patch remains the deprecatd function definition to prevent the build break. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 201 +++++----------------------------------- include/linux/extcon.h | 84 +++++------------ 2 files changed, 49 insertions(+), 236 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 21a123cadf78..4fef9ab4b148 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -127,38 +127,6 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id return -EINVAL; } -static int find_cable_id_by_name(struct extcon_dev *edev, const char *name) -{ - int id = -EINVAL; - int i = 0; - - /* Find the id of extcon cable */ - while (extcon_name[i]) { - if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) { - id = i; - break; - } - i++; - } - - return id; -} - -static int find_cable_index_by_name(struct extcon_dev *edev, const char *name) -{ - int id; - - if (edev->max_supported == 0) - return -EINVAL; - - /* Find the the number of extcon cable */ - id = find_cable_id_by_name(edev, name); - if (id < 0) - return id; - - return find_cable_index_by_id(edev, id); -} - static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) { if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) { @@ -373,25 +341,6 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) } EXPORT_SYMBOL_GPL(extcon_get_cable_state_); -/** - * extcon_get_cable_state() - Get the status of a specific cable. - * @edev: the extcon device that has the cable. - * @cable_name: cable name. - * - * Note that this is slower than extcon_get_cable_state_. - */ -int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name) -{ - int id; - - id = find_cable_id_by_name(edev, cable_name); - if (id < 0) - return id; - - return extcon_get_cable_state_(edev, id); -} -EXPORT_SYMBOL_GPL(extcon_get_cable_state); - /** * extcon_set_cable_state_() - Set the status of a specific cable. * @edev: the extcon device that has the cable. @@ -421,28 +370,6 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, } EXPORT_SYMBOL_GPL(extcon_set_cable_state_); -/** - * extcon_set_cable_state() - Set the status of a specific cable. - * @edev: the extcon device that has the cable. - * @cable_name: cable name. - * @cable_state: the new cable status. The default semantics is - * true: attached / false: detached. - * - * Note that this is slower than extcon_set_cable_state_. - */ -int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, bool cable_state) -{ - int id; - - id = find_cable_id_by_name(edev, cable_name); - if (id < 0) - return id; - - return extcon_set_cable_state_(edev, id, cable_state); -} -EXPORT_SYMBOL_GPL(extcon_set_cable_state); - /** * extcon_get_extcon_dev() - Get the extcon device instance from the name * @extcon_name: The extcon name provided with extcon_dev_register() @@ -466,105 +393,6 @@ out: } EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); -/** - * extcon_register_interest() - Register a notifier for a state change of a - * specific cable, not an entier set of cables of a - * extcon device. - * @obj: an empty extcon_specific_cable_nb object to be returned. - * @extcon_name: the name of extcon device. - * if NULL, extcon_register_interest will register - * every cable with the target cable_name given. - * @cable_name: the target cable name. - * @nb: the notifier block to get notified. - * - * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets - * the struct for you. - * - * extcon_register_interest is a helper function for those who want to get - * notification for a single specific cable's status change. If a user wants - * to get notification for any changes of all cables of a extcon device, - * he/she should use the general extcon_register_notifier(). - * - * Note that the second parameter given to the callback of nb (val) is - * "old_state", not the current state. The current state can be retrieved - * by looking at the third pameter (edev pointer)'s state value. - */ -int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, const char *cable_name, - struct notifier_block *nb) -{ - unsigned long flags; - int ret; - - if (!obj || !cable_name || !nb) - return -EINVAL; - - if (extcon_name) { - obj->edev = extcon_get_extcon_dev(extcon_name); - if (!obj->edev) - return -ENODEV; - - obj->cable_index = find_cable_index_by_name(obj->edev, - cable_name); - if (obj->cable_index < 0) - return obj->cable_index; - - obj->user_nb = nb; - - spin_lock_irqsave(&obj->edev->lock, flags); - ret = raw_notifier_chain_register( - &obj->edev->nh[obj->cable_index], - obj->user_nb); - spin_unlock_irqrestore(&obj->edev->lock, flags); - } else { - struct class_dev_iter iter; - struct extcon_dev *extd; - struct device *dev; - - if (!extcon_class) - return -ENODEV; - class_dev_iter_init(&iter, extcon_class, NULL, NULL); - while ((dev = class_dev_iter_next(&iter))) { - extd = dev_get_drvdata(dev); - - if (find_cable_index_by_name(extd, cable_name) < 0) - continue; - - class_dev_iter_exit(&iter); - return extcon_register_interest(obj, extd->name, - cable_name, nb); - } - - ret = -ENODEV; - } - - return ret; -} -EXPORT_SYMBOL_GPL(extcon_register_interest); - -/** - * extcon_unregister_interest() - Unregister the notifier registered by - * extcon_register_interest(). - * @obj: the extcon_specific_cable_nb object returned by - * extcon_register_interest(). - */ -int extcon_unregister_interest(struct extcon_specific_cable_nb *obj) -{ - unsigned long flags; - int ret; - - if (!obj) - return -EINVAL; - - spin_lock_irqsave(&obj->edev->lock, flags); - ret = raw_notifier_chain_unregister( - &obj->edev->nh[obj->cable_index], obj->user_nb); - spin_unlock_irqrestore(&obj->edev->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(extcon_unregister_interest); - /** * extcon_register_notifier() - Register a notifiee to get notified by * any attach status changes from the extcon. @@ -582,14 +410,33 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, unsigned long flags; int ret, idx; - if (!edev || !nb) + if (!nb) return -EINVAL; - idx = find_cable_index_by_id(edev, id); + if (edev) { + idx = find_cable_index_by_id(edev, id); - spin_lock_irqsave(&edev->lock, flags); - ret = raw_notifier_chain_register(&edev->nh[idx], nb); - spin_unlock_irqrestore(&edev->lock, flags); + spin_lock_irqsave(&edev->lock, flags); + ret = raw_notifier_chain_register(&edev->nh[idx], nb); + spin_unlock_irqrestore(&edev->lock, flags); + } else { + struct extcon_dev *extd; + + mutex_lock(&extcon_dev_list_lock); + list_for_each_entry(extd, &extcon_dev_list, entry) { + idx = find_cable_index_by_id(extd, id); + if (idx >= 0) + break; + } + mutex_unlock(&extcon_dev_list_lock); + + if (idx >= 0) { + edev = extd; + return extcon_register_notifier(extd, id, nb); + } else { + ret = -ENODEV; + } + } return ret; } diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 7abf674c388c..cec5c543afc6 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -146,22 +146,6 @@ struct extcon_cable { struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ }; -/** - * struct extcon_specific_cable_nb - An internal data for - * extcon_register_interest(). - * @user_nb: user provided notifier block for events from - * a specific cable. - * @cable_index: the target cable. - * @edev: the target extcon device. - * @previous_value: the saved previous event value. - */ -struct extcon_specific_cable_nb { - struct notifier_block *user_nb; - int cable_index; - struct extcon_dev *edev; - unsigned long previous_value; -}; - #if IS_ENABLED(CONFIG_EXTCON) /* @@ -207,23 +191,6 @@ extern int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id); extern int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, bool cable_state); -extern int extcon_get_cable_state(struct extcon_dev *edev, - const char *cable_name); -extern int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, bool cable_state); - -/* - * Following APIs are for notifiees (those who want to be notified) - * to register a callback for events from a specific cable of the extcon. - * Notifiees are the connected device drivers wanting to get notified by - * a specific external port of a connection device. - */ -extern int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, - const char *cable_name, - struct notifier_block *nb); -extern int extcon_unregister_interest(struct extcon_specific_cable_nb *nb); - /* * Following APIs are to monitor every action of a notifier. * Registrar gets notified for every external port of a connection device. @@ -246,6 +213,7 @@ extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, /* Following API to get information of extcon device */ extern const char *extcon_get_edev_name(struct extcon_dev *edev); + #else /* CONFIG_EXTCON */ static inline int extcon_dev_register(struct extcon_dev *edev) { @@ -306,18 +274,6 @@ static inline int extcon_set_cable_state_(struct extcon_dev *edev, return 0; } -static inline int extcon_get_cable_state(struct extcon_dev *edev, - const char *cable_name) -{ - return 0; -} - -static inline int extcon_set_cable_state(struct extcon_dev *edev, - const char *cable_name, int state) -{ - return 0; -} - static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { return NULL; @@ -337,24 +293,34 @@ static inline int extcon_unregister_notifier(struct extcon_dev *edev, return 0; } -static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj, - const char *extcon_name, - const char *cable_name, - struct notifier_block *nb) -{ - return 0; -} - -static inline int extcon_unregister_interest(struct extcon_specific_cable_nb - *obj) -{ - return 0; -} - static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) { return ERR_PTR(-ENODEV); } #endif /* CONFIG_EXTCON */ + +/* + * Following structure and API are deprecated. EXTCON remains the function + * definition to prevent the build break. + */ +struct extcon_specific_cable_nb { + struct notifier_block *user_nb; + int cable_index; + struct extcon_dev *edev; + unsigned long previous_value; +}; + +static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj, + const char *extcon_name, const char *cable_name, + struct notifier_block *nb) +{ + return -EINVAL; +} + +static inline int extcon_unregister_interest(struct extcon_specific_cable_nb + *obj) +{ + return -EINVAL; +} #endif /* __LINUX_EXTCON_H__ */ From 12bd0f323b855ee548367f48062cf58cae5acda8 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 6 Apr 2016 20:32:37 +0300 Subject: [PATCH 03/15] extcon: usb-gpio: switch to use pm wakeirq apis Switch to use PM wakeirq APIs which automates wakeup IRQs enabling/disabling and so allows to make code simpler. Signed-off-by: Grygorii Strashko Acked-by: Tony Lindgren Acked-by: Roger Quadros Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-usb-gpio.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 2b2fecffb1ad..bc61d1165d73 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -141,7 +142,8 @@ static int usb_extcon_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, info); - device_init_wakeup(dev, 1); + device_init_wakeup(dev, true); + dev_pm_set_wake_irq(dev, info->id_irq); /* Perform initial detection */ usb_extcon_detect_cable(&info->wq_detcable.work); @@ -155,6 +157,9 @@ static int usb_extcon_remove(struct platform_device *pdev) cancel_delayed_work_sync(&info->wq_detcable); + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + return 0; } @@ -164,12 +169,6 @@ static int usb_extcon_suspend(struct device *dev) struct usb_extcon_info *info = dev_get_drvdata(dev); int ret = 0; - if (device_may_wakeup(dev)) { - ret = enable_irq_wake(info->id_irq); - if (ret) - return ret; - } - /* * We don't want to process any IRQs after this point * as GPIOs used behind I2C subsystem might not be @@ -185,12 +184,6 @@ static int usb_extcon_resume(struct device *dev) struct usb_extcon_info *info = dev_get_drvdata(dev); int ret = 0; - if (device_may_wakeup(dev)) { - ret = disable_irq_wake(info->id_irq); - if (ret) - return ret; - } - enable_irq(info->id_irq); return ret; From 04c080080855ce84dcd490a2e04805608a21085d Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 11 Apr 2016 17:04:45 +0300 Subject: [PATCH 04/15] extcon: usb-gpio: Don't miss event during suspend/resume Pin state might have changed during suspend/resume while our interrupts were disabled and if device doesn't support wakeup. Scan for change during resume for such case. Signed-off-by: Roger Quadros Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-usb-gpio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index bc61d1165d73..bad2159d3611 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -185,6 +185,9 @@ static int usb_extcon_resume(struct device *dev) int ret = 0; enable_irq(info->id_irq); + if (!device_may_wakeup(dev)) + queue_delayed_work(system_power_efficient_wq, + &info->wq_detcable, 0); return ret; } From 058b6659e98ffa8bc2781dba9ca56893be577ca3 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Mon, 25 Apr 2016 16:04:47 +0800 Subject: [PATCH 05/15] extcon: usb-gpio: add device binding for platform device This is needed to handle the GPIO connected USB ID pin found on Intel Baytrail devices. Signed-off-by: Lu Baolu Reviewed-by: Felipe Balbi Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-usb-gpio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index bad2159d3611..8969606e629b 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -202,6 +202,12 @@ static const struct of_device_id usb_extcon_dt_match[] = { }; MODULE_DEVICE_TABLE(of, usb_extcon_dt_match); +static const struct platform_device_id usb_extcon_platform_ids[] = { + { .name = "extcon-usb-gpio", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, usb_extcon_platform_ids); + static struct platform_driver usb_extcon_driver = { .probe = usb_extcon_probe, .remove = usb_extcon_remove, @@ -210,6 +216,7 @@ static struct platform_driver usb_extcon_driver = { .pm = &usb_extcon_pm_ops, .of_match_table = usb_extcon_dt_match, }, + .id_table = usb_extcon_platform_ids, }; module_platform_driver(usb_extcon_driver); From 942c7924a51edb75baf805679141e97140e07218 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Tue, 26 Apr 2016 08:35:54 +0900 Subject: [PATCH 06/15] extcon: usb-gpio: add support for ACPI gpio interface GPIO resource could be retrieved through APCI as well. Signed-off-by: Lu Baolu Reviewed-by: Felipe Balbi Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-usb-gpio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 8969606e629b..2512660dc4b9 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -27,6 +27,7 @@ #include #include #include +#include #define USB_GPIO_DEBOUNCE_MS 20 /* ms */ @@ -92,7 +93,7 @@ static int usb_extcon_probe(struct platform_device *pdev) struct usb_extcon_info *info; int ret; - if (!np) + if (!np && !ACPI_HANDLE(dev)) return -EINVAL; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); From 846d9ce535309798ae6d8c8781b0207f3cb41e6e Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 1 Jun 2016 16:13:12 +0100 Subject: [PATCH 07/15] extcon: arizona: Update binding docs to mention new defines for GPSW Update the binding documentation to mention the defines added for the possible values of wlf,gpsw. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- Documentation/devicetree/bindings/extcon/extcon-arizona.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index e27341f8a4c7..7f3d94ae81ff 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -46,7 +46,8 @@ Optional properties: The second cell represents the MICBIAS to be used. The third cell represents the value of the micd-pol-gpio pin. - - wlf,gpsw : Settings for the general purpose switch + - wlf,gpsw : Settings for the general purpose switch, set as one of the + ARIZONA_GPSW_XXX defines. Example: From a05f44c89ee1151b0da3ddd43d9e57d8f15b2f20 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 23 Jun 2016 19:34:30 +0900 Subject: [PATCH 08/15] extcon: Check for incorrect connection type in notifier register If we call extcon_register_notifier() with the wrong cable type, it blows up with an oops instead of returning an error code. Let's be nice and fail gracefully given that the consumer might not know if the cable is supported by the extcon provider. Signed-off-by: Stephen Boyd Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 4fef9ab4b148..b6408f015637 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -415,6 +415,8 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, if (edev) { idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; spin_lock_irqsave(&edev->lock, flags); ret = raw_notifier_chain_register(&edev->nh[idx], nb); @@ -458,6 +460,8 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, return -EINVAL; idx = find_cable_index_by_id(edev, id); + if (idx < 0) + return idx; spin_lock_irqsave(&edev->lock, flags); ret = raw_notifier_chain_unregister(&edev->nh[idx], nb); From 20f7b53dfc24e0caa984087691af82e442229680 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 19:17:06 +0900 Subject: [PATCH 09/15] extcon: Move struct extcon_cable from header file to core This patch moves the struct extcon_cable because that should be only handled by extcon core. There are no reason to publish the internal structure. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 20 ++++++++++++++++++++ include/linux/extcon.h | 20 -------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index b6408f015637..b5fdb5d9dbad 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -77,6 +77,26 @@ static const char *extcon_name[] = { NULL, }; +/** + * struct extcon_cable - An internal data for each cable of extcon device. + * @edev: The extcon device + * @cable_index: Index of this cable in the edev + * @attr_g: Attribute group for the cable + * @attr_name: "name" sysfs entry + * @attr_state: "state" sysfs entry + * @attrs: Array pointing to attr_name and attr_state for attr_g + */ +struct extcon_cable { + struct extcon_dev *edev; + int cable_index; + + struct attribute_group attr_g; + struct device_attribute attr_name; + struct device_attribute attr_state; + + struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ +}; + static struct class *extcon_class; #if defined(CONFIG_ANDROID) static struct class_compat *switch_class; diff --git a/include/linux/extcon.h b/include/linux/extcon.h index cec5c543afc6..1b2c8b6809cc 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -126,26 +126,6 @@ struct extcon_dev { struct device_attribute *d_attrs_muex; }; -/** - * struct extcon_cable - An internal data for each cable of extcon device. - * @edev: The extcon device - * @cable_index: Index of this cable in the edev - * @attr_g: Attribute group for the cable - * @attr_name: "name" sysfs entry - * @attr_state: "state" sysfs entry - * @attrs: Array pointing to attr_name and attr_state for attr_g - */ -struct extcon_cable { - struct extcon_dev *edev; - int cable_index; - - struct attribute_group attr_g; - struct device_attribute attr_name; - struct device_attribute attr_state; - - struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ -}; - #if IS_ENABLED(CONFIG_EXTCON) /* From b225d00f3ad2d996f914790a0f6324a4efd18768 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 19:28:04 +0900 Subject: [PATCH 10/15] extcon: Split out the resource-managed functions from extcon core This patch split out the resource-managed related functions from extcon core driver. Signed-off-by: Chanwoo Choi --- drivers/extcon/Makefile | 2 +- drivers/extcon/devres.c | 143 ++++++++++++++++++++++++++++++++++++++++ drivers/extcon/extcon.c | 117 -------------------------------- 3 files changed, 144 insertions(+), 118 deletions(-) create mode 100644 drivers/extcon/devres.c diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 2a0e4f45d5b2..423ebc8714c5 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -2,7 +2,7 @@ # Makefile for external connector class (extcon) devices # -obj-$(CONFIG_EXTCON) += extcon.o +obj-$(CONFIG_EXTCON) += extcon.o devres.o obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o diff --git a/drivers/extcon/devres.c b/drivers/extcon/devres.c new file mode 100644 index 000000000000..694ca85d5a70 --- /dev/null +++ b/drivers/extcon/devres.c @@ -0,0 +1,143 @@ +/* + * drivers/extcon/devres.c - EXTCON device's resource management + * + * Copyright (C) 2016 Samsung Electronics + * Author: Chanwoo Choi + * + * 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 + +static int devm_extcon_dev_match(struct device *dev, void *res, void *data) +{ + struct extcon_dev **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +static void devm_extcon_dev_release(struct device *dev, void *res) +{ + extcon_dev_free(*(struct extcon_dev **)res); +} + + +static void devm_extcon_dev_unreg(struct device *dev, void *res) +{ + extcon_dev_unregister(*(struct extcon_dev **)res); +} + +/** + * devm_extcon_dev_allocate - Allocate managed extcon device + * @dev: device owning the extcon device being created + * @supported_cable: Array of supported extcon ending with EXTCON_NONE. + * If supported_cable is NULL, cable name related APIs + * are disabled. + * + * This function manages automatically the memory of extcon device using device + * resource management and simplify the control of freeing the memory of extcon + * device. + * + * Returns the pointer memory of allocated extcon_dev if success + * or ERR_PTR(err) if fail + */ +struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, + const unsigned int *supported_cable) +{ + struct extcon_dev **ptr, *edev; + + ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + edev = extcon_dev_allocate(supported_cable); + if (IS_ERR(edev)) { + devres_free(ptr); + return edev; + } + + edev->dev.parent = dev; + + *ptr = edev; + devres_add(dev, ptr); + + return edev; +} +EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate); + +/** + * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister() + * @dev: device the extcon belongs to + * @edev: the extcon device to unregister + * + * Free the memory that is allocated with devm_extcon_dev_allocate() + * function. + */ +void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev) +{ + WARN_ON(devres_release(dev, devm_extcon_dev_release, + devm_extcon_dev_match, edev)); +} +EXPORT_SYMBOL_GPL(devm_extcon_dev_free); + +/** + * devm_extcon_dev_register() - Resource-managed extcon_dev_register() + * @dev: device to allocate extcon device + * @edev: the new extcon device to register + * + * Managed extcon_dev_register() function. If extcon device is attached with + * this function, that extcon device is automatically unregistered on driver + * detach. Internally this function calls extcon_dev_register() function. + * To get more information, refer that function. + * + * If extcon device is registered with this function and the device needs to be + * unregistered separately, devm_extcon_dev_unregister() should be used. + * + * Returns 0 if success or negaive error number if failure. + */ +int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev) +{ + struct extcon_dev **ptr; + int ret; + + ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = extcon_dev_register(edev); + if (ret) { + devres_free(ptr); + return ret; + } + + *ptr = edev; + devres_add(dev, ptr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_extcon_dev_register); + +/** + * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister() + * @dev: device the extcon belongs to + * @edev: the extcon device to unregister + * + * Unregister extcon device that is registered with devm_extcon_dev_register() + * function. + */ +void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev) +{ + WARN_ON(devres_release(dev, devm_extcon_dev_unreg, + devm_extcon_dev_match, edev)); +} +EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister); diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index b5fdb5d9dbad..862334e69cf1 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -564,66 +564,6 @@ void extcon_dev_free(struct extcon_dev *edev) } EXPORT_SYMBOL_GPL(extcon_dev_free); -static int devm_extcon_dev_match(struct device *dev, void *res, void *data) -{ - struct extcon_dev **r = res; - - if (WARN_ON(!r || !*r)) - return 0; - - return *r == data; -} - -static void devm_extcon_dev_release(struct device *dev, void *res) -{ - extcon_dev_free(*(struct extcon_dev **)res); -} - -/** - * devm_extcon_dev_allocate - Allocate managed extcon device - * @dev: device owning the extcon device being created - * @supported_cable: Array of supported extcon ending with EXTCON_NONE. - * If supported_cable is NULL, cable name related APIs - * are disabled. - * - * This function manages automatically the memory of extcon device using device - * resource management and simplify the control of freeing the memory of extcon - * device. - * - * Returns the pointer memory of allocated extcon_dev if success - * or ERR_PTR(err) if fail - */ -struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, - const unsigned int *supported_cable) -{ - struct extcon_dev **ptr, *edev; - - ptr = devres_alloc(devm_extcon_dev_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - edev = extcon_dev_allocate(supported_cable); - if (IS_ERR(edev)) { - devres_free(ptr); - return edev; - } - - edev->dev.parent = dev; - - *ptr = edev; - devres_add(dev, ptr); - - return edev; -} -EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate); - -void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev) -{ - WARN_ON(devres_release(dev, devm_extcon_dev_release, - devm_extcon_dev_match, edev)); -} -EXPORT_SYMBOL_GPL(devm_extcon_dev_free); - /** * extcon_dev_register() - Register a new extcon device * @edev : the new extcon device (should be allocated before calling) @@ -889,63 +829,6 @@ void extcon_dev_unregister(struct extcon_dev *edev) } EXPORT_SYMBOL_GPL(extcon_dev_unregister); -static void devm_extcon_dev_unreg(struct device *dev, void *res) -{ - extcon_dev_unregister(*(struct extcon_dev **)res); -} - -/** - * devm_extcon_dev_register() - Resource-managed extcon_dev_register() - * @dev: device to allocate extcon device - * @edev: the new extcon device to register - * - * Managed extcon_dev_register() function. If extcon device is attached with - * this function, that extcon device is automatically unregistered on driver - * detach. Internally this function calls extcon_dev_register() function. - * To get more information, refer that function. - * - * If extcon device is registered with this function and the device needs to be - * unregistered separately, devm_extcon_dev_unregister() should be used. - * - * Returns 0 if success or negaive error number if failure. - */ -int devm_extcon_dev_register(struct device *dev, struct extcon_dev *edev) -{ - struct extcon_dev **ptr; - int ret; - - ptr = devres_alloc(devm_extcon_dev_unreg, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - ret = extcon_dev_register(edev); - if (ret) { - devres_free(ptr); - return ret; - } - - *ptr = edev; - devres_add(dev, ptr); - - return 0; -} -EXPORT_SYMBOL_GPL(devm_extcon_dev_register); - -/** - * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister() - * @dev: device the extcon belongs to - * @edev: the extcon device to unregister - * - * Unregister extcon device that is registered with devm_extcon_dev_register() - * function. - */ -void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev) -{ - WARN_ON(devres_release(dev, devm_extcon_dev_unreg, - devm_extcon_dev_match, edev)); -} -EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister); - #ifdef CONFIG_OF /* * extcon_get_edev_by_phandle - Get the extcon device from devicetree From 58f386560a68dd98bd6744a28fc853eef11faebe Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 20:03:39 +0900 Subject: [PATCH 11/15] extcon: Add resource-managed functions to register extcon notifier This patch adds the resource-managed functions for register/unregister the extcon notifier with the id of each external connector. This function will make it easy to handle the extcon notifier. - int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); - void devm_extcon_unregister_notifier(struct device *dev, struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); Signed-off-by: Chanwoo Choi --- drivers/extcon/devres.c | 73 +++++++++++++++++++++++++++++++++++++++++ include/linux/extcon.h | 17 ++++++++++ 2 files changed, 90 insertions(+) diff --git a/drivers/extcon/devres.c b/drivers/extcon/devres.c index 694ca85d5a70..e686acd1c459 100644 --- a/drivers/extcon/devres.c +++ b/drivers/extcon/devres.c @@ -37,6 +37,19 @@ static void devm_extcon_dev_unreg(struct device *dev, void *res) extcon_dev_unregister(*(struct extcon_dev **)res); } +struct extcon_dev_notifier_devres { + struct extcon_dev *edev; + unsigned int id; + struct notifier_block *nb; +}; + +static void devm_extcon_dev_notifier_unreg(struct device *dev, void *res) +{ + struct extcon_dev_notifier_devres *this = res; + + extcon_unregister_notifier(this->edev, this->id, this->nb); +} + /** * devm_extcon_dev_allocate - Allocate managed extcon device * @dev: device owning the extcon device being created @@ -141,3 +154,63 @@ void devm_extcon_dev_unregister(struct device *dev, struct extcon_dev *edev) devm_extcon_dev_match, edev)); } EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister); + +/** + * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier() + * @dev: device to allocate extcon device + * @edev: the extcon device that has the external connecotr. + * @id: the unique id of each external connector in extcon enumeration. + * @nb: a notifier block to be registered. + * + * This function manages automatically the notifier of extcon device using + * device resource management and simplify the control of unregistering + * the notifier of extcon device. + * + * Note that the second parameter given to the callback of nb (val) is + * "old_state", not the current state. The current state can be retrieved + * by looking at the third pameter (edev pointer)'s state value. + * + * Returns 0 if success or negaive error number if failure. + */ +int devm_extcon_register_notifier(struct device *dev, struct extcon_dev *edev, + unsigned int id, struct notifier_block *nb) +{ + struct extcon_dev_notifier_devres *ptr; + int ret; + + ptr = devres_alloc(devm_extcon_dev_notifier_unreg, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = extcon_register_notifier(edev, id, nb); + if (ret) { + devres_free(ptr); + return ret; + } + + ptr->edev = edev; + ptr->id = id; + ptr->nb = nb; + devres_add(dev, ptr); + + return 0; +} +EXPORT_SYMBOL(devm_extcon_register_notifier); + +/** + * devm_extcon_unregister_notifier() + - Resource-managed extcon_unregister_notifier() + * @dev: device to allocate extcon device + * @edev: the extcon device that has the external connecotr. + * @id: the unique id of each external connector in extcon enumeration. + * @nb: a notifier block to be registered. + */ +void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) +{ + WARN_ON(devres_release(dev, devm_extcon_dev_notifier_unreg, + devm_extcon_dev_match, edev)); +} +EXPORT_SYMBOL(devm_extcon_unregister_notifier); diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 1b2c8b6809cc..7bf530f3f4f5 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -182,6 +182,12 @@ extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb); +extern int devm_extcon_register_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb); +extern void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb); /* * Following API get the extcon device from devicetree. @@ -273,6 +279,17 @@ static inline int extcon_unregister_notifier(struct extcon_dev *edev, return 0; } +static inline int devm_extcon_register_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) +{ + return -ENOSYS; +} + +static inline void devm_extcon_unregister_notifier(struct device *dev, + struct extcon_dev *edev, unsigned int id, + struct notifier_block *nb) { } + static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) { From bc92126012c8c84988eebbbf9c8a246949b07462 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 27 Jun 2016 21:09:04 +0900 Subject: [PATCH 12/15] extcon: Fix the wrong description about extcon_set/get_cable_state_() This patch fixes the wrong description about extcon_set/get_cable_state_() because they use the unique id of external connector instead of legacy name. Signed-off-by: Chanwoo Choi --- include/linux/extcon.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 7bf530f3f4f5..61004413dc64 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -165,7 +165,7 @@ extern int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state); /* * get/set_cable_state access each bit of the 32b encoded state value. - * They are used to access the status of each cable based on the cable_name. + * They are used to access the status of each cable based on the cable id. */ extern int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id); extern int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, From af61f96109b73fefbe0589c320d2219567f4f660 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 29 Jun 2016 16:38:30 +0200 Subject: [PATCH 13/15] extcon: link devres into core module Splitting the resource-managed functions into a separate module means that the extcon core now fails to build because the internal "extcon_dev_allocate" symbol is not exported: ERROR: extcon_dev_allocate [drivers/extcon/devres.ko] undefined! My guess is that the intention was not to have two separate modules (which could be fixed by adding an export, plus the normal MODULE_AUTHOR/MODULE_LICENSE/... fields), but have two source files in the same module. This fixes the Makefile accordingly, making the name of the module extcon_core.ko, which is created from building both extcon.c and devres.c. Fixes: b225d00f3ad2 ("extcon: Split out the resource-managed functions from extcon core") Signed-off-by: Arnd Bergmann Signed-off-by: Chanwoo Choi --- drivers/extcon/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 423ebc8714c5..972c813c375b 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -2,7 +2,8 @@ # Makefile for external connector class (extcon) devices # -obj-$(CONFIG_EXTCON) += extcon.o devres.o +obj-$(CONFIG_EXTCON) += extcon-core.o +extcon-core-objs += extcon.o devres.o obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o From 5d5c4c139dd766dff903ba35d72fb3ec90022e91 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 1 Jul 2016 18:41:55 +0900 Subject: [PATCH 14/15] extcon: add missing of_node_put after calling of_parse_phandle of_node_put needs to be called when the device node which is got from of_parse_phandle has finished using. Signed-off-by: Peter Chen Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 862334e69cf1..8682efc0f57b 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -861,10 +861,12 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) 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); + of_node_put(node); return ERR_PTR(-EPROBE_DEFER); } From 1b6cf310103799f371066453f55755088b008be0 Mon Sep 17 00:00:00 2001 From: Venkat Reddy Talla Date: Thu, 30 Jun 2016 17:54:00 +0900 Subject: [PATCH 15/15] extcon: adc-jack: add suspend/resume support adding suspend and resume funtionality for extcon-adc-jack driver to configure system wake up for extcon events, also adding support to enable/disable system wakeup through flag wakeup_source based on platform requirement. Signed-off-by: Venkat Reddy Talla Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 34 ++++++++++++++++++++++++++ include/linux/extcon/extcon-adc-jack.h | 2 ++ 2 files changed, 36 insertions(+) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 7fc0ae1912f8..44e48aa78a84 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -38,6 +38,7 @@ * @chan: iio channel being queried. */ struct adc_jack_data { + struct device *dev; struct extcon_dev *edev; const unsigned int **cable_names; @@ -49,6 +50,7 @@ struct adc_jack_data { struct delayed_work handler; struct iio_channel *chan; + bool wakeup_source; }; static void adc_jack_handler(struct work_struct *work) @@ -105,6 +107,7 @@ static int adc_jack_probe(struct platform_device *pdev) return -EINVAL; } + data->dev = &pdev->dev; data->edev = devm_extcon_dev_allocate(&pdev->dev, pdata->cable_names); if (IS_ERR(data->edev)) { dev_err(&pdev->dev, "failed to allocate extcon device\n"); @@ -128,6 +131,7 @@ static int adc_jack_probe(struct platform_device *pdev) return PTR_ERR(data->chan); data->handling_delay = msecs_to_jiffies(pdata->handling_delay_ms); + data->wakeup_source = pdata->wakeup_source; INIT_DEFERRABLE_WORK(&data->handler, adc_jack_handler); @@ -151,6 +155,9 @@ static int adc_jack_probe(struct platform_device *pdev) return err; } + if (data->wakeup_source) + device_init_wakeup(&pdev->dev, 1); + return 0; } @@ -165,11 +172,38 @@ static int adc_jack_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int adc_jack_suspend(struct device *dev) +{ + struct adc_jack_data *data = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&data->handler); + if (device_may_wakeup(data->dev)) + enable_irq_wake(data->irq); + + return 0; +} + +static int adc_jack_resume(struct device *dev) +{ + struct adc_jack_data *data = dev_get_drvdata(dev); + + if (device_may_wakeup(data->dev)) + disable_irq_wake(data->irq); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(adc_jack_pm_ops, + adc_jack_suspend, adc_jack_resume); + static struct platform_driver adc_jack_driver = { .probe = adc_jack_probe, .remove = adc_jack_remove, .driver = { .name = "adc-jack", + .pm = &adc_jack_pm_ops, }, }; diff --git a/include/linux/extcon/extcon-adc-jack.h b/include/linux/extcon/extcon-adc-jack.h index 53c60806bcfb..ac85f2061351 100644 --- a/include/linux/extcon/extcon-adc-jack.h +++ b/include/linux/extcon/extcon-adc-jack.h @@ -53,6 +53,7 @@ struct adc_jack_cond { * milli-seconds after the interrupt occurs. You may * describe such delays with @handling_delay_ms, which * is rounded-off by jiffies. + * @wakeup_source: flag to wake up the system for extcon events. */ struct adc_jack_pdata { const char *name; @@ -65,6 +66,7 @@ struct adc_jack_pdata { unsigned long irq_flags; unsigned long handling_delay_ms; /* in ms */ + bool wakeup_source; }; #endif /* _EXTCON_ADC_JACK_H */