From ba4b27151ade5eab3d32a47bf323bfa8c5cd0726 Mon Sep 17 00:00:00 2001 From: Venkat Reddy Talla Date: Tue, 5 Jul 2016 19:26:21 +0530 Subject: [PATCH 001/343] extcon: adc-jack: update cable state during boot Update cable state during boot to avoid any missing external cable events occurred before driver initialisation. Signed-off-by: Venkat Reddy Talla Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 44e48aa78a84..48dec94b487b 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -158,6 +158,7 @@ static int adc_jack_probe(struct platform_device *pdev) if (data->wakeup_source) device_init_wakeup(&pdev->dev, 1); + adc_jack_handler(&data->handler.work); return 0; } From e8752b7a7294a7c19545123eea079d873f8cc243 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 5 Jul 2016 11:57:05 -0700 Subject: [PATCH 002/343] extcon: Move extcon_get_edev_by_phandle() errors to dbg level Sometimes drivers may call this API and expect it to fail because the extcon they're looking for is optional. Let's move these prints to debug level so it doesn't look like there's a problem when there isn't one. Signed-off-by: Stephen Boyd Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 8682efc0f57b..319659c6af28 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -846,13 +846,13 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) return ERR_PTR(-EINVAL); if (!dev->of_node) { - dev_err(dev, "device does not have a device node entry\n"); + dev_dbg(dev, "device does not have a device node entry\n"); return ERR_PTR(-EINVAL); } node = of_parse_phandle(dev->of_node, "extcon", index); if (!node) { - dev_err(dev, "failed to get phandle in %s node\n", + dev_dbg(dev, "failed to get phandle in %s node\n", dev->of_node->full_name); return ERR_PTR(-ENODEV); } From c19dc203e61886b4e61201832adc4da2816c5def Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 19 Jul 2016 13:23:56 +0100 Subject: [PATCH 003/343] extcon: arizona: Remove unneeded semi-colon There is no need for a semi-colon at the end of a switch statement so remove it. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 1d8e0a57bd51..be4d93d4c546 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -183,7 +183,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, if (clamp) val = ARIZONA_RMV_SHRT_HP1L; break; - }; + } snd_soc_dapm_mutex_lock(arizona->dapm); From 5475e6317525b37241766c2e87731fd152e1150b Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 1 Jul 2016 02:36:49 +0900 Subject: [PATCH 004/343] extcon: arizona: Remove the usage of extcon_update_state() This patch remvoes the usage of extcon_update_state() because the extcon_update_state() use directly the bit masking calculation to change the state of external connector without the unique id of external connector. It makes the code diffcult to read it. So, this patch uses the extcon_set_cable_state_() instead. Signed-off-by: Chanwoo Choi Acked-by: Charles Keepax --- drivers/extcon/extcon-arizona.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index be4d93d4c546..493bd9fe5f67 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1149,10 +1149,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data) info->micd_ranges[i].key, 0); input_sync(info->input); - ret = extcon_update_state(info->edev, 0xffffffff, 0); - if (ret != 0) - dev_err(arizona->dev, "Removal report failed: %d\n", - ret); + for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) { + ret = extcon_set_cable_state_(info->edev, + arizona_cable[i], false); + if (ret != 0) + dev_err(arizona->dev, + "Removal report failed: %d\n", ret); + } regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE, From a7da72eeec78b8ce08a99d132b3e269942b977eb Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 18 Jul 2016 16:16:29 +0900 Subject: [PATCH 005/343] extcon: adc-jack: Remove the usage of extcon_set_state() This patch removes the usage of extcon_set_state() because it uses the bit masking to change the state of external connectors. The extcon framework should handle the state by extcon_set/get_cable_state_() with extcon id. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 26 ++++++++++++++------------ include/linux/extcon/extcon-adc-jack.h | 4 ++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 48dec94b487b..e62e6cd7e00a 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -3,6 +3,9 @@ * * Analog Jack extcon driver with ADC-based detection capability. * + * Copyright (C) 2016 Samsung Electronics + * Chanwoo Choi + * * Copyright (C) 2012 Samsung Electronics * MyungJoo Ham * @@ -58,7 +61,7 @@ static void adc_jack_handler(struct work_struct *work) struct adc_jack_data *data = container_of(to_delayed_work(work), struct adc_jack_data, handler); - u32 state = 0; + struct adc_jack_cond *def; int ret, adc_val; int i; @@ -70,17 +73,18 @@ static void adc_jack_handler(struct work_struct *work) /* Get state from adc value with adc_conditions */ for (i = 0; i < data->num_conditions; i++) { - struct adc_jack_cond *def = &data->adc_conditions[i]; - if (!def->state) - break; + def = &data->adc_conditions[i]; if (def->min_adc <= adc_val && def->max_adc >= adc_val) { - state = def->state; - break; + extcon_set_cable_state_(data->edev, def->id, true); + return; } } - /* if no def has met, it means state = 0 (no cables attached) */ - extcon_set_state(data->edev, state); + /* Set the detached state if adc value is not included in the range */ + for (i = 0; i < data->num_conditions; i++) { + def = &data->adc_conditions[i]; + extcon_set_cable_state_(data->edev, def->id, false); + } } static irqreturn_t adc_jack_irq_thread(int irq, void *_data) @@ -114,16 +118,14 @@ static int adc_jack_probe(struct platform_device *pdev) return -ENOMEM; } - if (!pdata->adc_conditions || - !pdata->adc_conditions[0].state) { + if (!pdata->adc_conditions) { dev_err(&pdev->dev, "error: adc_conditions not defined.\n"); return -EINVAL; } data->adc_conditions = pdata->adc_conditions; /* Check the length of array and set num_conditions */ - for (i = 0; data->adc_conditions[i].state; i++) - ; + for (i = 0; data->adc_conditions[i].id != EXTCON_NONE; i++); data->num_conditions = i; data->chan = iio_channel_get(&pdev->dev, pdata->consumer_channel); diff --git a/include/linux/extcon/extcon-adc-jack.h b/include/linux/extcon/extcon-adc-jack.h index ac85f2061351..a0e03b13b449 100644 --- a/include/linux/extcon/extcon-adc-jack.h +++ b/include/linux/extcon/extcon-adc-jack.h @@ -20,8 +20,8 @@ /** * struct adc_jack_cond - condition to use an extcon state - * @state: the corresponding extcon state (if 0, this struct * denotes the last adc_jack_cond element among the array) + * @id: the unique id of each external connector * @min_adc: min adc value for this condition * @max_adc: max adc value for this condition * @@ -33,7 +33,7 @@ * because when no adc_jack_cond is met, state = 0 is automatically chosen. */ struct adc_jack_cond { - u32 state; /* extcon state value. 0 if invalid */ + unsigned int id; u32 min_adc; u32 max_adc; }; From 7575591c2db8cbf4ba543cb9bcb6a4cdd5a7aa97 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 21 Jul 2016 20:00:29 +0900 Subject: [PATCH 006/343] extcon: gpio: Remove the usage of extcon_set_state() This patch removes the usage of extcon_set_state() because it uses the bit masking to change the state of external connectors. The extcon framework should handle the state by extcon_set_cable_state_() with extcon id. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index d023789f0fda..b1b0264eb12d 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -49,7 +49,7 @@ static void gpio_extcon_work(struct work_struct *work) state = gpiod_get_value_cansleep(data->id_gpiod); if (data->pdata->gpio_active_low) state = !state; - extcon_set_state(data->edev, state); + extcon_set_cable_state_(data->edev, data->pdata->extcon_id, state); } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) From 5d5321e90a69881a6e92604b73f7c8e8ca473373 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 18 Jul 2016 15:39:28 +0900 Subject: [PATCH 007/343] extcon: Remove the state_store() to prevent the wrong access This patch removes the state_store() which change the state of external connectors with bit masking on user-space. It is wrong access to modify the change the state of external connectors. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 319659c6af28..ad5e4546f82c 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -174,26 +174,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, return count; } - -static ssize_t state_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - u32 state; - ssize_t ret = 0; - struct extcon_dev *edev = dev_get_drvdata(dev); - - ret = sscanf(buf, "0x%x", &state); - if (ret == 0) - ret = -EINVAL; - else - ret = extcon_set_state(edev, state); - - if (ret < 0) - return ret; - - return count; -} -static DEVICE_ATTR_RW(state); +static DEVICE_ATTR_RO(state); static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) From 912465bcf869660900cf77c4761869048f3ff063 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 1 Jul 2016 02:41:18 +0900 Subject: [PATCH 008/343] extcon: Block the bit masking operation for cable state except for extcon core This patch restrict the usage of extcon_update_state() in the extcon core because the extcon_update_state() use the bit masking to change the state of external connector. When this function is used in device drivers, it may occur the probelm with the handling mistake of bit masking. Also, this patch removes the extcon_get/set_state() functions because these functions use the bit masking which is reluctant way. Instead, extcon provides the extcon_set/get_cable_state_() functions. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 20 +------------------- include/linux/extcon.h | 30 ------------------------------ 2 files changed, 1 insertion(+), 49 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index ad5e4546f82c..5b61000cde26 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -224,7 +224,7 @@ static ssize_t cable_state_show(struct device *dev, * Note that the notifier provides which bits are changed in the state * variable with the val parameter (second) to the callback. */ -int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) +static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) { char name_buf[120]; char state_buf[120]; @@ -300,24 +300,6 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) return 0; } -EXPORT_SYMBOL_GPL(extcon_update_state); - -/** - * extcon_set_state() - Set the cable attach states of the extcon device. - * @edev: the extcon device - * @state: new cable attach status for @edev - * - * Note that notifier provides which bits are changed in the state - * variable with the val parameter (second) to the callback. - */ -int extcon_set_state(struct extcon_dev *edev, u32 state) -{ - if (!edev) - return -EINVAL; - - return extcon_update_state(edev, 0xffffffff, state); -} -EXPORT_SYMBOL_GPL(extcon_set_state); /** * extcon_get_cable_state_() - Get the status of a specific cable. diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 61004413dc64..667b1d35af12 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -149,20 +149,6 @@ extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, const unsigned int *cable); extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); -/* - * get/set/update_state access the 32b encoded state value, which represents - * states of all possible cables of the multistate port. For example, if one - * calls extcon_set_state(edev, 0x7), it may mean that all the three cables - * are attached to the port. - */ -static inline u32 extcon_get_state(struct extcon_dev *edev) -{ - return edev->state; -} - -extern int extcon_set_state(struct extcon_dev *edev, u32 state); -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 id. @@ -232,22 +218,6 @@ static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, static inline void devm_extcon_dev_free(struct extcon_dev *edev) { } -static inline u32 extcon_get_state(struct extcon_dev *edev) -{ - return 0; -} - -static inline int extcon_set_state(struct extcon_dev *edev, u32 state) -{ - return 0; -} - -static inline int extcon_update_state(struct extcon_dev *edev, u32 mask, - u32 state) -{ - return 0; -} - static inline int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id) { From 2c8116a1110a93f298b10339d773fb055a0c04d7 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Mon, 1 Aug 2016 14:51:30 +0530 Subject: [PATCH 009/343] extcon: Fix compile time warning This patch fixes below compilation warning:- drivers/extcon/extcon.c: In function extcon_register_notifier: drivers/extcon/extcon.c:455:6: warning: idx may be used uninitialized in this function [-Wmaybe-uninitialized] if (idx >= 0) { Signed-off-by: Vaneet Narang Signed-off-by: Maninder Singh [cw00.choi : Modify the patch title using the a captical letter for first char] Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 5b61000cde26..9a266e5c7e10 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -391,7 +391,7 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb) { unsigned long flags; - int ret, idx; + int ret, idx = -EINVAL; if (!nb) return -EINVAL; From 55e4e2f129c6664c14166a30f4e0e933ebb61d9b Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 11 Jul 2016 16:34:52 +0900 Subject: [PATCH 010/343] extcon: Add the extcon_type to gather each connector into five category This patch adds the new extcon type to group the each connecotr into following five category. This type would be used to handle the connectors as a group unit instead of a connector unit. - EXTCON_TYPE_USB : USB connector - EXTCON_TYPE_CHG : Charger connector - EXTCON_TYPE_JACK : Jack connector - EXTCON_TYPE_DISP : Display connector - EXTCON_TYPE_MISC : Miscellaneous connector Also, each external connector is possible to belong to one more extcon type. In caes of EXTCON_CHG_USB_SDP, it have the EXTCON_TYPE_CHG and EXTCON_TYPE_USB. Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Signed-off-by: MyungJoo Ham Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 157 +++++++++++++++++++++++++++++++++------- include/linux/extcon.h | 9 +++ 2 files changed, 138 insertions(+), 28 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 9a266e5c7e10..f209a6959fed 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -38,43 +38,144 @@ #define SUPPORTED_CABLE_MAX 32 #define CABLE_NAME_MAX 30 -static const char *extcon_name[] = { - [EXTCON_NONE] = "NONE", +struct __extcon_info { + unsigned int type; + unsigned int id; + const char *name; + +} extcon_info[] = { + [EXTCON_NONE] = { + .type = EXTCON_TYPE_MISC, + .id = EXTCON_NONE, + .name = "NONE", + }, /* USB external connector */ - [EXTCON_USB] = "USB", - [EXTCON_USB_HOST] = "USB-HOST", + [EXTCON_USB] = { + .type = EXTCON_TYPE_USB, + .id = EXTCON_USB, + .name = "USB", + }, + [EXTCON_USB_HOST] = { + .type = EXTCON_TYPE_USB, + .id = EXTCON_USB_HOST, + .name = "USB_HOST", + }, /* Charging external connector */ - [EXTCON_CHG_USB_SDP] = "SDP", - [EXTCON_CHG_USB_DCP] = "DCP", - [EXTCON_CHG_USB_CDP] = "CDP", - [EXTCON_CHG_USB_ACA] = "ACA", - [EXTCON_CHG_USB_FAST] = "FAST-CHARGER", - [EXTCON_CHG_USB_SLOW] = "SLOW-CHARGER", + [EXTCON_CHG_USB_SDP] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_SDP, + .name = "SDP", + }, + [EXTCON_CHG_USB_DCP] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_DCP, + .name = "DCP", + }, + [EXTCON_CHG_USB_CDP] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_CDP, + .name = "CDP", + }, + [EXTCON_CHG_USB_ACA] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_ACA, + .name = "ACA", + }, + [EXTCON_CHG_USB_FAST] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_FAST, + .name = "FAST-CHARGER", + }, + [EXTCON_CHG_USB_SLOW] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_SLOW, + .name = "SLOW-CHARGER", + }, /* Jack external connector */ - [EXTCON_JACK_MICROPHONE] = "MICROPHONE", - [EXTCON_JACK_HEADPHONE] = "HEADPHONE", - [EXTCON_JACK_LINE_IN] = "LINE-IN", - [EXTCON_JACK_LINE_OUT] = "LINE-OUT", - [EXTCON_JACK_VIDEO_IN] = "VIDEO-IN", - [EXTCON_JACK_VIDEO_OUT] = "VIDEO-OUT", - [EXTCON_JACK_SPDIF_IN] = "SPDIF-IN", - [EXTCON_JACK_SPDIF_OUT] = "SPDIF-OUT", + [EXTCON_JACK_MICROPHONE] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_MICROPHONE, + .name = "MICROPHONE", + }, + [EXTCON_JACK_HEADPHONE] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_HEADPHONE, + .name = "HEADPHONE", + }, + [EXTCON_JACK_LINE_IN] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_LINE_IN, + .name = "LINE-IN", + }, + [EXTCON_JACK_LINE_OUT] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_LINE_OUT, + .name = "LINE-OUT", + }, + [EXTCON_JACK_VIDEO_IN] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_VIDEO_IN, + .name = "VIDEO-IN", + }, + [EXTCON_JACK_VIDEO_OUT] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_VIDEO_OUT, + .name = "VIDEO-OUT", + }, + [EXTCON_JACK_SPDIF_IN] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_SPDIF_IN, + .name = "SPDIF-IN", + }, + [EXTCON_JACK_SPDIF_OUT] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_SPDIF_OUT, + .name = "SPDIF-OUT", + }, /* Display external connector */ - [EXTCON_DISP_HDMI] = "HDMI", - [EXTCON_DISP_MHL] = "MHL", - [EXTCON_DISP_DVI] = "DVI", - [EXTCON_DISP_VGA] = "VGA", + [EXTCON_DISP_HDMI] = { + .type = EXTCON_TYPE_DISP, + .id = EXTCON_DISP_HDMI, + .name = "HDMI", + }, + [EXTCON_DISP_MHL] = { + .type = EXTCON_TYPE_DISP, + .id = EXTCON_DISP_MHL, + .name = "MHL", + }, + [EXTCON_DISP_DVI] = { + .type = EXTCON_TYPE_DISP, + .id = EXTCON_DISP_DVI, + .name = "DVI", + }, + [EXTCON_DISP_VGA] = { + .type = EXTCON_TYPE_DISP, + .id = EXTCON_DISP_VGA, + .name = "VGA", + }, /* Miscellaneous external connector */ - [EXTCON_DOCK] = "DOCK", - [EXTCON_JIG] = "JIG", - [EXTCON_MECHANICAL] = "MECHANICAL", + [EXTCON_DOCK] = { + .type = EXTCON_TYPE_MISC, + .id = EXTCON_DOCK, + .name = "DOCK", + }, + [EXTCON_JIG] = { + .type = EXTCON_TYPE_MISC, + .id = EXTCON_JIG, + .name = "JIG", + }, + [EXTCON_MECHANICAL] = { + .type = EXTCON_TYPE_MISC, + .id = EXTCON_MECHANICAL, + .name = "MECHANICAL", + }, - NULL, + { /* sentinel */ } }; /** @@ -168,7 +269,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, for (i = 0; i < edev->max_supported; i++) { count += sprintf(buf + count, "%s=%d\n", - extcon_name[edev->supported_cable[i]], + extcon_info[edev->supported_cable[i]].name, !!(edev->state & (1 << i))); } @@ -193,7 +294,7 @@ static ssize_t cable_name_show(struct device *dev, int i = cable->cable_index; return sprintf(buf, "%s\n", - extcon_name[cable->edev->supported_cable[i]]); + extcon_info[cable->edev->supported_cable[i]].name); } static ssize_t cable_state_show(struct device *dev, diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 667b1d35af12..46d802892c82 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -28,6 +28,15 @@ #include +/* + * Define the type of supported external connectors + */ +#define EXTCON_TYPE_USB BIT(0) /* USB connector */ +#define EXTCON_TYPE_CHG BIT(1) /* Charger connector */ +#define EXTCON_TYPE_JACK BIT(2) /* Jack connector */ +#define EXTCON_TYPE_DISP BIT(3) /* Display connector */ +#define EXTCON_TYPE_MISC BIT(4) /* Miscellaneous connector */ + /* * Define the unique id of supported external connectors */ From 792e7e9e5d4358bc6157152b2c07b94eb9e261b0 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 11 Jul 2016 19:30:43 +0900 Subject: [PATCH 011/343] extcon: Add the support for extcon property according to extcon type This patch support the extcon property for the external connector because each external connector might have the property according to the H/W design and the specific characteristics. - EXTCON_PROP_USB_[property name] - EXTCON_PROP_CHG_[property name] - EXTCON_PROP_JACK_[property name] - EXTCON_PROP_DISP_[property name] Add the new extcon APIs to get/set the property value as following: - int extcon_get_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value *prop_val) - int extcon_set_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val) Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 201 +++++++++++++++++++++++++++++++++++++++- include/linux/extcon.h | 81 ++++++++++++++++ 2 files changed, 281 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index f209a6959fed..37fa4b51c5a1 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -196,6 +196,11 @@ struct extcon_cable { struct device_attribute attr_state; struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ + + union extcon_property_value usb_propval[EXTCON_PROP_USB_CNT]; + union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT]; + union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; + union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; }; static struct class *extcon_class; @@ -248,6 +253,27 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id return -EINVAL; } +static int get_extcon_type(unsigned int prop) +{ + switch (prop) { + case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: + return EXTCON_TYPE_USB; + case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: + return EXTCON_TYPE_CHG; + case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: + return EXTCON_TYPE_JACK; + case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: + return EXTCON_TYPE_DISP; + default: + return -EINVAL; + } +} + +static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index) +{ + return !!(edev->state & BIT(index)); +} + static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) { if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) { @@ -258,6 +284,34 @@ static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) return false; } +static bool is_extcon_property_supported(unsigned int id, unsigned int prop) +{ + int type; + + /* Check whether the property is supported or not. */ + type = get_extcon_type(prop); + if (type < 0) + return false; + + /* Check whether a specific extcon id supports the property or not. */ + return !!(extcon_info[id].type & type); +} + +static void init_property(struct extcon_dev *edev, unsigned int id, int index) +{ + unsigned int type = extcon_info[id].type; + struct extcon_cable *cable = &edev->cables[index]; + + if (EXTCON_TYPE_USB & type) + memset(cable->usb_propval, 0, sizeof(cable->usb_propval)); + if (EXTCON_TYPE_CHG & type) + memset(cable->chg_propval, 0, sizeof(cable->chg_propval)); + if (EXTCON_TYPE_JACK & type) + memset(cable->jack_propval, 0, sizeof(cable->jack_propval)); + if (EXTCON_TYPE_DISP & type) + memset(cable->disp_propval, 0, sizeof(cable->disp_propval)); +} + static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -421,7 +475,7 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) if (edev->max_supported && edev->max_supported <= index) return -EINVAL; - return !!(edev->state & (1 << index)); + return is_extcon_attached(edev, index); } EXPORT_SYMBOL_GPL(extcon_get_cable_state_); @@ -449,11 +503,156 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, if (edev->max_supported && edev->max_supported <= index) return -EINVAL; + /* + * Initialize the value of extcon property before setting + * the detached state for an external connector. + */ + if (!cable_state) + init_property(edev, id, index); + state = cable_state ? (1 << index) : 0; return extcon_update_state(edev, 1 << index, state); } EXPORT_SYMBOL_GPL(extcon_set_cable_state_); +/** + * extcon_get_property() - Get the property value of a specific cable. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @prop: the property id among enum extcon_property. + * @prop_val: the pointer which store the value of property. + * + * When getting the property value of external connector, the external connector + * should be attached. If detached state, function just return 0 without + * property value. Also, the each property should be included in the list of + * supported properties according to the type of external connectors. + * + * Returns 0 if success or error number if fail + */ +int extcon_get_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value *prop_val) +{ + struct extcon_cable *cable; + unsigned long flags; + int index, ret = 0; + + *prop_val = (union extcon_property_value)(0); + + if (!edev) + return -EINVAL; + + /* Check whether the property is supported or not */ + if (!is_extcon_property_supported(id, prop)) + return -EINVAL; + + /* Find the cable index of external connector by using id */ + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + spin_lock_irqsave(&edev->lock, flags); + + /* + * Check whether the external connector is attached. + * If external connector is detached, the user can not + * get the property value. + */ + if (!is_extcon_attached(edev, index)) { + spin_unlock_irqrestore(&edev->lock, flags); + return 0; + } + + cable = &edev->cables[index]; + + /* Get the property value according to extcon type */ + switch (prop) { + case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: + *prop_val = cable->usb_propval[prop - EXTCON_PROP_USB_MIN]; + break; + case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: + *prop_val = cable->chg_propval[prop - EXTCON_PROP_CHG_MIN]; + break; + case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: + *prop_val = cable->jack_propval[prop - EXTCON_PROP_JACK_MIN]; + break; + case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: + *prop_val = cable->disp_propval[prop - EXTCON_PROP_DISP_MIN]; + break; + default: + ret = -EINVAL; + break; + } + + spin_unlock_irqrestore(&edev->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(extcon_get_property); + +/** + * extcon_set_property() - Set the property value of a specific cable. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @prop: the property id among enum extcon_property. + * @prop_val: the pointer including the new value of property. + * + * The each property should be included in the list of supported properties + * according to the type of external connectors. + * + * Returns 0 if success or error number if fail + */ +int extcon_set_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val) +{ + struct extcon_cable *cable; + unsigned long flags; + int index, ret = 0; + + if (!edev) + return -EINVAL; + + /* Check whether the property is supported or not */ + if (!is_extcon_property_supported(id, prop)) + return -EINVAL; + + /* Find the cable index of external connector by using id */ + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + spin_lock_irqsave(&edev->lock, flags); + + cable = &edev->cables[index]; + + /* Set the property value according to extcon type */ + switch (prop) { + case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: + cable->usb_propval[prop - EXTCON_PROP_USB_MIN] = prop_val; + break; + case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: + cable->chg_propval[prop - EXTCON_PROP_CHG_MIN] = prop_val; + break; + case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: + cable->jack_propval[prop - EXTCON_PROP_JACK_MIN] = prop_val; + break; + case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: + cable->disp_propval[prop - EXTCON_PROP_DISP_MIN] = prop_val; + break; + default: + ret = -EINVAL; + break; + } + + spin_unlock_irqrestore(&edev->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(extcon_set_property); + /** * extcon_get_extcon_dev() - Get the extcon device instance from the name * @extcon_name: The extcon name provided with extcon_dev_register() diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 46d802892c82..f9d4a44e86d3 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -77,6 +77,63 @@ #define EXTCON_NUM 63 +/* + * Define the property of supported external connectors. + * + * When adding the new extcon property, they *must* have + * the type/value/default information. Also, you *have to* + * modify the EXTCON_PROP_[type]_START/END definitions + * which mean the range of the supported properties + * for each extcon type. + * + * The naming style of property + * : EXTCON_PROP_[type]_[property name] + * + * EXTCON_PROP_USB_[property name] : USB property + * EXTCON_PROP_CHG_[property name] : Charger property + * EXTCON_PROP_JACK_[property name] : Jack property + * EXTCON_PROP_DISP_[property name] : Display property + */ + +/* + * Properties of EXTCON_TYPE_USB. + * + * - EXTCON_PROP_USB_VBUS + * @type: integer (intval) + * @value: 0 (low) or 1 (high) + * @default: 0 (low) + */ +#define EXTCON_PROP_USB_VBUS 0 + +#define EXTCON_PROP_USB_MIN 0 +#define EXTCON_PROP_USB_MAX 0 +#define EXTCON_PROP_USB_CNT (EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1) + +/* Properties of EXTCON_TYPE_CHG. */ +#define EXTCON_PROP_CHG_MIN 50 +#define EXTCON_PROP_CHG_MAX 50 +#define EXTCON_PROP_CHG_CNT (EXTCON_PROP_CHG_MAX - EXTCON_PROP_CHG_MIN + 1) + +/* Properties of EXTCON_TYPE_JACK. */ +#define EXTCON_PROP_JACK_MIN 100 +#define EXTCON_PROP_JACK_MAX 100 +#define EXTCON_PROP_JACK_CNT (EXTCON_PROP_JACK_MAX - EXTCON_PROP_JACK_MIN + 1) + +/* Properties of EXTCON_TYPE_DISP. */ +#define EXTCON_PROP_DISP_MIN 150 +#define EXTCON_PROP_DISP_MAX 150 +#define EXTCON_PROP_DISP_CNT (EXTCON_PROP_DISP_MAX - EXTCON_PROP_DISP_MIN + 1) + +/* + * Define the type of property's value. + * + * Define the property's value as union type. Because each property + * would need the different data type to store it. + */ +union extcon_property_value { + int intval; /* type : integer (intval) */ +}; + struct extcon_cable; /** @@ -166,6 +223,17 @@ 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); +/* + * get/set_property access the property value of each external connector. + * They are used to access the property of each cable based on the property id. + */ +extern int extcon_get_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value *prop_val); +extern int extcon_set_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val); + /* * Following APIs are to monitor every action of a notifier. * Registrar gets notified for every external port of a connection device. @@ -239,6 +307,19 @@ static inline int extcon_set_cable_state_(struct extcon_dev *edev, return 0; } +static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value *prop_val) +{ + return 0; +} +static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val) +{ + return 0; +} + static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { return NULL; From 7f2a0a1699b51bfd738f1e0b15e057996fe1f259 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 25 Jul 2016 21:15:19 +0900 Subject: [PATCH 012/343] extcon: Add the support for the capability of each property This patch adds the support of the property capability setting. This function decides the supported properties of each external connector on extcon provider driver. Ths list of new extcon APIs to get/set the capability of property as following: - int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop); - int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop); Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 140 ++++++++++++++++++++++++++++++++++++++++ include/linux/extcon.h | 22 +++++++ 2 files changed, 162 insertions(+) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 37fa4b51c5a1..599fc377a965 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -201,6 +201,11 @@ struct extcon_cable { union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT]; union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; + + unsigned long usb_bits[BITS_TO_LONGS(EXTCON_PROP_USB_CNT)]; + unsigned long chg_bits[BITS_TO_LONGS(EXTCON_PROP_CHG_CNT)]; + unsigned long jack_bits[BITS_TO_LONGS(EXTCON_PROP_JACK_CNT)]; + unsigned long disp_bits[BITS_TO_LONGS(EXTCON_PROP_DISP_CNT)]; }; static struct class *extcon_class; @@ -297,6 +302,39 @@ static bool is_extcon_property_supported(unsigned int id, unsigned int prop) return !!(extcon_info[id].type & type); } +static int is_extcon_property_capability(struct extcon_dev *edev, + unsigned int id, int index,unsigned int prop) +{ + struct extcon_cable *cable; + int type, ret; + + /* Check whether the property is supported or not. */ + type = get_extcon_type(prop); + if (type < 0) + return type; + + cable = &edev->cables[index]; + + switch (type) { + case EXTCON_TYPE_USB: + ret = test_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits); + break; + case EXTCON_TYPE_CHG: + ret = test_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits); + break; + case EXTCON_TYPE_JACK: + ret = test_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits); + break; + case EXTCON_TYPE_DISP: + ret = test_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits); + break; + default: + ret = -EINVAL; + } + + return ret; +} + static void init_property(struct extcon_dev *edev, unsigned int id, int index) { unsigned int type = extcon_info[id].type; @@ -554,6 +592,12 @@ int extcon_get_property(struct extcon_dev *edev, unsigned int id, spin_lock_irqsave(&edev->lock, flags); + /* Check whether the property is available or not. */ + if (!is_extcon_property_capability(edev, id, index, prop)) { + spin_unlock_irqrestore(&edev->lock, flags); + return -EPERM; + } + /* * Check whether the external connector is attached. * If external connector is detached, the user can not @@ -626,6 +670,12 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id, spin_lock_irqsave(&edev->lock, flags); + /* Check whether the property is available or not. */ + if (!is_extcon_property_capability(edev, id, index, prop)) { + spin_unlock_irqrestore(&edev->lock, flags); + return -EPERM; + } + cable = &edev->cables[index]; /* Set the property value according to extcon type */ @@ -653,6 +703,96 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id, } EXPORT_SYMBOL_GPL(extcon_set_property); +/** + * extcon_get_property_capability() - Get the capability of property + * of an external connector. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @prop: the property id among enum extcon_property. + * + * Returns 1 if the property is available or 0 if not available. + */ +int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, + unsigned int prop) +{ + int index; + + if (!edev) + return -EINVAL; + + /* Check whether the property is supported or not */ + if (!is_extcon_property_supported(id, prop)) + return -EINVAL; + + /* Find the cable index of external connector by using id */ + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + return is_extcon_property_capability(edev, id, index, prop); +} +EXPORT_SYMBOL_GPL(extcon_get_property_capability); + +/** + * extcon_set_property_capability() - Set the capability of a property + * of an external connector. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @prop: the property id among enum extcon_property. + * + * This function set the capability of a property for an external connector + * to mark the bit in capability bitmap which mean the available state of + * a property. + * + * Returns 0 if success or error number if fail + */ +int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, + unsigned int prop) +{ + struct extcon_cable *cable; + int index, type, ret = 0; + + if (!edev) + return -EINVAL; + + /* Check whether the property is supported or not. */ + if (!is_extcon_property_supported(id, prop)) + return -EINVAL; + + /* Find the cable index of external connector by using id. */ + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + type = get_extcon_type(prop); + if (type < 0) + return type; + + cable = &edev->cables[index]; + + switch (type) { + case EXTCON_TYPE_USB: + __set_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits); + break; + case EXTCON_TYPE_CHG: + __set_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits); + break; + case EXTCON_TYPE_JACK: + __set_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits); + break; + case EXTCON_TYPE_DISP: + __set_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits); + break; + default: + ret = -EINVAL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(extcon_set_property_capability); + /** * extcon_get_extcon_dev() - Get the extcon device instance from the name * @extcon_name: The extcon name provided with extcon_dev_register() diff --git a/include/linux/extcon.h b/include/linux/extcon.h index f9d4a44e86d3..f08469089f74 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -234,6 +234,16 @@ extern int extcon_set_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val); +/* + * get/set_property_capability set the capability of the property for each + * external connector. They are used to set the capability of the property + * of each external connector based on the id and property. + */ +extern int extcon_get_property_capability(struct extcon_dev *edev, + unsigned int id, unsigned int prop); +extern int extcon_set_property_capability(struct extcon_dev *edev, + unsigned int id, unsigned int prop); + /* * Following APIs are to monitor every action of a notifier. * Registrar gets notified for every external port of a connection device. @@ -320,6 +330,18 @@ static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, return 0; } +static inline int extcon_get_property_capability(struct extcon_dev *edev, + unsigned int id, unsigned int prop) +{ + return 0; +} + +static inline int extcon_set_property_capability(struct extcon_dev *edev, + unsigned int id, unsigned int prop) +{ + return 0; +} + static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { return NULL; From 575c2b867ee0c2affdd309f375c032c0c7dc219c Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 22 Jul 2016 13:03:17 +0900 Subject: [PATCH 013/343] extcon: Rename the extcon_set/get_state() to maintain the function naming pattern This patch just renames the existing extcon_get/set_cable_state_() as following because of maintaining the function naming pattern like as extcon APIs for property. - extcon_set_cable_state_() -> extcon_set_state() - extcon_get_cable_state_() -> extcon_get_state() But, this patch remains the old extcon_set/get_cable_state_() functions to prevent the build break. After altering new APIs, remove the old APIs. Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 28 +++++++++++++--------------- include/linux/extcon.h | 25 ++++++++++++++++++------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 599fc377a965..d66adfd21159 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -398,8 +398,7 @@ static ssize_t cable_state_show(struct device *dev, int i = cable->cable_index; return sprintf(buf, "%d\n", - extcon_get_cable_state_(cable->edev, - cable->edev->supported_cable[i])); + extcon_get_state(cable->edev, cable->edev->supported_cable[i])); } /** @@ -495,13 +494,14 @@ static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) } /** - * extcon_get_cable_state_() - Get the status of a specific cable. + * extcon_get_state() - Get the state of a external connector. * @edev: the extcon device that has the cable. * @id: the unique id of each external connector in extcon enumeration. */ -int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) +int extcon_get_state(struct extcon_dev *edev, const unsigned int id) { - int index; + int index, state; + unsigned long flags; if (!edev) return -EINVAL; @@ -510,22 +510,23 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) if (index < 0) return index; - if (edev->max_supported && edev->max_supported <= index) - return -EINVAL; + spin_lock_irqsave(&edev->lock, flags); + state = is_extcon_attached(edev, index); + spin_unlock_irqrestore(&edev->lock, flags); - return is_extcon_attached(edev, index); + return state; } -EXPORT_SYMBOL_GPL(extcon_get_cable_state_); +EXPORT_SYMBOL_GPL(extcon_get_state); /** - * extcon_set_cable_state_() - Set the status of a specific cable. + * extcon_set_state() - Set the state of a external connector. * @edev: the extcon device that has the cable. * @id: the unique id of each external connector * in extcon enumeration. * @state: the new cable status. The default semantics is * true: attached / false: detached. */ -int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, +int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool cable_state) { u32 state; @@ -538,9 +539,6 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, if (index < 0) return index; - if (edev->max_supported && edev->max_supported <= index) - return -EINVAL; - /* * Initialize the value of extcon property before setting * the detached state for an external connector. @@ -551,7 +549,7 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, state = cable_state ? (1 << index) : 0; return extcon_update_state(edev, 1 << index, state); } -EXPORT_SYMBOL_GPL(extcon_set_cable_state_); +EXPORT_SYMBOL_GPL(extcon_set_state); /** * extcon_get_property() - Get the property value of a specific cable. diff --git a/include/linux/extcon.h b/include/linux/extcon.h index f08469089f74..4fa37385c97a 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -216,11 +216,11 @@ extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); /* - * get/set_cable_state access each bit of the 32b encoded state value. + * get/set_state access each bit of the 32b encoded state value. * 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, +extern int extcon_get_state(struct extcon_dev *edev, unsigned int id); +extern int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool cable_state); /* @@ -305,14 +305,14 @@ static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, static inline void devm_extcon_dev_free(struct extcon_dev *edev) { } -static inline int extcon_get_cable_state_(struct extcon_dev *edev, - unsigned int id) + +static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id) { return 0; } -static inline int extcon_set_cable_state_(struct extcon_dev *edev, - unsigned int id, bool cable_state) +static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id, + bool cable_state) { return 0; } @@ -402,4 +402,15 @@ static inline int extcon_unregister_interest(struct extcon_specific_cable_nb { return -EINVAL; } + +static inline int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id) +{ + return extcon_get_state(edev, id); +} + +static inline int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, + bool cable_state) +{ + return extcon_set_state(edev, id, cable_state); +} #endif /* __LINUX_EXTCON_H__ */ From ab11af049f88f059a73f679fb050bd7abb98d24b Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 22 Jul 2016 13:16:34 +0900 Subject: [PATCH 014/343] extcon: Add the synchronization extcon APIs to support the notification This patch adds the synchronization extcon APIs to support the notifications for both state and property. When extcon_*_sync() functions is called, the extcon informs the information from extcon provider to extcon client. The extcon driver may need to change the both state and multiple properties at the same time. After setting the data of a external connector, the extcon send the notification to client driver with the extcon_*_sync(). The list of new extcon APIs as following: - extcon_sync() : Send the notification for each external connector to synchronize the information between extcon provider driver and extcon client driver. - extcon_set_state_sync() : Set the state of external connector with noti. - extcon_set_property_sync() : Set the property of external connector with noti. For example, case 1, change the state of external connector and synchronized the data. extcon_set_state_sync(edev, EXTCON_USB, 1); case 2, change both the state and property of external connector and synchronized the data. extcon_set_state(edev, EXTCON_USB, 1); extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS 1); extcon_sync(edev, EXTCON_USB); case 3, change the property of external connector and synchronized the data. extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS, 0); extcon_sync(edev, EXTCON_USB); case 4, change the property of external connector and synchronized the data. extcon_set_property_sync(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS, 0); Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 216 +++++++++++++++++++++++++--------------- include/linux/extcon.h | 30 +++++- 2 files changed, 167 insertions(+), 79 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index d66adfd21159..8fde4befaa51 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -279,14 +279,11 @@ static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index) return !!(edev->state & BIT(index)); } -static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) +static bool is_extcon_changed(struct extcon_dev *edev, int index, + bool new_state) { - if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) { - *attached = ((new >> idx) & 0x1) ? true : false; - return true; - } - - return false; + int state = !!(edev->state & BIT(index)); + return (state != new_state); } static bool is_extcon_property_supported(unsigned int id, unsigned int prop) @@ -402,21 +399,13 @@ static ssize_t cable_state_show(struct device *dev, } /** - * extcon_update_state() - Update the cable attach states of the extcon device - * only for the masked bits. - * @edev: the extcon device - * @mask: the bit mask to designate updated bits. - * @state: new cable attach status for @edev + * extcon_sync() - Synchronize the states for both the attached/detached + * @edev: the extcon device that has the cable. * - * Changing the state sends uevent with environment variable containing - * the name of extcon device (envp[0]) and the state output (envp[1]). - * Tizen uses this format for extcon device to get events from ports. - * Android uses this format as well. - * - * Note that the notifier provides which bits are changed in the state - * variable with the val parameter (second) to the callback. + * This function send a notification to synchronize the all states of a + * specific external connector */ -static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) +int extcon_sync(struct extcon_dev *edev, unsigned int id) { char name_buf[120]; char state_buf[120]; @@ -425,73 +414,58 @@ static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) int env_offset = 0; int length; int index; + int state; unsigned long flags; - bool attached; if (!edev) return -EINVAL; + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + spin_lock_irqsave(&edev->lock, flags); - if (edev->state != ((edev->state & ~mask) | (state & mask))) { - u32 old_state; + state = !!(edev->state & BIT(index)); + raw_notifier_call_chain(&edev->nh[index], state, edev); - if (check_mutually_exclusive(edev, (edev->state & ~mask) | - (state & mask))) { - spin_unlock_irqrestore(&edev->lock, flags); - return -EPERM; - } - - old_state = edev->state; - edev->state &= ~mask; - edev->state |= state & mask; - - for (index = 0; index < edev->max_supported; index++) { - if (is_extcon_changed(old_state, edev->state, index, - &attached)) - raw_notifier_call_chain(&edev->nh[index], - attached, edev); - } - - /* This could be in interrupt handler */ - prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); - if (prop_buf) { - length = name_show(&edev->dev, NULL, prop_buf); - if (length > 0) { - if (prop_buf[length - 1] == '\n') - prop_buf[length - 1] = 0; - snprintf(name_buf, sizeof(name_buf), - "NAME=%s", prop_buf); - envp[env_offset++] = name_buf; - } - length = state_show(&edev->dev, NULL, prop_buf); - if (length > 0) { - if (prop_buf[length - 1] == '\n') - prop_buf[length - 1] = 0; - snprintf(state_buf, sizeof(state_buf), - "STATE=%s", prop_buf); - envp[env_offset++] = state_buf; - } - envp[env_offset] = NULL; - /* Unlock early before uevent */ - spin_unlock_irqrestore(&edev->lock, flags); - - kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp); - free_page((unsigned long)prop_buf); - } else { - /* Unlock early before uevent */ - spin_unlock_irqrestore(&edev->lock, flags); - - dev_err(&edev->dev, "out of memory in extcon_set_state\n"); - kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE); - } - } else { - /* No changes */ + /* This could be in interrupt handler */ + prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); + if (!prop_buf) { + /* Unlock early before uevent */ spin_unlock_irqrestore(&edev->lock, flags); + + dev_err(&edev->dev, "out of memory in extcon_set_state\n"); + kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE); + + return 0; } + length = name_show(&edev->dev, NULL, prop_buf); + if (length > 0) { + if (prop_buf[length - 1] == '\n') + prop_buf[length - 1] = 0; + snprintf(name_buf, sizeof(name_buf), "NAME=%s", prop_buf); + envp[env_offset++] = name_buf; + } + + length = state_show(&edev->dev, NULL, prop_buf); + if (length > 0) { + if (prop_buf[length - 1] == '\n') + prop_buf[length - 1] = 0; + snprintf(state_buf, sizeof(state_buf), "STATE=%s", prop_buf); + envp[env_offset++] = state_buf; + } + envp[env_offset] = NULL; + + /* Unlock early before uevent */ + spin_unlock_irqrestore(&edev->lock, flags); + kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp); + free_page((unsigned long)prop_buf); + return 0; } +EXPORT_SYMBOL_GPL(extcon_sync); /** * extcon_get_state() - Get the state of a external connector. @@ -520,17 +494,22 @@ EXPORT_SYMBOL_GPL(extcon_get_state); /** * extcon_set_state() - Set the state of a external connector. + * without a notification. * @edev: the extcon device that has the cable. * @id: the unique id of each external connector * in extcon enumeration. * @state: the new cable status. The default semantics is * true: attached / false: detached. + * + * This function only set the state of a external connector without + * a notification. To synchronize the data of a external connector, + * use extcon_set_state_sync() and extcon_sync(). */ int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool cable_state) { - u32 state; - int index; + unsigned long flags; + int index, ret = 0; if (!edev) return -EINVAL; @@ -539,6 +518,18 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id, if (index < 0) return index; + spin_lock_irqsave(&edev->lock, flags); + + /* Check whether the external connector's state is changed. */ + if (!is_extcon_changed(edev, index, cable_state)) + goto out; + + if (check_mutually_exclusive(edev, + (edev->state & ~BIT(index)) | (cable_state & BIT(index)))) { + ret = -EPERM; + goto out; + } + /* * Initialize the value of extcon property before setting * the detached state for an external connector. @@ -546,11 +537,55 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id, if (!cable_state) init_property(edev, id, index); - state = cable_state ? (1 << index) : 0; - return extcon_update_state(edev, 1 << index, state); + /* Update the state for a external connector. */ + if (cable_state) + edev->state |= BIT(index); + else + edev->state &= ~(BIT(index)); +out: + spin_unlock_irqrestore(&edev->lock, flags); + + return ret; } EXPORT_SYMBOL_GPL(extcon_set_state); +/** + * extcon_set_state_sync() - Set the state of a external connector + * with a notification. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @state: the new cable status. The default semantics is + * true: attached / false: detached. + * + * This function set the state of external connector and synchronize the data + * by usning a notification. + */ +int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, + bool cable_state) +{ + int ret, index; + unsigned long flags; + + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + /* Check whether the external connector's state is changed. */ + spin_lock_irqsave(&edev->lock, flags); + ret = is_extcon_changed(edev, index, cable_state); + spin_unlock_irqrestore(&edev->lock, flags); + if (!ret) + return 0; + + ret = extcon_set_state(edev, id, cable_state); + if (ret < 0) + return ret; + + return extcon_sync(edev, id); +} +EXPORT_SYMBOL_GPL(extcon_set_state_sync); + /** * extcon_get_property() - Get the property value of a specific cable. * @edev: the extcon device that has the cable. @@ -701,6 +736,31 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id, } EXPORT_SYMBOL_GPL(extcon_set_property); +/** + * extcon_set_property_sync() - Set the property value of a specific cable + with a notification. + * @prop_val: the pointer including the new value of property. + * + * When setting the property value of external connector, the external connector + * should be attached. The each property should be included in the list of + * supported properties according to the type of external connectors. + * + * Returns 0 if success or error number if fail + */ +int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val) +{ + int ret; + + ret = extcon_set_property(edev, id, prop, prop_val); + if (ret < 0) + return ret; + + return extcon_sync(edev, id); +} +EXPORT_SYMBOL_GPL(extcon_set_property_sync); + /** * extcon_get_property_capability() - Get the capability of property * of an external connector. diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 4fa37385c97a..162c46a42bac 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -222,6 +222,13 @@ extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); extern int extcon_get_state(struct extcon_dev *edev, unsigned int id); extern int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool cable_state); +extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, + bool cable_state); + +/* + * Synchronize the state and property data for a specific external connector. + */ +extern int extcon_sync(struct extcon_dev *edev, unsigned int id); /* * get/set_property access the property value of each external connector. @@ -233,6 +240,9 @@ extern int extcon_get_property(struct extcon_dev *edev, unsigned int id, extern int extcon_set_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val); +extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val); /* * get/set_property_capability set the capability of the property for each @@ -317,6 +327,17 @@ static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id, return 0; } +static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, + bool cable_state) +{ + return 0; +} + +static inline int extcon_sync(struct extcon_dev *edev, unsigned int id) +{ + return 0; +} + static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value *prop_val) @@ -330,6 +351,13 @@ static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, return 0; } +static inline int extcon_set_property_sync(struct extcon_dev *edev, + unsigned int id, unsigned int prop, + union extcon_property_value prop_val) +{ + return 0; +} + static inline int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop) { @@ -411,6 +439,6 @@ static inline int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int static inline int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, bool cable_state) { - return extcon_set_state(edev, id, cable_state); + return extcon_set_state_sync(edev, id, cable_state); } #endif /* __LINUX_EXTCON_H__ */ From 2164188d57f8862f1b69e2c5b7c0585f01077bee Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Fri, 22 Jul 2016 01:13:02 +0900 Subject: [PATCH 015/343] extcon: Add EXTCON_DISP_DP and the property for USB Type-C Add EXTCON_DISP_DP for the Display external connector. For Type-C connector the DisplayPort can work as an Alternate Mode(VESA DisplayPort Alt Mode on USB Type-C Standard). The Type-C support both normal and flipped orientation, so add a property to extcon. Signed-off-by: Chris Zhong Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 5 +++++ include/linux/extcon.h | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 8fde4befaa51..a0a1eea18727 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -157,6 +157,11 @@ struct __extcon_info { .id = EXTCON_DISP_VGA, .name = "VGA", }, + [EXTCON_DISP_DP] = { + .type = EXTCON_TYPE_DISP | EXTCON_TYPE_USB, + .id = EXTCON_DISP_DP, + .name = "DP", + }, /* Miscellaneous external connector */ [EXTCON_DOCK] = { diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 162c46a42bac..ad7a1606a7f3 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -69,6 +69,7 @@ #define EXTCON_DISP_MHL 41 /* Mobile High-Definition Link */ #define EXTCON_DISP_DVI 42 /* Digital Visual Interface */ #define EXTCON_DISP_VGA 43 /* Video Graphics Array */ +#define EXTCON_DISP_DP 44 /* Display Port */ /* Miscellaneous external connector */ #define EXTCON_DOCK 60 @@ -102,11 +103,16 @@ * @type: integer (intval) * @value: 0 (low) or 1 (high) * @default: 0 (low) + * - EXTCON_PROP_USB_TYPEC_POLARITY + * @type: integer (intval) + * @value: 0 (normal) or 1 (flip) + * @default: 0 (normal) */ #define EXTCON_PROP_USB_VBUS 0 +#define EXTCON_PROP_USB_TYPEC_POLARITY 1 #define EXTCON_PROP_USB_MIN 0 -#define EXTCON_PROP_USB_MAX 0 +#define EXTCON_PROP_USB_MAX 1 #define EXTCON_PROP_USB_CNT (EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1) /* Properties of EXTCON_TYPE_CHG. */ From 9c0595d688e9deb337ff8901bb25281cdb19050b Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 5 Aug 2016 17:49:23 +0900 Subject: [PATCH 016/343] extcon: Add new EXTCON_DISP_HMD for Head-mounted Display device This patch adds the new EXTCON_DISP_HMD id for Head-mounted Display[1] device. The HMD device is usually for USB connector type So, the HMD connector has the two extcon types of both EXTCON_TYPE_DISP and EXTCON_TYPE_USB. [1] https://en.wikipedia.org/wiki/Head-mounted_display Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 5 +++++ include/linux/extcon.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index a0a1eea18727..10ba876ea77a 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -162,6 +162,11 @@ struct __extcon_info { .id = EXTCON_DISP_DP, .name = "DP", }, + [EXTCON_DISP_HMD] = { + .type = EXTCON_TYPE_DISP | EXTCON_TYPE_USB, + .id = EXTCON_DISP_HMD, + .name = "HMD", + }, /* Miscellaneous external connector */ [EXTCON_DOCK] = { diff --git a/include/linux/extcon.h b/include/linux/extcon.h index ad7a1606a7f3..e79b644f41a7 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -70,6 +70,7 @@ #define EXTCON_DISP_DVI 42 /* Digital Visual Interface */ #define EXTCON_DISP_VGA 43 /* Video Graphics Array */ #define EXTCON_DISP_DP 44 /* Display Port */ +#define EXTCON_DISP_HMD 45 /* Head-Mounted Display */ /* Miscellaneous external connector */ #define EXTCON_DOCK 60 From 7fe95fb889faf07ee438384858d38b820973397e Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 5 Aug 2016 18:15:46 +0900 Subject: [PATCH 017/343] extcon: Add new EXTCON_CHG_WPT for Wireless Power Transfer device This patchs add the new EXTCON_CHG_WPT for Wireless Power Transfer[1]. The Wireless Power Transfer is the transmission of electronical energy from a power source. The EXTCON_CHG_WPT has the EXTCON_TYPE_CHG. [1] https://en.wikipedia.org/wiki/Wireless_power_transfer Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 5 +++++ include/linux/extcon.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 10ba876ea77a..78298460d168 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -93,6 +93,11 @@ struct __extcon_info { .id = EXTCON_CHG_USB_SLOW, .name = "SLOW-CHARGER", }, + [EXTCON_CHG_WPT] = { + .type = EXTCON_TYPE_CHG, + .id = EXTCON_CHG_WPT, + .name = "WPT", + }, /* Jack external connector */ [EXTCON_JACK_MICROPHONE] = { diff --git a/include/linux/extcon.h b/include/linux/extcon.h index e79b644f41a7..461abee969b7 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -53,6 +53,7 @@ #define EXTCON_CHG_USB_ACA 8 /* Accessory Charger Adapter */ #define EXTCON_CHG_USB_FAST 9 #define EXTCON_CHG_USB_SLOW 10 +#define EXTCON_CHG_WPT 11 /* Wireless Power Transfer */ /* Jack external connector */ #define EXTCON_JACK_MICROPHONE 20 From 740a6a1720f631ef2ad84fc378f2469c37f389c7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 25 Jun 2016 22:24:54 -0700 Subject: [PATCH 018/343] usb: misc: Add driver for usb4604 This is a minimal driver to support bringing a usb4604 device from microchip out of reset and into hub mode. The usb4604 device is related to the usb3503 device, but it didn't seem close enough to warrant putting both into the same file. This patch borrows some of the usb3503 structure and trims it down to just handle the optional reset gpio and adds the i2c command to put the device into hub mode. Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/00001716A.pdf Cc: Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/usb4604.txt | 19 ++ drivers/usb/misc/Kconfig | 6 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/usb4604.c | 175 ++++++++++++++++++ 4 files changed, 201 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/usb4604.txt create mode 100644 drivers/usb/misc/usb4604.c diff --git a/Documentation/devicetree/bindings/usb/usb4604.txt b/Documentation/devicetree/bindings/usb/usb4604.txt new file mode 100644 index 000000000000..82506d17712c --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb4604.txt @@ -0,0 +1,19 @@ +SMSC USB4604 High-Speed Hub Controller + +Required properties: +- compatible: Should be "smsc,usb4604" + +Optional properties: +- reg: Specifies the i2c slave address, it is required and should be 0x2d + if I2C is used. +- reset-gpios: Should specify GPIO for reset. +- initial-mode: Should specify initial mode. + (1 for HUB mode, 2 for STANDBY mode) + +Examples: + usb-hub@2d { + compatible = "smsc,usb4604"; + reg = <0x2d>; + reset-gpios = <&gpx3 5 1>; + initial-mode = <1>; + }; diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index eb8f8d37cd95..47b357760afc 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -240,6 +240,12 @@ config USB_HSIC_USB3503 help This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. +config USB_HSIC_USB4604 + tristate "USB4604 HSIC to USB20 Driver" + depends on I2C + help + This option enables support for SMSC USB4604 HSIC to USB 2.0 Driver. + config USB_LINK_LAYER_TEST tristate "USB Link Layer Test driver" help diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 3d79faaad2fb..3d1992750da4 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o obj-$(CONFIG_USB_YUREX) += yurex.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o +obj-$(CONFIG_USB_HSIC_USB4604) += usb4604.o obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o obj-$(CONFIG_UCSI) += ucsi.o diff --git a/drivers/usb/misc/usb4604.c b/drivers/usb/misc/usb4604.c new file mode 100644 index 000000000000..e9f37fb746ac --- /dev/null +++ b/drivers/usb/misc/usb4604.c @@ -0,0 +1,175 @@ +/* + * Driver for SMSC USB4604 USB HSIC 4-port 2.0 hub controller driver + * Based on usb3503 driver + * + * Copyright (c) 2012-2013 Dongjin Kim (tobetter@gmail.com) + * Copyright (c) 2016 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include + +enum usb4604_mode { + USB4604_MODE_UNKNOWN, + USB4604_MODE_HUB, + USB4604_MODE_STANDBY, +}; + +struct usb4604 { + enum usb4604_mode mode; + struct device *dev; + struct gpio_desc *gpio_reset; +}; + +static void usb4604_reset(struct usb4604 *hub, int state) +{ + gpiod_set_value_cansleep(hub->gpio_reset, state); + + /* Wait for i2c logic to come up */ + if (state) + msleep(250); +} + +static int usb4604_connect(struct usb4604 *hub) +{ + struct device *dev = hub->dev; + struct i2c_client *client = to_i2c_client(dev); + int err; + u8 connect_cmd[] = { 0xaa, 0x55, 0x00 }; + + usb4604_reset(hub, 1); + + err = i2c_master_send(client, connect_cmd, ARRAY_SIZE(connect_cmd)); + if (err < 0) { + usb4604_reset(hub, 0); + return err; + } + + hub->mode = USB4604_MODE_HUB; + dev_dbg(dev, "switched to HUB mode\n"); + + return 0; +} + +static int usb4604_switch_mode(struct usb4604 *hub, enum usb4604_mode mode) +{ + struct device *dev = hub->dev; + int err = 0; + + switch (mode) { + case USB4604_MODE_HUB: + err = usb4604_connect(hub); + break; + + case USB4604_MODE_STANDBY: + usb4604_reset(hub, 0); + dev_dbg(dev, "switched to STANDBY mode\n"); + break; + + default: + dev_err(dev, "unknown mode is requested\n"); + err = -EINVAL; + break; + } + + return err; +} + +static int usb4604_probe(struct usb4604 *hub) +{ + struct device *dev = hub->dev; + struct device_node *np = dev->of_node; + struct gpio_desc *gpio; + u32 mode = USB4604_MODE_HUB; + + gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + hub->gpio_reset = gpio; + + if (of_property_read_u32(np, "initial-mode", &hub->mode)) + hub->mode = mode; + + return usb4604_switch_mode(hub, hub->mode); +} + +static int usb4604_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct usb4604 *hub; + + hub = devm_kzalloc(&i2c->dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + i2c_set_clientdata(i2c, hub); + hub->dev = &i2c->dev; + + return usb4604_probe(hub); +} + +#ifdef CONFIG_PM_SLEEP +static int usb4604_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb4604 *hub = i2c_get_clientdata(client); + + usb4604_switch_mode(hub, USB4604_MODE_STANDBY); + + return 0; +} + +static int usb4604_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb4604 *hub = i2c_get_clientdata(client); + + usb4604_switch_mode(hub, hub->mode); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(usb4604_i2c_pm_ops, usb4604_i2c_suspend, + usb4604_i2c_resume); + +static const struct i2c_device_id usb4604_id[] = { + { "usb4604", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, usb4604_id); + +#ifdef CONFIG_OF +static const struct of_device_id usb4604_of_match[] = { + { .compatible = "smsc,usb4604" }, + {} +}; +MODULE_DEVICE_TABLE(of, usb4604_of_match); +#endif + +static struct i2c_driver usb4604_i2c_driver = { + .driver = { + .name = "usb4604", + .pm = &usb4604_i2c_pm_ops, + .of_match_table = of_match_ptr(usb4604_of_match), + }, + .probe = usb4604_i2c_probe, + .id_table = usb4604_id, +}; +module_i2c_driver(usb4604_i2c_driver); + +MODULE_DESCRIPTION("USB4604 USB HUB driver"); +MODULE_LICENSE("GPL v2"); From 72cd194f897d7f7e334d570662b25f71068e5637 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 5 Aug 2016 13:26:53 +0200 Subject: [PATCH 019/343] usb: host: fsl-mph-dr-of: use of_property_read_bool Use of_property_read_bool to check for the existence of a property. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression e1,e2,x; @@ - if (of_get_property(e1,e2,NULL)) - x = true; - else - x = false; + x = of_property_read_bool(e1,e2); // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fsl-mph-dr-of.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 1044b0f9d656..f07ccb25bc24 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -222,23 +222,17 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->controller_ver = usb_get_ver_info(np); /* Activate Erratum by reading property in device tree */ - if (of_get_property(np, "fsl,usb-erratum-a007792", NULL)) - pdata->has_fsl_erratum_a007792 = 1; - else - pdata->has_fsl_erratum_a007792 = 0; - if (of_get_property(np, "fsl,usb-erratum-a005275", NULL)) - pdata->has_fsl_erratum_a005275 = 1; - else - pdata->has_fsl_erratum_a005275 = 0; + pdata->has_fsl_erratum_a007792 = + of_property_read_bool(np, "fsl,usb-erratum-a007792"); + pdata->has_fsl_erratum_a005275 = + of_property_read_bool(np, "fsl,usb-erratum-a005275"); /* * Determine whether phy_clk_valid needs to be checked * by reading property in device tree */ - if (of_get_property(np, "phy-clk-valid", NULL)) - pdata->check_phy_clk_valid = 1; - else - pdata->check_phy_clk_valid = 0; + pdata->check_phy_clk_valid = + of_property_read_bool(np, "phy-clk-valid"); if (pdata->have_sysif_regs) { if (pdata->controller_ver == FSL_USB_VER_NONE) { From bd783108acfe359f1817365823d4a98d79e37dbb Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Thu, 28 Jul 2016 14:15:11 +0530 Subject: [PATCH 020/343] usb: lvstest: Remove deprecated create_singlethread_workqueue The workqueue has a single work item(&lvs->rh_work) and hence doesn't require ordering. Also, it is not being used on a memory reclaim path. Hence, the singlethreaded workqueue has been replaced with the use of system_wq. System workqueues have been able to handle high level of concurrency for a long time now and hence it's not required to have a singlethreaded workqueue just to gain concurrency. Unlike a dedicated per-cpu workqueue created with create_singlethread_workqueue(), system_wq allows multiple work items to overlap executions even on the same CPU; however, a per-cpu workqueue doesn't have any CPU locality or global ordering guarantee unless the target CPU is explicitly specified and thus the increase of local concurrency shouldn't make any difference. The work item has been flushed in lvs_rh_disconnect() to ensure that there are no pending tasks while disconnecting the driver. Signed-off-by: Bhaktipriya Shridhar Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/lvstest.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c index 86b4e4b2ab9a..a985cadc0b76 100644 --- a/drivers/usb/misc/lvstest.c +++ b/drivers/usb/misc/lvstest.c @@ -34,8 +34,6 @@ struct lvs_rh { struct usb_hub_descriptor descriptor; /* urb for polling interrupt pipe */ struct urb *urb; - /* LVS RH work queue */ - struct workqueue_struct *rh_queue; /* LVH RH work */ struct work_struct rh_work; /* RH port status */ @@ -355,7 +353,7 @@ static void lvs_rh_irq(struct urb *urb) { struct lvs_rh *lvs = urb->context; - queue_work(lvs->rh_queue, &lvs->rh_work); + schedule_work(&lvs->rh_work); } static int lvs_rh_probe(struct usb_interface *intf, @@ -402,19 +400,12 @@ static int lvs_rh_probe(struct usb_interface *intf, return -ENOMEM; } - lvs->rh_queue = create_singlethread_workqueue("lvs_rh_queue"); - if (!lvs->rh_queue) { - dev_err(&intf->dev, "couldn't create workqueue\n"); - ret = -ENOMEM; - goto free_urb; - } - INIT_WORK(&lvs->rh_work, lvs_rh_work); ret = sysfs_create_group(&intf->dev.kobj, &lvs_attr_group); if (ret < 0) { dev_err(&intf->dev, "Failed to create sysfs node %d\n", ret); - goto destroy_queue; + goto free_urb; } pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); @@ -432,8 +423,6 @@ static int lvs_rh_probe(struct usb_interface *intf, sysfs_remove: sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); -destroy_queue: - destroy_workqueue(lvs->rh_queue); free_urb: usb_free_urb(lvs->urb); return ret; @@ -444,7 +433,7 @@ static void lvs_rh_disconnect(struct usb_interface *intf) struct lvs_rh *lvs = usb_get_intfdata(intf); sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); - destroy_workqueue(lvs->rh_queue); + flush_work(&lvs->rh_work); usb_free_urb(lvs->urb); } From 6a0bb4348bb4b6cce1bb06ac8fa38fc4fb0d9088 Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Tue, 26 Jul 2016 22:19:18 +0530 Subject: [PATCH 021/343] USB: appledisplay: Remove deprecated create_singlethread_workqueue The workqueue "wq" is involved in controlling the brightness of an Apple Cinema Display over USB. It has a single work item(&pdata->work) per appledisplay and hence doesn't require ordering. Also, it is not being used on a memory reclaim path. Hence, the singlethreaded workqueue has been replaced with the use of system_wq. System workqueues have been able to handle high level of concurrency for a long time now and hence it's not required to have a singlethreaded workqueue just to gain concurrency. Unlike a dedicated per-cpu workqueue created with create_singlethread_workqueue(), system_wq allows multiple work items to overlap executions even on the same CPU; however, a per-cpu workqueue doesn't have any CPU locality or global ordering guarantee unless the target CPU is explicitly specified and thus the increase of local concurrency shouldn't make any difference. The work item is self-requeueing and needs to wait for the in-flight work item to finish before proceeding with destruction. Hence, it has been sync cancelled in appledisplay_disconnect(). This also ensures that there are no pending tasks while disconnecting the driver. Signed-off-by: Bhaktipriya Shridhar Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/appledisplay.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index a0a3827b4aff..188c8d2e6007 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -85,7 +85,6 @@ struct appledisplay { }; static atomic_t count_displays = ATOMIC_INIT(0); -static struct workqueue_struct *wq; static void appledisplay_complete(struct urb *urb) { @@ -122,7 +121,7 @@ static void appledisplay_complete(struct urb *urb) case ACD_BTN_BRIGHT_UP: case ACD_BTN_BRIGHT_DOWN: pdata->button_pressed = 1; - queue_delayed_work(wq, &pdata->work, 0); + schedule_delayed_work(&pdata->work, 0); break; case ACD_BTN_NONE: default: @@ -344,7 +343,7 @@ static void appledisplay_disconnect(struct usb_interface *iface) if (pdata) { usb_kill_urb(pdata->urb); - cancel_delayed_work(&pdata->work); + cancel_delayed_work_sync(&pdata->work); backlight_device_unregister(pdata->bd); usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN, pdata->urbdata, pdata->urb->transfer_dma); @@ -365,19 +364,11 @@ static struct usb_driver appledisplay_driver = { static int __init appledisplay_init(void) { - wq = create_singlethread_workqueue("appledisplay"); - if (!wq) { - printk(KERN_ERR "appledisplay: Could not create work queue\n"); - return -ENOMEM; - } - return usb_register(&appledisplay_driver); } static void __exit appledisplay_exit(void) { - flush_workqueue(wq); - destroy_workqueue(wq); usb_deregister(&appledisplay_driver); } From c936f45fc25fd53c1517571aa379e07bca1f28ed Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Tue, 26 Jul 2016 10:47:20 +0530 Subject: [PATCH 022/343] usb: ftdi-elan: Remove deprecated create_singlethread_workqueue The status workqueue is involved in initializing the Uxxx and polling the Uxxx until a supported PCMCIA CardBus device is detected. It then starts the command and respond workqueues and then loads the module that handles the device, after which it just polls the Uxxx looking for card ejects. The command and respond workqueues are involved in implementing a command sequencer for communicating with the firmware on the other side of the FTDI chip in the Uxxx. These workqueues have only a single work item each and hence they do not require ordering. Also, none of the above workqueues are being used on a memory recliam path. Hence, the singlethreaded workqueues have been replaced with the use of system_wq. System workqueues have been able to handle high level of concurrency for a long time now and hence it's not required to have a singlethreaded workqueue just to gain concurrency. Unlike a dedicated per-cpu workqueue created with create_singlethread_workqueue(), system_wq allows multiple work items to overlap executions even on the same CPU; however, a per-cpu workqueue doesn't have any CPU locality or global ordering guarantee unless the target CPU is explicitly specified and thus the increase of local concurrency shouldn't make any difference. The work items have been sync cancelled because they are self-requeueing and need to wait for the in-flight work item to finish before proceeding with destruction. Hence, they have been sync cancelled in ftdi_status_cancel_work(), ftdi_command_cancel_work() and ftdi_response_cancel_work(). These functions are called in ftdi_elan_exit() to ensure that there are no pending work items while disconnecting the driver. Signed-off-by: Bhaktipriya Shridhar Acked-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 53 +++++++----------------------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 52c27cab78c3..59031dc21eab 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -61,9 +61,6 @@ module_param(distrust_firmware, bool, 0); MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent setup"); extern struct platform_driver u132_platform_driver; -static struct workqueue_struct *status_queue; -static struct workqueue_struct *command_queue; -static struct workqueue_struct *respond_queue; /* * ftdi_module_lock exists to protect access to global variables * @@ -228,56 +225,56 @@ static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (!queue_delayed_work(status_queue, &ftdi->status_work, delta)) + if (!schedule_delayed_work(&ftdi->status_work, delta)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) + if (schedule_delayed_work(&ftdi->status_work, delta)) kref_get(&ftdi->kref); } static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->status_work)) + if (cancel_delayed_work_sync(&ftdi->status_work)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (!queue_delayed_work(command_queue, &ftdi->command_work, delta)) + if (!schedule_delayed_work(&ftdi->command_work, delta)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (queue_delayed_work(command_queue, &ftdi->command_work, delta)) + if (schedule_delayed_work(&ftdi->command_work, delta)) kref_get(&ftdi->kref); } static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->command_work)) + if (cancel_delayed_work_sync(&ftdi->command_work)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + if (!schedule_delayed_work(&ftdi->respond_work, delta)) kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + if (schedule_delayed_work(&ftdi->respond_work, delta)) kref_get(&ftdi->kref); } static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) { - if (cancel_delayed_work(&ftdi->respond_work)) + if (cancel_delayed_work_sync(&ftdi->respond_work)) kref_put(&ftdi->kref, ftdi_elan_delete); } @@ -2823,9 +2820,6 @@ static void ftdi_elan_disconnect(struct usb_interface *interface) ftdi->initialized = 0; ftdi->registered = 0; } - flush_workqueue(status_queue); - flush_workqueue(command_queue); - flush_workqueue(respond_queue); ftdi->disconnected += 1; usb_set_intfdata(interface, NULL); dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n"); @@ -2845,31 +2839,12 @@ static int __init ftdi_elan_init(void) pr_info("driver %s\n", ftdi_elan_driver.name); mutex_init(&ftdi_module_lock); INIT_LIST_HEAD(&ftdi_static_list); - status_queue = create_singlethread_workqueue("ftdi-status-control"); - if (!status_queue) - goto err_status_queue; - command_queue = create_singlethread_workqueue("ftdi-command-engine"); - if (!command_queue) - goto err_command_queue; - respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); - if (!respond_queue) - goto err_respond_queue; result = usb_register(&ftdi_elan_driver); if (result) { - destroy_workqueue(status_queue); - destroy_workqueue(command_queue); - destroy_workqueue(respond_queue); pr_err("usb_register failed. Error number %d\n", result); } return result; -err_respond_queue: - destroy_workqueue(command_queue); -err_command_queue: - destroy_workqueue(status_queue); -err_status_queue: - pr_err("%s couldn't create workqueue\n", ftdi_elan_driver.name); - return -ENOMEM; } static void __exit ftdi_elan_exit(void) @@ -2882,15 +2857,7 @@ static void __exit ftdi_elan_exit(void) ftdi_status_cancel_work(ftdi); ftdi_command_cancel_work(ftdi); ftdi_response_cancel_work(ftdi); - } flush_workqueue(status_queue); - destroy_workqueue(status_queue); - status_queue = NULL; - flush_workqueue(command_queue); - destroy_workqueue(command_queue); - command_queue = NULL; - flush_workqueue(respond_queue); - destroy_workqueue(respond_queue); - respond_queue = NULL; + } } From ec7b1268510908157d4e8878bb753ea844446856 Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Thu, 28 Jul 2016 13:57:29 +0530 Subject: [PATCH 023/343] usb: dwc2: Remove deprecated create_singlethread_workqueue alloc_ordered_workqueue replaces the deprecated create_singlethread_workqueue. There are multiple work items on the work queue, which require ordering. Hence, an ordered workqueue has been used. The workqueue "wq_otg" is not being used on a memory reclaim path. Hence, WQ_MEM_RECLAIM has not been set. Signed-off-by: Bhaktipriya Shridhar Acked-by: Tejun Heo Acked-by: John Youn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 2df3d04d26f5..df5a06578005 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -5040,7 +5040,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) /* Create new workqueue and init work */ retval = -ENOMEM; - hsotg->wq_otg = create_singlethread_workqueue("dwc2"); + hsotg->wq_otg = alloc_ordered_workqueue("dwc2", 0); if (!hsotg->wq_otg) { dev_err(hsotg->dev, "Failed to create workqueue\n"); goto error2; From 833415a3e781a26fe480a34d45086bdb4fe1e4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Sun, 10 Jul 2016 17:45:14 +0200 Subject: [PATCH 024/343] cdc-wdm: fix "out-of-sync" due to missing notifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver enforces a strict one-to-one relationship between the received RESPONSE_AVAILABLE notifications and messages read from the device. At the same time, it will cancel the interrupt URB when there is no client holding the character device open. Many devices do not cope well with this behaviour. They maintain a FIFO queue of messages, and send notifications on a best effort basis. Messages are queued regardless of whether the notification is successful or not. So if the driver loses a single notification, which can easily happen when the interrupt URB is cancelled, then the device and driver becomes out-of-sync. New messages end up at the end of the queue, while the associated notification makes the driver read only the first message from the queue. This state is permanent from a user point of view. There is no no way to flush the device queue without resetting the device or using another driver. The problem is easy to hit with current QMI and MBIM command line tools, which typically close the character device after seeing the reply they expect. Any pending unsolicited messages from the device will then trigger the driver bug. Fix by always reading all queued messages from the device when the notification URB is first submitted. This is expected to end with an -EPIPE status when there are no more pending messages, so demote the printk associated with -EPIPE to debug level. The workaround has been tested on a large number of different MBIM and QMI devices, as well as the Ericsson F5521gw and H5321gw modems with real Device Management functions. Signed-off-by: Bjørn Mork Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 103 ++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 337948c42110..4bfc48d18654 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -58,6 +58,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); #define WDM_SUSPENDING 8 #define WDM_RESETTING 9 #define WDM_OVERFLOW 10 +#define WDM_DRAIN_ON_OPEN 11 #define WDM_MAX 16 @@ -178,7 +179,7 @@ static void wdm_in_callback(struct urb *urb) "nonzero urb status received: -ESHUTDOWN"); goto skip_error; case -EPIPE: - dev_err(&desc->intf->dev, + dev_dbg(&desc->intf->dev, "nonzero urb status received: -EPIPE\n"); break; default: @@ -200,10 +201,30 @@ static void wdm_in_callback(struct urb *urb) desc->reslength = length; } } + + /* + * Handling devices with the WDM_DRAIN_ON_OPEN flag set: + * If desc->resp_count is unset, then the urb was submitted + * without a prior notification. If the device returned any + * data, then this implies that it had messages queued without + * notifying us. Continue reading until that queue is flushed. + */ + if (!desc->resp_count) { + if (!length) { + /* do not propagate the expected -EPIPE */ + desc->rerr = 0; + goto unlock; + } + dev_dbg(&desc->intf->dev, "got %d bytes without notification\n", length); + set_bit(WDM_RESPONDING, &desc->flags); + usb_submit_urb(desc->response, GFP_ATOMIC); + } + skip_error: wake_up(&desc->wait); set_bit(WDM_READ, &desc->flags); +unlock: spin_unlock(&desc->iuspin); } @@ -647,6 +668,17 @@ static int wdm_open(struct inode *inode, struct file *file) dev_err(&desc->intf->dev, "Error submitting int urb - %d\n", rv); rv = usb_translate_errors(rv); + } else if (test_bit(WDM_DRAIN_ON_OPEN, &desc->flags)) { + /* + * Some devices keep pending messages queued + * without resending notifications. We must + * flush the message queue before we can + * assume a one-to-one relationship between + * notifications and messages in the queue + */ + dev_dbg(&desc->intf->dev, "draining queued data\n"); + set_bit(WDM_RESPONDING, &desc->flags); + rv = usb_submit_urb(desc->response, GFP_KERNEL); } } else { rv = 0; @@ -753,7 +785,8 @@ static void wdm_rxwork(struct work_struct *work) /* --- hotplug --- */ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, - u16 bufsize, int (*manage_power)(struct usb_interface *, int)) + u16 bufsize, int (*manage_power)(struct usb_interface *, int), + bool drain_on_open) { int rv = -ENOMEM; struct wdm_device *desc; @@ -840,6 +873,68 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor desc->manage_power = manage_power; + /* + * "drain_on_open" enables a hack to work around a firmware + * issue observed on network functions, in particular MBIM + * functions. + * + * Quoting section 7 of the CDC-WMC r1.1 specification: + * + * "The firmware shall interpret GetEncapsulatedResponse as a + * request to read response bytes. The firmware shall send + * the next wLength bytes from the response. The firmware + * shall allow the host to retrieve data using any number of + * GetEncapsulatedResponse requests. The firmware shall + * return a zero- length reply if there are no data bytes + * available. + * + * The firmware shall send ResponseAvailable notifications + * periodically, using any appropriate algorithm, to inform + * the host that there is data available in the reply + * buffer. The firmware is allowed to send ResponseAvailable + * notifications even if there is no data available, but + * this will obviously reduce overall performance." + * + * These requirements, although they make equally sense, are + * often not implemented by network functions. Some firmwares + * will queue data indefinitely, without ever resending a + * notification. The result is that the driver and firmware + * loses "syncronization" if the driver ever fails to respond + * to a single notification, something which easily can happen + * on release(). When this happens, the driver will appear to + * never receive notifications for the most current data. Each + * notification will only cause a single read, which returns + * the oldest data in the firmware's queue. + * + * The "drain_on_open" hack resolves the situation by draining + * data from the firmware until none is returned, without a + * prior notification. + * + * This will inevitably race with the firmware, risking that + * we read data from the device before handling the associated + * notification. To make things worse, some of the devices + * needing the hack do not implement the "return zero if no + * data is available" requirement either. Instead they return + * an error on the subsequent read in this case. This means + * that "winning" the race can cause an unexpected EIO to + * userspace. + * + * "winning" the race is more likely on resume() than on + * open(), and the unexpected error is more harmful in the + * middle of an open session. The hack is therefore only + * applied on open(), and not on resume() where it logically + * would be equally necessary. So we define open() as the only + * driver <-> device "syncronization point". Should we happen + * to lose a notification after open(), then syncronization + * will be lost until release() + * + * The hack should not be enabled for CDC WDM devices + * conforming to the CDC-WMC r1.1 specification. This is + * ensured by setting drain_on_open to false in wdm_probe(). + */ + if (drain_on_open) + set_bit(WDM_DRAIN_ON_OPEN, &desc->flags); + spin_lock(&wdm_device_list_lock); list_add(&desc->device_list, &wdm_device_list); spin_unlock(&wdm_device_list_lock); @@ -893,7 +988,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) goto err; ep = &iface->endpoint[0].desc; - rv = wdm_create(intf, ep, maxcom, &wdm_manage_power); + rv = wdm_create(intf, ep, maxcom, &wdm_manage_power, false); err: return rv; @@ -925,7 +1020,7 @@ struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf, { int rv = -EINVAL; - rv = wdm_create(intf, ep, bufsize, manage_power); + rv = wdm_create(intf, ep, bufsize, manage_power, true); if (rv < 0) goto err; From a094760b9a77f81ee3cbeff323ee77c928f41106 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 3 Aug 2016 21:46:47 +0200 Subject: [PATCH 025/343] usb: storage: fix runtime pm issue in usb_stor_probe2 Since commit 71723f95463d "PM / runtime: print error when activating a child to unactive parent" I see the following error message: scsi host2: usb-storage 1-3:1.0 scsi host2: runtime PM trying to activate child device host2 but parent (1-3:1.0) is not active Digging into it it seems to be related to the problem described in the commit message for cd998ded5c12 "i2c: designware: Prevent runtime suspend during adapter registration" as scsi_add_host also calls device_add and after the call to device_add the parent device is suspended. Fix this by using the approach from the mentioned commit and getting the runtime pm reference before calling scsi_add_host. Signed-off-by: Heiner Kallweit Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index ef2d8cde6ef7..8c5f0115166a 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1070,17 +1070,17 @@ int usb_stor_probe2(struct us_data *us) result = usb_stor_acquire_resources(us); if (result) goto BadDevice; + usb_autopm_get_interface_no_resume(us->pusb_intf); snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s", dev_name(&us->pusb_intf->dev)); result = scsi_add_host(us_to_host(us), dev); if (result) { dev_warn(dev, "Unable to add the scsi host\n"); - goto BadDevice; + goto HostAddErr; } /* Submit the delayed_work for SCSI-device scanning */ - usb_autopm_get_interface_no_resume(us->pusb_intf); set_bit(US_FLIDX_SCAN_PENDING, &us->dflags); if (delay_use > 0) @@ -1090,6 +1090,8 @@ int usb_stor_probe2(struct us_data *us) return 0; /* We come here if there are any problems */ +HostAddErr: + usb_autopm_put_interface_no_suspend(us->pusb_intf); BadDevice: usb_stor_dbg(us, "storage_probe() failed\n"); release_everything(us); From 3cc7e7b7872ebd0f200b5450f5471bc3700de141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 8 Jul 2016 14:02:50 +0200 Subject: [PATCH 026/343] USB: bcma: initialize Northstar USB 3.0 controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a rather simple controller, we just need to make sure USB is powered (using GPIO pin) and reset bus core. Once this is done it's safe to register XHCI controller and let it init PHY and do its magic. Signed-off-by: Rafał Miłecki Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 172ef17911aa..422fdc295b8d 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -338,6 +339,18 @@ err_unregister_ohci_dev: return err; } +static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd) +{ + struct bcma_device *core = bcma_hcd->core; + struct device *dev = &core->dev; + + bcma_core_enable(core, 0); + + of_platform_default_populate(dev->of_node, NULL, dev); + + return 0; +} + static int bcma_hcd_probe(struct bcma_device *core) { int err; @@ -362,6 +375,11 @@ static int bcma_hcd_probe(struct bcma_device *core) if (err) return err; break; + case BCMA_CORE_NS_USB30: + err = bcma_hcd_usb30_init(usb_dev); + if (err) + return err; + break; default: return -ENODEV; } @@ -416,6 +434,7 @@ static int bcma_hcd_resume(struct bcma_device *dev) static const struct bcma_device_id bcma_hcd_table[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS), {}, }; MODULE_DEVICE_TABLE(bcma, bcma_hcd_table); From 1ebe88d38ddec6b05f7b5e64acef30a98a4ad17e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sat, 25 Jun 2016 22:38:21 -0700 Subject: [PATCH 027/343] usb: ulpi: Automatically set driver::owner with ulpi_driver_register() Let's follow other driver registration functions and automatically set the driver's owner member to THIS_MODULE when ulpi_driver_register() is called. This allows ulpi driver writers to forget about this boiler plate detail and avoids common bugs in the process. Signed-off-by: Stephen Boyd Acked-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/common/ulpi.c | 5 +++-- include/linux/ulpi/driver.h | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 01c0c0477a9e..e04a34e7a341 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -127,16 +127,17 @@ static struct device_type ulpi_dev_type = { * * Registers a driver with the ULPI bus. */ -int ulpi_register_driver(struct ulpi_driver *drv) +int __ulpi_register_driver(struct ulpi_driver *drv, struct module *module) { if (!drv->probe) return -EINVAL; + drv->driver.owner = module; drv->driver.bus = &ulpi_bus; return driver_register(&drv->driver); } -EXPORT_SYMBOL_GPL(ulpi_register_driver); +EXPORT_SYMBOL_GPL(__ulpi_register_driver); /** * ulpi_unregister_driver - unregister a driver with the ULPI bus diff --git a/include/linux/ulpi/driver.h b/include/linux/ulpi/driver.h index 388f6e08b9d4..80b36ca12e80 100644 --- a/include/linux/ulpi/driver.h +++ b/include/linux/ulpi/driver.h @@ -47,7 +47,11 @@ struct ulpi_driver { #define to_ulpi_driver(d) container_of(d, struct ulpi_driver, driver) -int ulpi_register_driver(struct ulpi_driver *drv); +/* + * use a macro to avoid include chaining to get THIS_MODULE + */ +#define ulpi_register_driver(drv) __ulpi_register_driver(drv, THIS_MODULE) +int __ulpi_register_driver(struct ulpi_driver *drv, struct module *module); void ulpi_unregister_driver(struct ulpi_driver *drv); #define module_ulpi_driver(__ulpi_driver) \ From a26a142275c690d122edfba79120412cd7dbe38e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Jul 2016 17:23:18 +0900 Subject: [PATCH 028/343] usb: remove redundant dependency on USB_SUPPORT The whole Kconfig entries of the USB subsystem are surrounded with "if USB_SUPPORT" ... "endif", so CONFIG_USB_SUPPORT=y is surely met when these two Kconfig options are visible. Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/Kconfig | 1 - drivers/usb/dwc3/Kconfig | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index dd280108758f..253aac74cce1 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -85,7 +85,6 @@ config USB_OTG_FSM config USB_ULPI_BUS tristate "USB ULPI PHY interface support" - depends on USB_SUPPORT help UTMI+ Low Pin Interface (ULPI) is specification for a commonly used USB 2.0 PHY interface. The ULPI specification defines a standard set diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index a64ce1c94d6d..b97cde76914d 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,7 +1,7 @@ config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB || USB_GADGET) && HAS_DMA - select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD + select USB_XHCI_PLATFORM if USB_XHCI_HCD help Say Y or M here if your system has a Dual Role SuperSpeed USB controller based on the DesignWare USB3 IP Core. From 0573f2c519e570d056989e57565e1ff1640dd794 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 15 Jun 2016 11:25:43 +0800 Subject: [PATCH 029/343] usb: core: of.c: fix defined but not declare warning The helper usb_of_get_child_node is defined at of.c, but missing its declare as a global function. Fix it by adding related header file as well as compile it on conditional of CONFIG_OF. Cc: Greg Kroah-Hartman Cc: Arnd Bergmann Cc: Alan Stern Cc: linux-usb@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Ben Dooks Cc: linux-kernel@lists.codethink.co.uk Signed-off-by: Peter Chen Reported-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/Makefile | 3 ++- drivers/usb/core/of.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 9780877010b4..da36b784a0ef 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -5,8 +5,9 @@ usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o -usbcore-y += port.o of.o +usbcore-y += port.o +usbcore-$(CONFIG_OF) += of.o usbcore-$(CONFIG_PCI) += hcd-pci.o usbcore-$(CONFIG_ACPI) += usb-acpi.o diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c index 2289700c31d6..3de4f8873984 100644 --- a/drivers/usb/core/of.c +++ b/drivers/usb/core/of.c @@ -18,6 +18,7 @@ */ #include +#include /** * usb_of_get_child_node - Find the device node match port number From 0775a9cbc694e8c7276688be3bbd2f386167ab54 Mon Sep 17 00:00:00 2001 From: Nobuo Iwata Date: Mon, 13 Jun 2016 11:33:40 +0900 Subject: [PATCH 030/343] usbip: vhci extension: modifications to vhci driver Modification to Kconfig, vhci_hc.c, vhci.h and vhci_sysfs.c. 1. kernel config Followings are added. USBIP_VHCI_HC_PORTS: Number of ports per USB/IP virtual host controller. The default is 8 - same as current VHCI_NPORTS. USBIP_VHCI_NR_HCS: Number of USB/IP virtual host controllers. The default is 1. This paratmeter is replaced with USBIP_VHCI_INIT_HCS and USBIP_VHCI_MAX_HCS included in succeeding dynamic extension patch. 2. the_controller to controllers the_controller is changed to vhci_pdevs: array of struct platform_device. 3. vhci_sysfs.c Sysfs structure is changed as following. BEFORE: /sys/devices/platform +-- vhci +-- status +-- attach +-- detach +-- usbip_debug AFTER: example for CONFIG_USBIP_NR_HCS=4 /sys/devices/platform +-- vhci | +-- nports | +-- status | +-- status.1 | +-- status.2 | +-- status.3 | +-- attach | +-- detach | +-- usbip_debug +-- vhci.1 +-- vhci.2 +-- vhci.3 vhci[.N] is shown for each host controller kobj. vhch.1, vhci.2, ... are shown only when CONFIG_USBIP_NR_HCS is more than 1. Only 'vhci' (without number) has user space interfaces. 'nports' is newly added to give ports-per-controller and number of controlles. Before that, number of ports is acquired by reading status lines. Status is divided for each controller to avoid page size (4KB) limitation. Old userspace tool binaries work with the first status within the first controller. Inconsistency between status header and content is fixed. 4th and 5th column are header: "dev bus" content(unused): "000 000" content(used): "%08x", devid Only 1st and 2nd column are used by program. In old version, sscanf() in parse_status expect no bus column. And bus_id string is shown in the last column. Then bus in the header is removed and unused content is replaced with 8 zeros. The sscanf() expects more than 5 columns and new has 6 columns so there's no compatibility issue in this change. Signed-off-by: Nobuo Iwata Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/Kconfig | 21 +++ drivers/usb/usbip/vhci.h | 54 ++++-- drivers/usb/usbip/vhci_hcd.c | 285 ++++++++++++++++++++----------- drivers/usb/usbip/vhci_rx.c | 21 +-- drivers/usb/usbip/vhci_sysfs.c | 296 +++++++++++++++++++++++++-------- 5 files changed, 497 insertions(+), 180 deletions(-) diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index 17646b25343f..29492c70e0e6 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -24,6 +24,27 @@ config USBIP_VHCI_HCD To compile this driver as a module, choose M here: the module will be called vhci-hcd. +config USBIP_VHCI_HC_PORTS + int "Number of ports per USB/IP virtual host controller" + range 1 31 + default 8 + depends on USBIP_VHCI_HCD + ---help--- + To increase number of ports available for USB/IP virtual + host controller driver, this defines number of ports per + USB/IP virtual host controller. + +config USBIP_VHCI_NR_HCS + int "Number of USB/IP virtual host controllers" + range 1 128 + default 1 + depends on USBIP_VHCI_HCD + ---help--- + To increase number of ports available for USB/IP virtual + host controller driver, this defines number of USB/IP + virtual host controllers as if adding physical host + controllers. + config USBIP_HOST tristate "Host driver" depends on USBIP_CORE && USB diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h index a863a98a91ce..88b71c4e068f 100644 --- a/drivers/usb/usbip/vhci.h +++ b/drivers/usb/usbip/vhci.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2003-2008 Takahiro Hirofuchi + * Copyright (C) 2015 Nobuo Iwata * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,13 +73,25 @@ struct vhci_unlink { }; /* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */ -#define VHCI_NPORTS 8 +#ifdef CONFIG_USBIP_VHCI_HC_PORTS +#define VHCI_HC_PORTS CONFIG_USBIP_VHCI_HC_PORTS +#else +#define VHCI_HC_PORTS 8 +#endif + +#ifdef CONFIG_USBIP_VHCI_NR_HCS +#define VHCI_NR_HCS CONFIG_USBIP_VHCI_NR_HCS +#else +#define VHCI_NR_HCS 1 +#endif + +#define MAX_STATUS_NAME 16 /* for usb_bus.hcpriv */ struct vhci_hcd { spinlock_t lock; - u32 port_status[VHCI_NPORTS]; + u32 port_status[VHCI_HC_PORTS]; unsigned resuming:1; unsigned long re_timeout; @@ -90,14 +103,19 @@ struct vhci_hcd { * wIndex shows the port number and begins from 1. * But, the index of this array begins from 0. */ - struct vhci_device vdev[VHCI_NPORTS]; + struct vhci_device vdev[VHCI_HC_PORTS]; }; -extern struct vhci_hcd *the_controller; -extern const struct attribute_group dev_attr_group; +extern int vhci_num_controllers; +extern struct platform_device **vhci_pdevs; +extern struct attribute_group vhci_attr_group; /* vhci_hcd.c */ -void rh_port_connect(int rhport, enum usb_device_speed speed); +void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed); + +/* vhci_sysfs.c */ +int vhci_init_attr_group(void); +void vhci_finish_attr_group(void); /* vhci_rx.c */ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum); @@ -106,9 +124,14 @@ int vhci_rx_loop(void *data); /* vhci_tx.c */ int vhci_tx_loop(void *data); -static inline struct vhci_device *port_to_vdev(__u32 port) +static inline __u32 port_to_rhport(__u32 port) { - return &the_controller->vdev[port]; + return port % VHCI_HC_PORTS; +} + +static inline int port_to_pdev_nr(__u32 port) +{ + return port / VHCI_HC_PORTS; } static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd) @@ -116,14 +139,25 @@ static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd) return (struct vhci_hcd *) (hcd->hcd_priv); } +static inline struct device *hcd_dev(struct usb_hcd *hcd) +{ + return (hcd)->self.controller; +} + +static inline const char *hcd_name(struct usb_hcd *hcd) +{ + return (hcd)->self.bus_name; +} + static inline struct usb_hcd *vhci_to_hcd(struct vhci_hcd *vhci) { return container_of((void *) vhci, struct usb_hcd, hcd_priv); } -static inline struct device *vhci_dev(struct vhci_hcd *vhci) +static inline struct vhci_hcd *vdev_to_vhci(struct vhci_device *vdev) { - return vhci_to_hcd(vhci)->self.controller; + return container_of( + (void *)(vdev - vdev->rhport), struct vhci_hcd, vdev); } #endif /* __USBIP_VHCI_H */ diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 2e0450bec1b1..96f2dacb27fa 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003-2008 Takahiro Hirofuchi + * Copyright (C) 2015-2016 Nobuo Iwata * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,7 +57,9 @@ static int vhci_get_frame_number(struct usb_hcd *hcd); static const char driver_name[] = "vhci_hcd"; static const char driver_desc[] = "USB/IP Virtual Host Controller"; -struct vhci_hcd *the_controller; +int vhci_num_controllers = VHCI_NR_HCS; + +struct platform_device **vhci_pdevs; static const char * const bit_desc[] = { "CONNECTION", /*0*/ @@ -119,47 +122,59 @@ static void dump_port_status_diff(u32 prev_status, u32 new_status) pr_debug("\n"); } -void rh_port_connect(int rhport, enum usb_device_speed speed) +void rh_port_connect(struct vhci_device *vdev, enum usb_device_speed speed) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); + int rhport = vdev->rhport; + u32 status; unsigned long flags; usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); - the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION - | (1 << USB_PORT_FEAT_C_CONNECTION); + status = vhci->port_status[rhport]; + + status |= USB_PORT_STAT_CONNECTION | (1 << USB_PORT_FEAT_C_CONNECTION); switch (speed) { case USB_SPEED_HIGH: - the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED; + status |= USB_PORT_STAT_HIGH_SPEED; break; case USB_SPEED_LOW: - the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED; + status |= USB_PORT_STAT_LOW_SPEED; break; default: break; } - spin_unlock_irqrestore(&the_controller->lock, flags); + vhci->port_status[rhport] = status; - usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); + spin_unlock_irqrestore(&vhci->lock, flags); + + usb_hcd_poll_rh_status(vhci_to_hcd(vhci)); } -static void rh_port_disconnect(int rhport) +static void rh_port_disconnect(struct vhci_device *vdev) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); + int rhport = vdev->rhport; + u32 status; unsigned long flags; usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); - the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION; - the_controller->port_status[rhport] |= - (1 << USB_PORT_FEAT_C_CONNECTION); + status = vhci->port_status[rhport]; - spin_unlock_irqrestore(&the_controller->lock, flags); - usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); + status &= ~USB_PORT_STAT_CONNECTION; + status |= (1 << USB_PORT_FEAT_C_CONNECTION); + + vhci->port_status[rhport] = status; + + spin_unlock_irqrestore(&vhci->lock, flags); + usb_hcd_poll_rh_status(vhci_to_hcd(vhci)); } #define PORT_C_MASK \ @@ -188,7 +203,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf) int changed = 0; unsigned long flags; - retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8); + retval = DIV_ROUND_UP(VHCI_HC_PORTS + 1, 8); memset(buf, 0, retval); vhci = hcd_to_vhci(hcd); @@ -200,7 +215,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf) } /* check pseudo status register for each port */ - for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { if ((vhci->port_status[rhport] & PORT_C_MASK)) { /* The status of a port has been changed, */ usbip_dbg_vhci_rh("port %d status changed\n", rhport); @@ -225,7 +240,7 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc) desc->bDescLength = 9; desc->wHubCharacteristics = cpu_to_le16( HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM); - desc->bNbrPorts = VHCI_NPORTS; + desc->bNbrPorts = VHCI_HC_PORTS; desc->u.hs.DeviceRemovable[0] = 0xff; desc->u.hs.DeviceRemovable[1] = 0xff; } @@ -238,7 +253,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, int rhport; unsigned long flags; - u32 prev_port_status[VHCI_NPORTS]; + u32 prev_port_status[VHCI_HC_PORTS]; if (!HCD_HW_ACCESSIBLE(hcd)) return -ETIMEDOUT; @@ -249,7 +264,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, */ usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue, wIndex); - if (wIndex > VHCI_NPORTS) + if (wIndex > VHCI_HC_PORTS) pr_err("invalid port number %d\n", wIndex); rhport = ((__u8)(wIndex & 0x00ff)) - 1; @@ -315,7 +330,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, break; case GetPortStatus: usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex); - if (wIndex > VHCI_NPORTS || wIndex < 1) { + if (wIndex > VHCI_HC_PORTS || wIndex < 1) { pr_err("invalid port number %d\n", wIndex); retval = -EPIPE; } @@ -416,14 +431,27 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, static struct vhci_device *get_vdev(struct usb_device *udev) { - int i; + struct platform_device *pdev; + struct usb_hcd *hcd; + struct vhci_hcd *vhci; + int pdev_nr, rhport; if (!udev) return NULL; - for (i = 0; i < VHCI_NPORTS; i++) - if (the_controller->vdev[i].udev == udev) - return port_to_vdev(i); + for (pdev_nr = 0; pdev_nr < vhci_num_controllers; pdev_nr++) { + pdev = *(vhci_pdevs + pdev_nr); + if (pdev == NULL) + continue; + hcd = platform_get_drvdata(pdev); + if (hcd == NULL) + continue; + vhci = hcd_to_vhci(hcd); + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { + if (vhci->vdev[rhport].udev == udev) + return &vhci->vdev[rhport]; + } + } return NULL; } @@ -432,6 +460,7 @@ static void vhci_tx_urb(struct urb *urb) { struct vhci_device *vdev = get_vdev(urb->dev); struct vhci_priv *priv; + struct vhci_hcd *vhci = vdev_to_vhci(vdev); unsigned long flags; if (!vdev) { @@ -447,7 +476,7 @@ static void vhci_tx_urb(struct urb *urb) spin_lock_irqsave(&vdev->priv_lock, flags); - priv->seqnum = atomic_inc_return(&the_controller->seqnum); + priv->seqnum = atomic_inc_return(&vhci->seqnum); if (priv->seqnum == 0xffff) dev_info(&urb->dev->dev, "seqnum max\n"); @@ -465,7 +494,9 @@ static void vhci_tx_urb(struct urb *urb) static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) { + struct vhci_hcd *vhci = hcd_to_vhci(hcd); struct device *dev = &urb->dev->dev; + u8 portnum = urb->dev->portnum; int ret = 0; struct vhci_device *vdev; unsigned long flags; @@ -473,26 +504,30 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n", hcd, urb, mem_flags); + if (portnum > VHCI_HC_PORTS) { + pr_err("invalid port number %d\n", portnum); + return -ENODEV; + } + vdev = &vhci->vdev[portnum-1]; + /* patch to usb_sg_init() is in 2.5.60 */ BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); if (urb->status != -EINPROGRESS) { dev_err(dev, "URB already unlinked!, status %d\n", urb->status); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return urb->status; } - vdev = port_to_vdev(urb->dev->portnum-1); - /* refuse enqueue for dead connection */ spin_lock(&vdev->ud.lock); if (vdev->ud.status == VDEV_ST_NULL || vdev->ud.status == VDEV_ST_ERROR) { dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport); spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return -ENODEV; } spin_unlock(&vdev->ud.lock); @@ -565,17 +600,16 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, out: vhci_tx_urb(urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return 0; no_need_xmit: usb_hcd_unlink_urb_from_ep(hcd, urb); no_need_unlink: - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); if (!ret) - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), - urb, urb->status); + usb_hcd_giveback_urb(hcd, urb, urb->status); return ret; } @@ -627,19 +661,20 @@ no_need_unlink: */ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { + struct vhci_hcd *vhci = hcd_to_vhci(hcd); struct vhci_priv *priv; struct vhci_device *vdev; unsigned long flags; pr_info("dequeue a urb %p\n", urb); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); priv = urb->hcpriv; if (!priv) { /* URB was never linked! or will be soon given back by * vhci_rx. */ - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return -EIDRM; } @@ -648,7 +683,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret) { - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return ret; } } @@ -676,10 +711,9 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock_irqrestore(&the_controller->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, - urb->status); - spin_lock_irqsave(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); + usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status); + spin_lock_irqsave(&vhci->lock, flags); } else { /* tcp connection is alive */ @@ -691,12 +725,12 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC); if (!unlink) { spin_unlock(&vdev->priv_lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); return -ENOMEM; } - unlink->seqnum = atomic_inc_return(&the_controller->seqnum); + unlink->seqnum = atomic_inc_return(&vhci->seqnum); if (unlink->seqnum == 0xffff) pr_info("seqnum max\n"); @@ -712,7 +746,7 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) spin_unlock(&vdev->priv_lock); } - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); usbip_dbg_vhci_hc("leave\n"); return 0; @@ -720,10 +754,12 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) static void vhci_device_unlink_cleanup(struct vhci_device *vdev) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); + struct usb_hcd *hcd = vhci_to_hcd(vhci); struct vhci_unlink *unlink, *tmp; unsigned long flags; - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); spin_lock(&vdev->priv_lock); list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { @@ -752,24 +788,23 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) urb->status = -ENODEV; - usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); + usb_hcd_unlink_urb_from_ep(hcd, urb); list_del(&unlink->list); spin_unlock(&vdev->priv_lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, - urb->status); + usb_hcd_giveback_urb(hcd, urb, urb->status); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); spin_lock(&vdev->priv_lock); kfree(unlink); } spin_unlock(&vdev->priv_lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); } /* @@ -827,7 +862,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud) * is actually given back by vhci_rx after receiving its return pdu. * */ - rh_port_disconnect(vdev->rhport); + rh_port_disconnect(vdev); pr_info("disconnect device\n"); } @@ -866,7 +901,7 @@ static void vhci_device_unusable(struct usbip_device *ud) static void vhci_device_init(struct vhci_device *vdev) { - memset(vdev, 0, sizeof(*vdev)); + memset(vdev, 0, sizeof(struct vhci_device)); vdev->ud.side = USBIP_VHCI; vdev->ud.status = VDEV_ST_NULL; @@ -887,17 +922,34 @@ static void vhci_device_init(struct vhci_device *vdev) usbip_start_eh(&vdev->ud); } +static int hcd_name_to_id(const char *name) +{ + char *c; + long val; + int ret; + + c = strchr(name, '.'); + if (c == NULL) + return 0; + + ret = kstrtol(c+1, 10, &val); + if (ret < 0) + return ret; + + return val; +} + static int vhci_start(struct usb_hcd *hcd) { struct vhci_hcd *vhci = hcd_to_vhci(hcd); - int rhport; + int id, rhport; int err = 0; usbip_dbg_vhci_hc("enter vhci_start\n"); /* initialize private data of usb_hcd */ - for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { struct vhci_device *vdev = &vhci->vdev[rhport]; vhci_device_init(vdev); @@ -910,11 +962,26 @@ static int vhci_start(struct usb_hcd *hcd) hcd->power_budget = 0; /* no limit */ hcd->uses_new_polling = 1; + id = hcd_name_to_id(hcd_name(hcd)); + if (id < 0) { + pr_err("invalid vhci name %s\n", hcd_name(hcd)); + return -EINVAL; + } + /* vhci_hcd is now ready to be controlled through sysfs */ - err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group); - if (err) { - pr_err("create sysfs files\n"); - return err; + if (id == 0) { + err = vhci_init_attr_group(); + if (err) { + pr_err("init attr group\n"); + return err; + } + err = sysfs_create_group(&hcd_dev(hcd)->kobj, &vhci_attr_group); + if (err) { + pr_err("create sysfs files\n"); + vhci_finish_attr_group(); + return err; + } + pr_info("created sysfs %s\n", hcd_name(hcd)); } return 0; @@ -923,15 +990,19 @@ static int vhci_start(struct usb_hcd *hcd) static void vhci_stop(struct usb_hcd *hcd) { struct vhci_hcd *vhci = hcd_to_vhci(hcd); - int rhport = 0; + int id, rhport; usbip_dbg_vhci_hc("stop VHCI controller\n"); /* 1. remove the userland interface of vhci_hcd */ - sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group); + id = hcd_name_to_id(hcd_name(hcd)); + if (id == 0) { + sysfs_remove_group(&hcd_dev(hcd)->kobj, &vhci_attr_group); + vhci_finish_attr_group(); + } /* 2. shutdown all the ports of vhci_hcd */ - for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) { struct vhci_device *vdev = &vhci->vdev[rhport]; usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED); @@ -1025,9 +1096,6 @@ static int vhci_hcd_probe(struct platform_device *pdev) } hcd->has_tt = 1; - /* this is private data for vhci_hcd */ - the_controller = hcd_to_vhci(hcd); - /* * Finish generic HCD structure initialization and register. * Call the driver's reset() and start() routines. @@ -1036,7 +1104,6 @@ static int vhci_hcd_probe(struct platform_device *pdev) if (ret != 0) { pr_err("usb_add_hcd failed %d\n", ret); usb_put_hcd(hcd); - the_controller = NULL; return ret; } @@ -1059,7 +1126,6 @@ static int vhci_hcd_remove(struct platform_device *pdev) */ usb_remove_hcd(hcd); usb_put_hcd(hcd); - the_controller = NULL; return 0; } @@ -1070,21 +1136,24 @@ static int vhci_hcd_remove(struct platform_device *pdev) static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state) { struct usb_hcd *hcd; - int rhport = 0; + struct vhci_hcd *vhci; + int rhport; int connected = 0; int ret = 0; unsigned long flags; hcd = platform_get_drvdata(pdev); + if (!hcd) + return 0; + vhci = hcd_to_vhci(hcd); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); - for (rhport = 0; rhport < VHCI_NPORTS; rhport++) - if (the_controller->port_status[rhport] & - USB_PORT_STAT_CONNECTION) + for (rhport = 0; rhport < VHCI_HC_PORTS; rhport++) + if (vhci->port_status[rhport] & USB_PORT_STAT_CONNECTION) connected += 1; - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); if (connected > 0) { dev_info(&pdev->dev, @@ -1106,6 +1175,8 @@ static int vhci_hcd_resume(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s\n", __func__); hcd = platform_get_drvdata(pdev); + if (!hcd) + return 0; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); usb_hcd_poll_rh_status(hcd); @@ -1129,52 +1200,78 @@ static struct platform_driver vhci_driver = { }, }; -/* - * The VHCI 'device' is 'virtual'; not a real plug&play hardware. - * We need to add this virtual device as a platform device arbitrarily: - * 1. platform_device_register() - */ -static void the_pdev_release(struct device *dev) +static int add_platform_device(int id) { + struct platform_device *pdev; + int dev_nr; + + if (id == 0) + dev_nr = -1; + else + dev_nr = id; + + pdev = platform_device_register_simple(driver_name, dev_nr, NULL, 0); + if (pdev == NULL) + return -ENODEV; + + *(vhci_pdevs + id) = pdev; + return 0; } -static struct platform_device the_pdev = { - /* should be the same name as driver_name */ - .name = driver_name, - .id = -1, - .dev = { - .release = the_pdev_release, - }, -}; +static void del_platform_devices(void) +{ + struct platform_device *pdev; + int i; + + for (i = 0; i < vhci_num_controllers; i++) { + pdev = *(vhci_pdevs + i); + if (pdev != NULL) + platform_device_unregister(pdev); + *(vhci_pdevs + i) = NULL; + } + sysfs_remove_link(&platform_bus.kobj, driver_name); +} static int __init vhci_hcd_init(void) { - int ret; + int i, ret; if (usb_disabled()) return -ENODEV; + if (vhci_num_controllers < 1) + vhci_num_controllers = 1; + + vhci_pdevs = kcalloc(vhci_num_controllers, sizeof(void *), GFP_KERNEL); + if (vhci_pdevs == NULL) + return -ENOMEM; + ret = platform_driver_register(&vhci_driver); if (ret) goto err_driver_register; - ret = platform_device_register(&the_pdev); - if (ret) - goto err_platform_device_register; + for (i = 0; i < vhci_num_controllers; i++) { + ret = add_platform_device(i); + if (ret) + goto err_platform_device_register; + } pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); return ret; err_platform_device_register: + del_platform_devices(); platform_driver_unregister(&vhci_driver); err_driver_register: + kfree(vhci_pdevs); return ret; } static void __exit vhci_hcd_exit(void) { - platform_device_unregister(&the_pdev); + del_platform_devices(); platform_driver_unregister(&vhci_driver); + kfree(vhci_pdevs); } module_init(vhci_hcd_init); diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c index d656e0edc3d5..fc2d319e2360 100644 --- a/drivers/usb/usbip/vhci_rx.c +++ b/drivers/usb/usbip/vhci_rx.c @@ -70,6 +70,7 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum) static void vhci_recv_ret_submit(struct vhci_device *vdev, struct usbip_header *pdu) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); struct usbip_device *ud = &vdev->ud; struct urb *urb; unsigned long flags; @@ -81,7 +82,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, if (!urb) { pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum); pr_info("max seqnum %d\n", - atomic_read(&the_controller->seqnum)); + atomic_read(&vhci->seqnum)); usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); return; } @@ -105,11 +106,11 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, usbip_dbg_vhci_rx("now giveback urb %p\n", urb); - spin_lock_irqsave(&the_controller->lock, flags); - usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); + usb_hcd_unlink_urb_from_ep(vhci_to_hcd(vhci), urb); + spin_unlock_irqrestore(&vhci->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); + usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status); usbip_dbg_vhci_rx("Leave\n"); } @@ -142,6 +143,7 @@ static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev, static void vhci_recv_ret_unlink(struct vhci_device *vdev, struct usbip_header *pdu) { + struct vhci_hcd *vhci = vdev_to_vhci(vdev); struct vhci_unlink *unlink; struct urb *urb; unsigned long flags; @@ -174,12 +176,11 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, urb->status = pdu->u.ret_unlink.status; pr_info("urb->status %d\n", urb->status); - spin_lock_irqsave(&the_controller->lock, flags); - usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_lock_irqsave(&vhci->lock, flags); + usb_hcd_unlink_urb_from_ep(vhci_to_hcd(vhci), urb); + spin_unlock_irqrestore(&vhci->lock, flags); - usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, - urb->status); + usb_hcd_giveback_urb(vhci_to_hcd(vhci), urb, urb->status); } kfree(unlink); diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 5b5462eb1665..c404017c1b5a 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003-2008 Takahiro Hirofuchi + * Copyright (C) 2015-2016 Nobuo Iwata * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +21,8 @@ #include #include #include +#include +#include #include "usbip_common.h" #include "vhci.h" @@ -27,106 +30,190 @@ /* TODO: refine locking ?*/ /* Sysfs entry to show port status */ -static ssize_t status_show(struct device *dev, struct device_attribute *attr, - char *out) +static ssize_t status_show_vhci(int pdev_nr, char *out) { + struct platform_device *pdev = *(vhci_pdevs + pdev_nr); + struct vhci_hcd *vhci; char *s = out; int i = 0; unsigned long flags; - BUG_ON(!the_controller || !out); + if (!pdev || !out) { + usbip_dbg_vhci_sysfs("show status error\n"); + return 0; + } - spin_lock_irqsave(&the_controller->lock, flags); + vhci = hcd_to_vhci(platform_get_drvdata(pdev)); + + spin_lock_irqsave(&vhci->lock, flags); /* * output example: - * prt sta spd dev socket local_busid - * 000 004 000 000 c5a7bb80 1-2.3 - * 001 004 000 000 d8cee980 2-3.4 + * port sta spd dev socket local_busid + * 0000 004 000 00000000 c5a7bb80 1-2.3 + * 0001 004 000 00000000 d8cee980 2-3.4 * * IP address can be retrieved from a socket pointer address by looking * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a * port number and its peer IP address. */ - out += sprintf(out, - "prt sta spd bus dev socket local_busid\n"); - - for (i = 0; i < VHCI_NPORTS; i++) { - struct vhci_device *vdev = port_to_vdev(i); + for (i = 0; i < VHCI_HC_PORTS; i++) { + struct vhci_device *vdev = &vhci->vdev[i]; spin_lock(&vdev->ud.lock); - out += sprintf(out, "%03u %03u ", i, vdev->ud.status); + out += sprintf(out, "%04u %03u ", + (pdev_nr * VHCI_HC_PORTS) + i, + vdev->ud.status); if (vdev->ud.status == VDEV_ST_USED) { out += sprintf(out, "%03u %08x ", - vdev->speed, vdev->devid); - out += sprintf(out, "%16p ", vdev->ud.tcp_socket); - out += sprintf(out, "%s", dev_name(&vdev->udev->dev)); + vdev->speed, vdev->devid); + out += sprintf(out, "%16p %s", + vdev->ud.tcp_socket, + dev_name(&vdev->udev->dev)); } else { - out += sprintf(out, "000 000 000 0000000000000000 0-0"); + out += sprintf(out, "000 00000000 "); + out += sprintf(out, "0000000000000000 0-0"); } out += sprintf(out, "\n"); spin_unlock(&vdev->ud.lock); } - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return out - s; } -static DEVICE_ATTR_RO(status); + +static ssize_t status_show_not_ready(int pdev_nr, char *out) +{ + char *s = out; + int i = 0; + + for (i = 0; i < VHCI_HC_PORTS; i++) { + out += sprintf(out, "%04u %03u ", + (pdev_nr * VHCI_HC_PORTS) + i, + VDEV_ST_NOTASSIGNED); + out += sprintf(out, "000 00000000 0000000000000000 0-0"); + out += sprintf(out, "\n"); + } + return out - s; +} + +static int status_name_to_id(const char *name) +{ + char *c; + long val; + int ret; + + c = strchr(name, '.'); + if (c == NULL) + return 0; + + ret = kstrtol(c+1, 10, &val); + if (ret < 0) + return ret; + + return val; +} + +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, char *out) +{ + char *s = out; + int pdev_nr; + + out += sprintf(out, + "port sta spd dev socket local_busid\n"); + + pdev_nr = status_name_to_id(attr->attr.name); + if (pdev_nr < 0) + out += status_show_not_ready(pdev_nr, out); + else + out += status_show_vhci(pdev_nr, out); + + return out - s; +} + +static ssize_t nports_show(struct device *dev, struct device_attribute *attr, + char *out) +{ + char *s = out; + + out += sprintf(out, "%d\n", VHCI_HC_PORTS * vhci_num_controllers); + return out - s; +} +static DEVICE_ATTR_RO(nports); /* Sysfs entry to shutdown a virtual connection */ -static int vhci_port_disconnect(__u32 rhport) +static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport) { - struct vhci_device *vdev; + struct vhci_device *vdev = &vhci->vdev[rhport]; unsigned long flags; usbip_dbg_vhci_sysfs("enter\n"); /* lock */ - spin_lock_irqsave(&the_controller->lock, flags); - - vdev = port_to_vdev(rhport); - + spin_lock_irqsave(&vhci->lock, flags); spin_lock(&vdev->ud.lock); + if (vdev->ud.status == VDEV_ST_NULL) { pr_err("not connected %d\n", vdev->ud.status); /* unlock */ spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); return -EINVAL; } /* unlock */ spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN); return 0; } +static int valid_port(__u32 pdev_nr, __u32 rhport) +{ + if (pdev_nr >= vhci_num_controllers) { + pr_err("pdev %u\n", pdev_nr); + return 0; + } + if (rhport >= VHCI_HC_PORTS) { + pr_err("rhport %u\n", rhport); + return 0; + } + return 1; +} + static ssize_t store_detach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int err; - __u32 rhport = 0; + __u32 port = 0, pdev_nr = 0, rhport = 0; + struct usb_hcd *hcd; + int ret; - if (sscanf(buf, "%u", &rhport) != 1) + if (kstrtoint(buf, 10, &port) < 0) return -EINVAL; - /* check rhport */ - if (rhport >= VHCI_NPORTS) { - dev_err(dev, "invalid port %u\n", rhport); + pdev_nr = port_to_pdev_nr(port); + rhport = port_to_rhport(port); + + if (!valid_port(pdev_nr, rhport)) return -EINVAL; + + hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr)); + if (hcd == NULL) { + dev_err(dev, "port is not ready %u\n", port); + return -EAGAIN; } - err = vhci_port_disconnect(rhport); - if (err < 0) + ret = vhci_port_disconnect(hcd_to_vhci(hcd), rhport); + if (ret < 0) return -EINVAL; usbip_dbg_vhci_sysfs("Leave\n"); @@ -135,16 +222,12 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); -/* Sysfs entry to establish a virtual connection */ -static int valid_args(__u32 rhport, enum usb_device_speed speed) +static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed) { - /* check rhport */ - if (rhport >= VHCI_NPORTS) { - pr_err("port %u\n", rhport); - return -EINVAL; + if (!valid_port(pdev_nr, rhport)) { + return 0; } - /* check speed */ switch (speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: @@ -154,12 +237,13 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed) default: pr_err("Failed attach request for unsupported USB speed: %s\n", usb_speed_string(speed)); - return -EINVAL; + return 0; } - return 0; + return 1; } +/* Sysfs entry to establish a virtual connection */ /* * To start a new USB/IP attachment, a userland program needs to setup a TCP * connection and then write its socket descriptor with remote device @@ -174,10 +258,12 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed) static ssize_t store_attach(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct vhci_device *vdev; struct socket *socket; int sockfd = 0; - __u32 rhport = 0, devid = 0, speed = 0; + __u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0; + struct usb_hcd *hcd; + struct vhci_hcd *vhci; + struct vhci_device *vdev; int err; unsigned long flags; @@ -187,16 +273,28 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, * @devid: unique device identifier in a remote host * @speed: usb device speed in a remote host */ - if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4) + if (sscanf(buf, "%u %u %u %u", &port, &sockfd, &devid, &speed) != 4) return -EINVAL; + pdev_nr = port_to_pdev_nr(port); + rhport = port_to_rhport(port); - usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", - rhport, sockfd, devid, speed); + usbip_dbg_vhci_sysfs("port(%u) pdev(%d) rhport(%u)\n", + port, pdev_nr, rhport); + usbip_dbg_vhci_sysfs("sockfd(%u) devid(%u) speed(%u)\n", + sockfd, devid, speed); /* check received parameters */ - if (valid_args(rhport, speed) < 0) + if (!valid_args(pdev_nr, rhport, speed)) return -EINVAL; + hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr)); + if (hcd == NULL) { + dev_err(dev, "port %d is not ready\n", port); + return -EAGAIN; + } + vhci = hcd_to_vhci(hcd); + vdev = &vhci->vdev[rhport]; + /* Extract socket from fd. */ socket = sockfd_lookup(sockfd, &err); if (!socket) @@ -205,14 +303,13 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, /* now need lock until setting vdev status as used */ /* begin a lock */ - spin_lock_irqsave(&the_controller->lock, flags); - vdev = port_to_vdev(rhport); + spin_lock_irqsave(&vhci->lock, flags); spin_lock(&vdev->ud.lock); if (vdev->ud.status != VDEV_ST_NULL) { /* end of the lock */ spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); sockfd_put(socket); @@ -220,9 +317,10 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, return -EINVAL; } - dev_info(dev, - "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n", - rhport, sockfd, devid, speed, usb_speed_string(speed)); + dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n", + pdev_nr, rhport, sockfd); + dev_info(dev, "devid(%u) speed(%u) speed_str(%s)\n", + devid, speed, usb_speed_string(speed)); vdev->devid = devid; vdev->speed = speed; @@ -230,26 +328,92 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, vdev->ud.status = VDEV_ST_NOTASSIGNED; spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock_irqrestore(&vhci->lock, flags); /* end the lock */ vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); - rh_port_connect(rhport, speed); + rh_port_connect(vdev, speed); return count; } static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach); -static struct attribute *dev_attrs[] = { - &dev_attr_status.attr, - &dev_attr_detach.attr, - &dev_attr_attach.attr, - &dev_attr_usbip_debug.attr, - NULL, +#define MAX_STATUS_NAME 16 + +struct status_attr { + struct device_attribute attr; + char name[MAX_STATUS_NAME+1]; }; -const struct attribute_group dev_attr_group = { - .attrs = dev_attrs, +static struct status_attr *status_attrs; + +static void set_status_attr(int id) +{ + struct status_attr *status; + + status = status_attrs + id; + if (id == 0) + strcpy(status->name, "status"); + else + snprintf(status->name, MAX_STATUS_NAME+1, "status.%d", id); + status->attr.attr.name = status->name; + status->attr.attr.mode = S_IRUGO; + status->attr.show = status_show; +} + +static int init_status_attrs(void) +{ + int id; + + status_attrs = kcalloc(vhci_num_controllers, sizeof(struct status_attr), + GFP_KERNEL); + if (status_attrs == NULL) + return -ENOMEM; + + for (id = 0; id < vhci_num_controllers; id++) + set_status_attr(id); + + return 0; +} + +static void finish_status_attrs(void) +{ + kfree(status_attrs); +} + +struct attribute_group vhci_attr_group = { + .attrs = NULL, }; + +int vhci_init_attr_group(void) +{ + struct attribute **attrs; + int ret, i; + + attrs = kcalloc((vhci_num_controllers + 5), sizeof(struct attribute *), + GFP_KERNEL); + if (attrs == NULL) + return -ENOMEM; + + ret = init_status_attrs(); + if (ret) { + kfree(attrs); + return ret; + } + *attrs = &dev_attr_nports.attr; + *(attrs + 1) = &dev_attr_detach.attr; + *(attrs + 2) = &dev_attr_attach.attr; + *(attrs + 3) = &dev_attr_usbip_debug.attr; + for (i = 0; i < vhci_num_controllers; i++) + *(attrs + i + 4) = &((status_attrs + i)->attr.attr); + vhci_attr_group.attrs = attrs; + return 0; +} + +void vhci_finish_attr_group(void) +{ + finish_status_attrs(); + kfree(vhci_attr_group.attrs); +} From c1da59dad0ebd3f9bd238f3fff82b1f7ffda7829 Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Tue, 9 Aug 2016 10:54:52 -0400 Subject: [PATCH 031/343] cdc-wdm: Clear read pipeline in case of error Implemented queued response handling. This queue is processed every time the WDM_READ flag is cleared. In case of a read error, userspace may not actually read the data, since the driver returns an error through wdm_poll. After this, the underlying device may attempt to send us more data, but the queue is not processed. While userspace is also blocked, because the read error is never cleared. After this patch, we proactively process the queue on a read error. If there was an outstanding response to handle, that will clear the error (or go through the same logic again, if another read error occurs). If there was no outstanding response, this will bring the queue size back to 0, unblocking a future response from the underlying device. Signed-off-by: Robert Foss Tested-by: Robert Foss Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 39 +++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 4bfc48d18654..56d3ab86be7f 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -155,6 +155,9 @@ static void wdm_out_callback(struct urb *urb) wake_up(&desc->wait); } +/* forward declaration */ +static int service_outstanding_interrupt(struct wdm_device *desc); + static void wdm_in_callback(struct urb *urb) { struct wdm_device *desc = urb->context; @@ -189,7 +192,13 @@ static void wdm_in_callback(struct urb *urb) } } - desc->rerr = status; + /* + * only set a new error if there is no previous error. + * Errors are only cleared during read/open + */ + if (desc->rerr == 0) + desc->rerr = status; + if (length + desc->length > desc->wMaxCommand) { /* The buffer would overflow */ set_bit(WDM_OVERFLOW, &desc->flags); @@ -221,9 +230,19 @@ static void wdm_in_callback(struct urb *urb) } skip_error: + set_bit(WDM_READ, &desc->flags); wake_up(&desc->wait); - set_bit(WDM_READ, &desc->flags); + if (desc->rerr) { + /* + * Since there was an error, userspace may decide to not read + * any data after poll'ing. + * We should respond to further attempts from the device to send + * data, so that we can get unstuck. + */ + service_outstanding_interrupt(desc); + } + unlock: spin_unlock(&desc->iuspin); } @@ -457,17 +476,14 @@ out_free_mem: } /* - * clear WDM_READ flag and possibly submit the read urb if resp_count - * is non-zero. + * Submit the read urb if resp_count is non-zero. * * Called with desc->iuspin locked */ -static int clear_wdm_read_flag(struct wdm_device *desc) +static int service_outstanding_interrupt(struct wdm_device *desc) { int rv = 0; - clear_bit(WDM_READ, &desc->flags); - /* submit read urb only if the device is waiting for it */ if (!desc->resp_count || !--desc->resp_count) goto out; @@ -559,7 +575,8 @@ retry: if (!desc->reslength) { /* zero length read */ dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); - rv = clear_wdm_read_flag(desc); + clear_bit(WDM_READ, &desc->flags); + rv = service_outstanding_interrupt(desc); spin_unlock_irq(&desc->iuspin); if (rv < 0) goto err; @@ -584,8 +601,10 @@ retry: desc->length -= cntr; /* in case we had outstanding data */ - if (!desc->length) - clear_wdm_read_flag(desc); + if (!desc->length) { + clear_bit(WDM_READ, &desc->flags); + service_outstanding_interrupt(desc); + } spin_unlock_irq(&desc->iuspin); rv = cntr; From c6a4c9fcfd2a1a6d14e46180d19e565aa2fbf362 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:42 +0200 Subject: [PATCH 032/343] uwb: hwa-rc: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/uwb/hwa-rc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c index 0257f35cfb9d..0aa6c3c29d17 100644 --- a/drivers/uwb/hwa-rc.c +++ b/drivers/uwb/hwa-rc.c @@ -701,10 +701,8 @@ static int hwarc_neep_init(struct uwb_rc *rc) goto error_rd_buffer; } hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL); - if (hwarc->neep_urb == NULL) { - dev_err(dev, "Unable to allocate notification URB\n"); + if (hwarc->neep_urb == NULL) goto error_urb_alloc; - } usb_fill_int_urb(hwarc->neep_urb, usb_dev, usb_rcvintpipe(usb_dev, epd->bEndpointAddress), hwarc->rd_buffer, PAGE_SIZE, From 8ebbbf2e5dc01599dcbf520463e9688e74133ad3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:32 +0200 Subject: [PATCH 033/343] usb: atm: cxacru: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 0a866e90b49c..18b281d73a39 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -1168,13 +1168,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, } instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL); if (!instance->rcv_urb) { - usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_urb\n"); ret = -ENOMEM; goto fail; } instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL); if (!instance->snd_urb) { - usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_urb\n"); ret = -ENOMEM; goto fail; } From 7ff56857e352c0a2f1ecaf662dbe93e3434e9ada Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:33 +0200 Subject: [PATCH 034/343] usb: atm: ueagle-atm: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 4333dc576a12..f198291630d7 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2203,10 +2203,8 @@ static int uea_boot(struct uea_softc *sc) } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); - if (!sc->urb_int) { - uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); + if (!sc->urb_int) goto err1; - } usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), From 4675e961b8c457d6edc184f31ad1fd12bfbbe9ca Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:34 +0200 Subject: [PATCH 035/343] usb: atm: usbatm: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index db322d9ccb6e..5e4f46c5a300 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1141,7 +1141,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, urb = usb_alloc_urb(iso_packets, GFP_KERNEL); if (!urb) { - dev_err(dev, "%s: no memory for urb %d!\n", __func__, i); error = -ENOMEM; goto fail_unbind; } From c3014d33f58651b05cf5d24598ce7048bb202bee Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:35 +0200 Subject: [PATCH 036/343] usb: class: usbtmc: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 917a55c4480d..22c235adacb3 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1467,10 +1467,8 @@ static int usbtmc_probe(struct usb_interface *intf, if (data->iin_ep_present) { /* allocate int urb */ data->iin_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!data->iin_urb) { - dev_err(&intf->dev, "Failed to allocate int urb\n"); + if (!data->iin_urb) goto error_register; - } /* will reference data in int urb */ kref_get(&data->kref); From 71574a558d243f99d03c4ebec2b2420402857c5b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:36 +0200 Subject: [PATCH 037/343] usb: misc: adutux: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 3071c0ef909b..c34a0b6980cd 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -744,20 +744,16 @@ static int adu_probe(struct usb_interface *interface, memset(dev->interrupt_in_buffer, 'i', in_end_size); dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); + if (!dev->interrupt_in_urb) goto error; - } dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n"); goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_out_urb\n"); + if (!dev->interrupt_out_urb) goto error; - } if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number, sizeof(dev->serial_number))) { From c6b1caaf2a6446516b5c8620d423ea2593142f03 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:37 +0200 Subject: [PATCH 038/343] usb: misc: appledisplay: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/appledisplay.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 188c8d2e6007..29569ec2ee50 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -261,7 +261,6 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->urb = usb_alloc_urb(0, GFP_KERNEL); if (!pdata->urb) { retval = -ENOMEM; - dev_err(&iface->dev, "Allocating URB failed\n"); goto error; } From d3ec72b0c15839600aa03d97c69313f53024015e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:38 +0200 Subject: [PATCH 039/343] usb: misc: ftdi-elan: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 59031dc21eab..4eb1e2e3f039 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -782,11 +782,8 @@ static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) return 0; total_size = ftdi_elan_total_command_size(ftdi, command_size); urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not get a urb to write %d commands totaling %d bytes to the Uxxx\n", - command_size, total_size); + if (!urb) return -ENOMEM; - } buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { @@ -1945,10 +1942,8 @@ static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) int I = 257; int i = 0; urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequence\n"); + if (!urb) return -ENOMEM; - } buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); if (!buf) { dev_err(&ftdi->udev->dev, "could not get a buffer for flush sequence\n"); @@ -1985,10 +1980,8 @@ static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) int I = 4; int i = 0; urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not get a urb for the reset sequence\n"); + if (!urb) return -ENOMEM; - } buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); if (!buf) { dev_err(&ftdi->udev->dev, "could not get a buffer for the reset sequence\n"); From 5656bbb772e51f59bcd254cb8e5fd03977d66028 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:39 +0200 Subject: [PATCH 040/343] usb: misc: iowarrior: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 1950e87b4219..7defa34dd4fa 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -413,8 +413,6 @@ static ssize_t iowarrior_write(struct file *file, int_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!int_out_urb) { retval = -ENOMEM; - dev_dbg(&dev->interface->dev, - "Unable to allocate urb\n"); goto error_no_urb; } buf = usb_alloc_coherent(dev->udev, dev->report_size, @@ -812,10 +810,8 @@ static int iowarrior_probe(struct usb_interface *interface, /* create the urb and buffer for reading */ dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->int_in_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); + if (!dev->int_in_urb) goto error; - } dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); if (!dev->int_in_buffer) { dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n"); From 2d40390337dcc4a02f06574a18119bfbeb798867 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:40 +0200 Subject: [PATCH 041/343] usb: misc: ldusb: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ldusb.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index cce22ff1c2eb..84890791c2f8 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -714,10 +714,8 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * goto error; } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); + if (!dev->interrupt_in_urb) goto error; - } dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? usb_endpoint_maxp(dev->interrupt_out_endpoint) : udev->descriptor.bMaxPacketSize0; dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); @@ -726,10 +724,8 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); + if (!dev->interrupt_out_urb) goto error; - } dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; if (dev->interrupt_out_endpoint) dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; From a131f41f5ba60e7a05fcbce304bc894845a4995a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:41 +0200 Subject: [PATCH 042/343] usb: misc: legousbtower: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 7771be3ac178..52b41fb66792 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -881,20 +881,16 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device goto error; } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - dev_err(idev, "Couldn't allocate interrupt_in_urb\n"); + if (!dev->interrupt_in_urb) goto error; - } dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { dev_err(idev, "Couldn't allocate interrupt_out_buffer\n"); goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - dev_err(idev, "Couldn't allocate interrupt_out_urb\n"); + if (!dev->interrupt_out_urb) goto error; - } dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; From da4e20ffcedfce5774dae3c3b653cd22b370c72b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:42 +0200 Subject: [PATCH 043/343] usb: misc: lvstest: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/lvstest.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c index a985cadc0b76..9c49334c622d 100644 --- a/drivers/usb/misc/lvstest.c +++ b/drivers/usb/misc/lvstest.c @@ -395,10 +395,8 @@ static int lvs_rh_probe(struct usb_interface *intf, /* submit urb to poll interrupt endpoint */ lvs->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!lvs->urb) { - dev_err(&intf->dev, "couldn't allocate lvs urb\n"); + if (!lvs->urb) return -ENOMEM; - } INIT_WORK(&lvs->rh_work, lvs_rh_work); From 843ac1975d146c1e247b5cc87f79ccb90814619b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:43 +0200 Subject: [PATCH 044/343] usb: misc: sisusbvga: sisusb: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/sisusbvga/sisusb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 02abfcdfbf7b..05bd39d62568 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3084,7 +3084,6 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate URBs */ sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL); if (!sisusb->sisurbin) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_3; } @@ -3093,8 +3092,6 @@ static int sisusb_probe(struct usb_interface *intf, for (i = 0; i < sisusb->numobufs; i++) { sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL); if (!sisusb->sisurbout[i]) { - dev_err(&sisusb->sisusb_dev->dev, - "Failed to allocate URBs\n"); retval = -ENOMEM; goto error_4; } From 39acc8a843c3ffee8e3c6d726c83c02f4dc291b8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:44 +0200 Subject: [PATCH 045/343] usb: misc: uss720: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/uss720.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index bbd029c9c725..256d02da444d 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -162,7 +162,6 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p rq->urb = usb_alloc_urb(0, mem_flags); if (!rq->urb) { kref_put(&rq->ref_count, destroy_async); - dev_err(&usbdev->dev, "submit_async_request out of memory\n"); return NULL; } rq->dr = kmalloc(sizeof(*rq->dr), mem_flags); From 0450ba4069226a16b2fb979fdb24a3ad60634933 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:45 +0200 Subject: [PATCH 046/343] usb: misc: yurex: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/yurex.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 343fa6ff9f4b..bb606bdc25e5 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -231,10 +231,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate control URB */ dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->cntl_urb) { - dev_err(&interface->dev, "Could not allocate control URB\n"); + if (!dev->cntl_urb) goto error; - } /* allocate buffer for control req */ dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL); @@ -269,10 +267,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate interrupt URB */ dev->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->urb) { - dev_err(&interface->dev, "Could not allocate URB\n"); + if (!dev->urb) goto error; - } /* allocate buffer for interrupt in */ dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE, From 792f94f5473beefd7baee437438b6450ac8a35b4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:46 +0200 Subject: [PATCH 047/343] usb: storage: usb: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 8c5f0115166a..c8afd2d4c40b 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -794,10 +794,8 @@ static int usb_stor_acquire_resources(struct us_data *us) struct task_struct *th; us->current_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!us->current_urb) { - usb_stor_dbg(us, "URB allocation failed\n"); + if (!us->current_urb) return -ENOMEM; - } /* * Just before we start our control thread, initialize From 2bd07d3c21058db28f6e8ad41b7854f5eaffa451 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:47 +0200 Subject: [PATCH 048/343] usb: usb-skeleton: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 545d09b8081d..89e02a7529b7 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -532,11 +532,8 @@ static int skel_probe(struct usb_interface *interface, goto error; } dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->bulk_in_urb) { - dev_err(&interface->dev, - "Could not allocate bulk_in_urb\n"); + if (!dev->bulk_in_urb) goto error; - } } if (!dev->bulk_out_endpointAddr && From 7190c178e65b111379faa7c3b453b7e54f078872 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:48 +0200 Subject: [PATCH 049/343] usb: usbip: stub_rx: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/stub_rx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 2df63e305722..191b176ffedf 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -461,7 +461,6 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, priv->urb = usb_alloc_urb(0, GFP_KERNEL); if (!priv->urb) { - dev_err(&udev->dev, "malloc urb\n"); usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); return; } From 6b017b7d1094415ea935d056abe18fe136adca71 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:14:49 +0200 Subject: [PATCH 050/343] usb: wusbcore: wa-nep: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/wa-nep.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c index 60a10d21947d..6140100ad50e 100644 --- a/drivers/usb/wusbcore/wa-nep.c +++ b/drivers/usb/wusbcore/wa-nep.c @@ -277,10 +277,8 @@ int wa_nep_create(struct wahc *wa, struct usb_interface *iface) goto error_nep_buffer; } wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL); - if (wa->nep_urb == NULL) { - dev_err(dev, "Unable to allocate notification URB\n"); + if (wa->nep_urb == NULL) goto error_urb_alloc; - } usb_fill_int_urb(wa->nep_urb, usb_dev, usb_rcvintpipe(usb_dev, epd->bEndpointAddress), wa->nep_buffer, wa->nep_buffer_size, From ff7bbff3bc6f12dee4fc180a79c964c5c3eea8b2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:22:46 +0200 Subject: [PATCH 051/343] usb: wusbcore: wa-xfer: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/wa-xfer.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 69af4fd9e072..167fcc71f5f6 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -2865,10 +2865,8 @@ int wa_dti_start(struct wahc *wa) goto out; wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL); - if (wa->dti_urb == NULL) { - dev_err(dev, "Can't allocate DTI URB\n"); + if (wa->dti_urb == NULL) goto error_dti_urb_alloc; - } usb_fill_bulk_urb( wa->dti_urb, wa->usb_dev, usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress), From 13a88bf5e0fa886394d7148b9eec1f58d14608b5 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 15 Aug 2016 11:17:55 +0200 Subject: [PATCH 052/343] cdc-wdm: cleanup debug messages Dynamic debugging will already add the function (and the line number) to a debug message if one requests that. It makes no sense to add them unconditionally in a driver. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 56d3ab86be7f..bf4bb58312fb 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -314,8 +314,7 @@ static void wdm_int_callback(struct urb *urb) && !test_bit(WDM_DISCONNECTING, &desc->flags) && !test_bit(WDM_SUSPENDING, &desc->flags)) { rv = usb_submit_urb(desc->response, GFP_ATOMIC); - dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", - __func__, rv); + dev_dbg(&desc->intf->dev, "submit response URB %d", rv); } spin_unlock(&desc->iuspin); if (rv < 0) { @@ -574,7 +573,7 @@ retry: } if (!desc->reslength) { /* zero length read */ - dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); + dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ"); clear_bit(WDM_READ, &desc->flags); rv = service_outstanding_interrupt(desc); spin_unlock_irq(&desc->iuspin); @@ -1081,7 +1080,7 @@ static void wdm_disconnect(struct usb_interface *intf) if (!desc->count) cleanup(desc); else - dev_dbg(&intf->dev, "%s: %d open files - postponing cleanup\n", __func__, desc->count); + dev_dbg(&intf->dev, "%d open files - postponing cleanup\n", desc->count); mutex_unlock(&wdm_mutex); } From d35cbed6047c0207b4be9ff60b541c331b62b59c Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Sat, 13 Aug 2016 21:20:40 +0530 Subject: [PATCH 053/343] whci: Remove deprecated create_singlethread_workqueue alloc_ordered_workqueue replaces the deprecated create_singlethread_workqueue. The workqueue "workqueue" has multiple workitems which may require ordering. Hence, a dedicated ordered workqueue has been used. Since the workqueue is not being used on a memory reclaim path, WQ_MEM_RECLAIM has not been set. Signed-off-by: Bhaktipriya Shridhar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/whci/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c index e36372393bb1..ad8eb575c30a 100644 --- a/drivers/usb/host/whci/init.c +++ b/drivers/usb/host/whci/init.c @@ -65,7 +65,7 @@ int whc_init(struct whc *whc) init_waitqueue_head(&whc->cmd_wq); init_waitqueue_head(&whc->async_list_wq); init_waitqueue_head(&whc->periodic_list_wq); - whc->workqueue = create_singlethread_workqueue(dev_name(&whc->umc->dev)); + whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0); if (whc->workqueue == NULL) { ret = -ENOMEM; goto error; From 6e958051cb0742dd54bb61528c130bd6eaecae0d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 12 Aug 2016 11:22:22 +0000 Subject: [PATCH 054/343] usbip: vhci_hcd: fix return value check in add_platform_device() In case of error, the function platform_device_register_simple() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vhci_hcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 96f2dacb27fa..03eccf29ace0 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1211,8 +1211,8 @@ static int add_platform_device(int id) dev_nr = id; pdev = platform_device_register_simple(driver_name, dev_nr, NULL, 0); - if (pdev == NULL) - return -ENODEV; + if (IS_ERR(pdev)) + return PTR_ERR(pdev); *(vhci_pdevs + id) = pdev; return 0; From d6b76c4ddb124dd22c6e910ca9332e472e7b3273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 10 Aug 2016 11:56:46 +0200 Subject: [PATCH 055/343] USB: bcma: support old USB 2.0 controller on Northstar devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently bcma-hcd driver handles 3 different bcma cores: 1) BCMA_CORE_USB20_HOST (0x819) 2) BCMA_CORE_NS_USB20 (0x504) 3) BCMA_CORE_NS_USB30 (0x505) The first one was introduced years ago and so far was used on MIPS devices only. All Northstar (ARM) devices were using other two cores which allowed easy implementation of separated initialization paths. It seems however Broadcom decided to reuse this old USB 2.0 controller on some recently introduced cheaper Northstar BCM53573 SoCs. I noticed this on Tenda AC9 (based on BCM47189B0 belonging to BCM53573 family). There is no difference in this old controller core identification between MIPS and ARM devices: they share the same id and revision. We need different controller initialization procedure however. To handle this add a check for architecture and implement required initialization for ARM case. Signed-off-by: Rafał Miłecki Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 86 ++++++++++++++++++++++++++++++++-- include/linux/bcma/bcma_regs.h | 1 + 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 422fdc295b8d..e0761d92f2b6 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -35,6 +35,9 @@ MODULE_AUTHOR("Hauke Mehrtens"); MODULE_DESCRIPTION("Common USB driver for BCMA Bus"); MODULE_LICENSE("GPL"); +/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */ +#define USB_BCMA_CLKCTLST_USB_CLK_REQ 0x00000100 + struct bcma_hcd_device { struct bcma_device *core; struct platform_device *ehci_dev; @@ -166,6 +169,76 @@ static void bcma_hcd_init_chip_mips(struct bcma_device *dev) } } +/** + * bcma_hcd_usb20_old_arm_init - Initialize old USB 2.0 controller on ARM + * + * Old USB 2.0 core is identified as BCMA_CORE_USB20_HOST and was introduced + * long before Northstar devices. It seems some cheaper chipsets like BCM53573 + * still use it. + * Initialization of this old core differs between MIPS and ARM. + */ +static int bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device *usb_dev) +{ + struct bcma_device *core = usb_dev->core; + struct device *dev = &core->dev; + struct bcma_device *pmu_core; + + usleep_range(10000, 20000); + if (core->id.rev < 5) + return 0; + + pmu_core = bcma_find_core(core->bus, BCMA_CORE_PMU); + if (!pmu_core) { + dev_err(dev, "Could not find PMU core\n"); + return -ENOENT; + } + + /* Take USB core out of reset */ + bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK | BCMA_IOCTL_FGC); + usleep_range(100, 200); + bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); + usleep_range(100, 200); + bcma_awrite32(core, BCMA_RESET_CTL, 0); + usleep_range(100, 200); + bcma_awrite32(core, BCMA_IOCTL, BCMA_IOCTL_CLK); + usleep_range(100, 200); + + /* Enable Misc PLL */ + bcma_write32(core, BCMA_CLKCTLST, BCMA_CLKCTLST_FORCEHT | + BCMA_CLKCTLST_HQCLKREQ | + USB_BCMA_CLKCTLST_USB_CLK_REQ); + usleep_range(100, 200); + + bcma_write32(core, 0x510, 0xc7f85000); + bcma_write32(core, 0x510, 0xc7f85003); + usleep_range(300, 600); + + /* Program USB PHY PLL parameters */ + bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x6); + bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x005360c1); + usleep_range(100, 200); + bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_ADDR, 0x7); + bcma_write32(pmu_core, BCMA_CC_PMU_PLLCTL_DATA, 0x0); + usleep_range(100, 200); + bcma_set32(pmu_core, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD); + usleep_range(100, 200); + + bcma_write32(core, 0x510, 0x7f8d007); + udelay(1000); + + /* Take controller out of reset */ + bcma_write32(core, 0x200, 0x4ff); + usleep_range(25, 50); + bcma_write32(core, 0x200, 0x6ff); + usleep_range(25, 50); + bcma_write32(core, 0x200, 0x7ff); + usleep_range(25, 50); + + of_platform_default_populate(dev->of_node, NULL, dev); + + return 0; +} + static void bcma_hcd_init_chip_arm_phy(struct bcma_device *dev) { struct bcma_device *arm_core; @@ -370,19 +443,24 @@ static int bcma_hcd_probe(struct bcma_device *core) switch (core->id.id) { case BCMA_CORE_USB20_HOST: + if (IS_ENABLED(CONFIG_ARM)) + err = bcma_hcd_usb20_old_arm_init(usb_dev); + else if (IS_ENABLED(CONFIG_MIPS)) + err = bcma_hcd_usb20_init(usb_dev); + else + err = -ENOTSUPP; + break; case BCMA_CORE_NS_USB20: err = bcma_hcd_usb20_init(usb_dev); - if (err) - return err; break; case BCMA_CORE_NS_USB30: err = bcma_hcd_usb30_init(usb_dev); - if (err) - return err; break; default: return -ENODEV; } + if (err) + return err; bcma_set_drvdata(core, usb_dev); return 0; diff --git a/include/linux/bcma/bcma_regs.h b/include/linux/bcma/bcma_regs.h index ebd5c1fcdea4..4901fb358b07 100644 --- a/include/linux/bcma/bcma_regs.h +++ b/include/linux/bcma/bcma_regs.h @@ -10,6 +10,7 @@ #define BCMA_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ #define BCMA_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ #define BCMA_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ +#define BCMA_CLKCTLST_HQCLKREQ 0x00000040 /* HQ Clock */ #define BCMA_CLKCTLST_EXTRESREQ 0x00000700 /* Mask of external resource requests */ #define BCMA_CLKCTLST_EXTRESREQ_SHIFT 8 #define BCMA_CLKCTLST_HAVEALP 0x00010000 /* ALP available */ From 73577d61799e8d8bb7d69a9acdc54923e5998138 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 12 Aug 2016 11:06:22 +0800 Subject: [PATCH 056/343] ehci-platform: add the max clock number to 4 Allwinner A64 EHCI requires 4 clocks to be enabled. Signed-off-by: Icenowy Zheng Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 6816b8c371d0..876dca4fc216 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -38,7 +38,7 @@ #include "ehci.h" #define DRIVER_DESC "EHCI generic platform driver" -#define EHCI_MAX_CLKS 3 +#define EHCI_MAX_CLKS 4 #define EHCI_MAX_RSTS 3 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) From 8457a1b49a2af0a0e71f80afed9f7c80de361610 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 15 Aug 2016 06:15:35 -0700 Subject: [PATCH 057/343] extcon: Introduce EXTCON_PROP_USB_SS property for SuperSpeed mode EXTCON_PROP_USB_SS (SuperSpeed)[1] is necessary to distinguish between USB/USB2 and USB3 connections on USB Type-C cables. [1] https://en.wikipedia.org/wiki/USB#Overview Cc: Chris Zhong Signed-off-by: Guenter Roeck Signed-off-by: Chanwoo Choi --- include/linux/extcon.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 461abee969b7..b34d1ae9011f 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -109,12 +109,18 @@ * @type: integer (intval) * @value: 0 (normal) or 1 (flip) * @default: 0 (normal) + * - EXTCON_PROP_USB_SS (SuperSpeed) + * @type: integer (intval) + * @value: 0 (USB/USB2) or 1 (USB3) + * @default: 0 (USB/USB2) + * */ #define EXTCON_PROP_USB_VBUS 0 #define EXTCON_PROP_USB_TYPEC_POLARITY 1 +#define EXTCON_PROP_USB_SS 2 #define EXTCON_PROP_USB_MIN 0 -#define EXTCON_PROP_USB_MAX 1 +#define EXTCON_PROP_USB_MAX 2 #define EXTCON_PROP_USB_CNT (EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1) /* Properties of EXTCON_TYPE_CHG. */ From 919568691df41e655a6dac2b7a5f94befeedaf71 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 18 Aug 2016 09:45:06 -0400 Subject: [PATCH 058/343] USB: serial: use IS_ENABLED() instead of checking for built-in or module The IS_ENABLED() macro checks if a Kconfig symbol has been enabled either built-in or as a module, use that macro instead of open coding the same. Using the macro makes the code more readable by helping abstract away some of the Kconfig built-in and module enable details. Signed-off-by: Javier Martinez Canillas Signed-off-by: Johan Hovold --- drivers/usb/serial/keyspan_pda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 4f7e072e4e00..e49ad0c63ad8 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -30,12 +30,12 @@ #include /* make a simple define to handle if we are compiling keyspan_pda or xircom support */ -#if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE) +#if IS_ENABLED(CONFIG_USB_SERIAL_KEYSPAN_PDA) #define KEYSPAN #else #undef KEYSPAN #endif -#if defined(CONFIG_USB_SERIAL_XIRCOM) || defined(CONFIG_USB_SERIAL_XIRCOM_MODULE) +#if IS_ENABLED(CONFIG_USB_SERIAL_XIRCOM) #define XIRCOM #else #undef XIRCOM From 4bc48c9747084dad4b258821a69026bcc552e8ff Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 10 Aug 2016 16:04:33 +0300 Subject: [PATCH 059/343] usb: dwc3: gadget: retire LST bit completely The only endpoint which actually requires LST bit and XferComplete is ep0/1. Let's save some time by completely removing LST bit support and XferComplete. This simplifies and consolidates endpoint handling for all other 3 transfer types while also avoiding extra interrupts. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 62 ++++++++++----------------------------- 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1f5597ef945d..15df5ed546da 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -490,7 +490,8 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, params.param0 |= DWC3_DEPCFG_ACTION_INIT; } - params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; + if (usb_endpoint_xfer_control(desc)) + params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN; if (dep->number <= 1 || usb_endpoint_xfer_isoc(desc)) params.param1 |= DWC3_DEPCFG_XFER_NOT_READY_EN; @@ -771,15 +772,13 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, */ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_request *req, dma_addr_t dma, - unsigned length, unsigned last, unsigned chain, unsigned node) + unsigned length, unsigned chain, unsigned node) { struct dwc3_trb *trb; - dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s", + dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s", dep->name, req, (unsigned long long) dma, - length, last ? " last" : "", - chain ? " chain" : ""); - + length, chain ? " chain" : ""); trb = &dep->trb_pool[dep->trb_enqueue]; @@ -829,9 +828,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, if (!req->request.no_interrupt && !chain) trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; - if (last && !usb_endpoint_xfer_isoc(dep->endpoint.desc)) - trb->ctrl |= DWC3_TRB_CTRL_LST; - if (chain) trb->ctrl |= DWC3_TRB_CTRL_CHN; @@ -894,13 +890,11 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) } static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left, - unsigned int more_coming) + struct dwc3_request *req, unsigned int trbs_left) { struct usb_request *request = &req->request; struct scatterlist *sg = request->sg; struct scatterlist *s; - unsigned int last = false; unsigned int length; dma_addr_t dma; int i; @@ -911,48 +905,28 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, length = sg_dma_len(s); dma = sg_dma_address(s); - if (sg_is_last(s)) { - if (usb_endpoint_xfer_int(dep->endpoint.desc) || - !more_coming) - last = true; - - chain = false; - } - - if (!trbs_left--) - last = true; - - if (last) + if (sg_is_last(s)) chain = false; dwc3_prepare_one_trb(dep, req, dma, length, - last, chain, i); + chain, i); - if (last) + if (!trbs_left--) break; } } static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left, - unsigned int more_coming) + struct dwc3_request *req, unsigned int trbs_left) { - unsigned int last = false; unsigned int length; dma_addr_t dma; dma = req->request.dma; length = req->request.length; - if (!trbs_left) - last = true; - - /* Is this the last request? */ - if (usb_endpoint_xfer_int(dep->endpoint.desc) || !more_coming) - last = true; - dwc3_prepare_one_trb(dep, req, dma, length, - last, false, 0); + false, 0); } /* @@ -966,7 +940,6 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; - unsigned int more_coming; u32 trbs_left; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); @@ -975,15 +948,11 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) if (!trbs_left) return; - more_coming = dep->allocated_requests - dep->queued_requests; - list_for_each_entry_safe(req, n, &dep->pending_list, list) { if (req->request.num_mapped_sgs > 0) - dwc3_prepare_one_trb_sg(dep, req, trbs_left--, - more_coming); + dwc3_prepare_one_trb_sg(dep, req, trbs_left--); else - dwc3_prepare_one_trb_linear(dep, req, trbs_left--, - more_coming); + dwc3_prepare_one_trb_linear(dep, req, trbs_left--); if (!trbs_left) return; @@ -1127,8 +1096,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * This will save one IRQ (XFER_NOT_READY) and possibly make it a * little bit faster. */ - if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) && - !usb_endpoint_xfer_int(dep->endpoint.desc)) { + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { ret = __dwc3_gadget_kick_transfer(dep, 0); goto out; } @@ -2045,7 +2013,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, int chain; req = next_request(&dep->started_list); - if (WARN_ON_ONCE(!req)) + if (!req) return 1; chain = req->request.num_mapped_sgs > 0; From 737f1ae2556a5d219c24fbea2e1c63b7d9e10869 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Aug 2016 12:24:27 +0300 Subject: [PATCH 060/343] usb: dwc3: gadget: increment dequeue pointer on completion Instead of waiting until giveback before incrementing the dequeue pointer, we can increment it from dwc3_cleanup_done_reqs(), that way we avoid an extra loop over all TRBs during giveback. While at that, also avoid using req->first_trb_index as that's completely unnecessary. A follow-up patch will clean up further uses of that and remove the field altogether. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 15df5ed546da..18045997b593 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -174,15 +174,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status) { struct dwc3 *dwc = dep->dwc; - int i; - if (req->started) { - i = 0; - do { - dwc3_ep_inc_deq(dep); - } while(++i < req->request.num_mapped_sgs); - req->started = false; - } + req->started = false; list_del(&req->list); req->trb = NULL; @@ -2004,7 +1997,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, { struct dwc3_request *req; struct dwc3_trb *trb; - unsigned int slot; unsigned int i; int count = 0; int ret; @@ -2019,12 +2011,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, chain = req->request.num_mapped_sgs > 0; i = 0; do { - slot = req->first_trb_index + i; - if (slot == DWC3_TRB_NUM - 1) - slot++; - slot %= DWC3_TRB_NUM; - trb = &dep->trb_pool[slot]; + trb = &dep->trb_pool[dep->trb_dequeue]; count += trb->size & DWC3_TRB_SIZE_MASK; + dwc3_ep_inc_deq(dep); ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); From 45438a0cd9c2b80917047b77fab1ff46cf710748 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Aug 2016 12:26:59 +0300 Subject: [PATCH 061/343] usb: dwc3: gadget: simplify dwc3_ep_prev_trb() We always need to decrement our index by at least one. Simplify the implementation by using a temporary local variable and making sure that we will always decrement one extra if tmp == 0. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 18045997b593..a310266abc20 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -845,12 +845,12 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, */ static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index) { - if (!index) - index = DWC3_TRB_NUM - 2; - else - index = dep->trb_enqueue - 1; + u8 tmp = index; - return &dep->trb_pool[index]; + if (!tmp) + tmp = DWC3_TRB_NUM - 1; + + return &dep->trb_pool[tmp - 1]; } static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) From 08a36b543803b7fe39b66ca0529bea34a88dc77f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Aug 2016 14:27:52 +0300 Subject: [PATCH 062/343] usb: dwc3: gadget: simplify __dwc3_gadget_ep_queue() Many of the comments in that function are really outdated and don't match what the driver is doing. Moreover, recent patches combined programming model for all non-control endpoints, this gives us an opportunity to get rid of our special cases in __dwc3_gadget_ep_queue(). Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 83 ++++----------------------------------- 1 file changed, 7 insertions(+), 76 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a310266abc20..3cf4c9016b75 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1063,18 +1063,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) trace_dwc3_ep_queue(req); - /* - * We only add to our list of requests now and - * start consuming the list once we get XferNotReady - * IRQ. - * - * That way, we avoid doing anything that we don't need - * to do now and defer it until the point we receive a - * particular token from the Host side. - * - * This will also avoid Host cancelling URBs due to too - * many NAKs. - */ ret = usb_gadget_map_request(&dwc->gadget, &req->request, dep->direction); if (ret) @@ -1082,73 +1070,16 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) list_add_tail(&req->list, &dep->pending_list); - /* - * If there are no pending requests and the endpoint isn't already - * busy, we will just start the request straight away. - * - * This will save one IRQ (XFER_NOT_READY) and possibly make it a - * little bit faster. - */ - if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - ret = __dwc3_gadget_kick_transfer(dep, 0); - goto out; - } - - /* - * There are a few special cases: - * - * 1. XferNotReady with empty list of requests. We need to kick the - * transfer here in that situation, otherwise we will be NAKing - * forever. If we get XferNotReady before gadget driver has a - * chance to queue a request, we will ACK the IRQ but won't be - * able to receive the data until the next request is queued. - * The following code is handling exactly that. - * - */ - if (dep->flags & DWC3_EP_PENDING_REQUEST) { - /* - * If xfernotready is already elapsed and it is a case - * of isoc transfer, then issue END TRANSFER, so that - * you can receive xfernotready again and can have - * notion of current microframe. - */ - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - if (list_empty(&dep->started_list)) { - dwc3_stop_active_transfer(dwc, dep->number, true); - dep->flags = DWC3_EP_ENABLED; - } - return 0; - } - - ret = __dwc3_gadget_kick_transfer(dep, 0); - if (!ret) - dep->flags &= ~DWC3_EP_PENDING_REQUEST; - - goto out; - } - - /* - * 2. XferInProgress on Isoc EP with an active transfer. We need to - * kick the transfer here after queuing a request, otherwise the - * core may not see the modified TRB(s). - */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - (dep->flags & DWC3_EP_BUSY) && - !(dep->flags & DWC3_EP_MISSED_ISOC)) { - WARN_ON_ONCE(!dep->resource_index); - ret = __dwc3_gadget_kick_transfer(dep, dep->resource_index); - goto out; + dep->flags & DWC3_EP_PENDING_REQUEST) { + if (list_empty(&dep->started_list)) { + dwc3_stop_active_transfer(dwc, dep->number, true); + dep->flags = DWC3_EP_ENABLED; + } + return 0; } - /* - * 4. Stream Capable Bulk Endpoints. We need to start the transfer - * right away, otherwise host will not know we have streams to be - * handled. - */ - if (dep->stream_capable) - ret = __dwc3_gadget_kick_transfer(dep, 0); - -out: + ret = __dwc3_gadget_kick_transfer(dep, 0); if (ret && ret != -EBUSY) dwc3_trace(trace_dwc3_gadget, "%s: failed to kick transfers", From 31162af447d7afba6820e42ed9cf968ed74c64cd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 11 Aug 2016 14:38:37 +0300 Subject: [PATCH 063/343] usb: dwc3: gadget: avoid while (1) loop on completion We know that we have to iterate over the list of started requests. Instead of looping forever, we can rely on list_for_each_entry(). Likewise, instead of a do {} while loop over all, maybe available, scatterlist entries, we can detect if $this request uses scatterlist and rely on for_each_sg(). This makes the code easier to follow while making sure that we will *always* break out of the loop. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3cf4c9016b75..c776fb7f524a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1926,31 +1926,37 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, const struct dwc3_event_depevt *event, int status) { - struct dwc3_request *req; + struct dwc3_request *req, *n; struct dwc3_trb *trb; - unsigned int i; int count = 0; int ret; - do { + list_for_each_entry_safe(req, n, &dep->started_list, list) { + int chain; - req = next_request(&dep->started_list); - if (!req) - return 1; - chain = req->request.num_mapped_sgs > 0; - i = 0; - do { + if (chain) { + struct scatterlist *sg = req->request.sg; + struct scatterlist *s; + unsigned int i; + + for_each_sg(sg, s, req->request.num_mapped_sgs, i) { + trb = &dep->trb_pool[dep->trb_dequeue]; + count += trb->size & DWC3_TRB_SIZE_MASK; + dwc3_ep_inc_deq(dep); + + ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, + event, status, chain); + } + } else { trb = &dep->trb_pool[dep->trb_dequeue]; count += trb->size & DWC3_TRB_SIZE_MASK; dwc3_ep_inc_deq(dep); ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); - if (ret) - break; - } while (++i < req->request.num_mapped_sgs); + } /* * We assume here we will always receive the entire data block @@ -1964,7 +1970,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, if (ret) break; - } while (1); + } /* * Our endpoint might get disabled by another thread during From 0b3e4af3c740937d1e0f7d444f75d087c29a2d1b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:10:10 +0300 Subject: [PATCH 064/343] usb: dwc3: gadget: add sg and num_pending_sgs to dwc3_request These two fields will be used in a follow-up patch to track how many entries of request's sglist we have already processed. The reason is that if a gadget driver sends an sglist with more entries then we can fit in the ring, we will have to continue processing remaining afterwards. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 45d6de5107c7..1a6cc48fc7c4 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -685,6 +685,8 @@ struct dwc3_hwparams { * @request: struct usb_request to be transferred * @list: a list_head used for request queueing * @dep: struct dwc3_ep owning this request + * @sg: pointer to first incomplete sg + * @num_pending_sgs: counter to pending sgs * @first_trb_index: index to first trb used by this request * @epnum: endpoint number to which this request refers * @trb: pointer to struct dwc3_trb @@ -697,7 +699,9 @@ struct dwc3_request { struct usb_request request; struct list_head list; struct dwc3_ep *dep; + struct scatterlist *sg; + unsigned num_pending_sgs; u8 first_trb_index; u8 epnum; struct dwc3_trb *trb; From 2c78c0295fd8e4e3fef74dcddecc9cabf44a81a5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:13:10 +0300 Subject: [PATCH 065/343] usb: dwc3: gadget: interrupt on ring full too If the ring is full and we are processing a big sglist, then let's interrupt so we can, later, add more TRBs to the ring. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c776fb7f524a..90b3d7965136 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -758,6 +758,8 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, kfree(req); } +static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep); + /** * dwc3_prepare_one_trb - setup one TRB from one request * @dep: endpoint for which this request is prepared @@ -818,7 +820,8 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, /* always enable Continue on Short Packet */ trb->ctrl |= DWC3_TRB_CTRL_CSP; - if (!req->request.no_interrupt && !chain) + if ((!req->request.no_interrupt && !chain) || + (dwc3_calc_trbs_left(dep) == 0)) trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; if (chain) From f1054b2d6a6b7b87c91467a301c2c08413f92d86 Mon Sep 17 00:00:00 2001 From: Mathieu OTHACEHE Date: Tue, 26 Jul 2016 19:59:41 +0200 Subject: [PATCH 066/343] USB: serial: ti_usb_3410_5052: do not use __uX types __uX types should only be used for user-space interactions. Also clean up uart-config endianess handling, and drop some redundant casts. Signed-off-by: Mathieu OTHACEHE [ johan: amend commit message ] Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 99 ++++++++++++++------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 07b4bf01061d..7f3d2c71bb54 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -179,23 +179,23 @@ /* Config struct */ struct ti_uart_config { - __u16 wBaudRate; - __u16 wFlags; - __u8 bDataBits; - __u8 bParity; - __u8 bStopBits; + __be16 wBaudRate; + __be16 wFlags; + u8 bDataBits; + u8 bParity; + u8 bStopBits; char cXon; char cXoff; - __u8 bUartMode; + u8 bUartMode; } __packed; /* Get port status */ struct ti_port_status { - __u8 bCmdCode; - __u8 bModuleId; - __u8 bErrorCode; - __u8 bMSR; - __u8 bLSR; + u8 bCmdCode; + u8 bModuleId; + u8 bErrorCode; + u8 bMSR; + u8 bLSR; } __packed; /* Purge modes */ @@ -218,12 +218,12 @@ struct ti_port_status { #define TI_RW_DATA_DOUBLE_WORD 0x04 struct ti_write_data_bytes { - __u8 bAddrType; - __u8 bDataType; - __u8 bDataCounter; + u8 bAddrType; + u8 bDataType; + u8 bDataCounter; __be16 wBaseAddrHi; __be16 wBaseAddrLo; - __u8 bData[0]; + u8 bData[0]; } __packed; struct ti_read_data_request { @@ -258,7 +258,7 @@ struct ti_interrupt { /* Firmware image header */ struct ti_firmware_header { __le16 wLength; - __u8 bCheckSum; + u8 bCheckSum; } __packed; /* UART addresses */ @@ -288,9 +288,9 @@ struct ti_firmware_header { struct ti_port { int tp_is_open; - __u8 tp_msr; - __u8 tp_shadow_mcr; - __u8 tp_uart_mode; /* 232 or 485 modes */ + u8 tp_msr; + u8 tp_shadow_mcr; + u8 tp_uart_mode; /* 232 or 485 modes */ unsigned int tp_uart_base_addr; int tp_flags; struct ti_device *tp_tdev; @@ -343,7 +343,7 @@ static int ti_get_serial_info(struct ti_port *tport, struct serial_struct __user *ret_arg); static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, struct serial_struct __user *new_arg); -static void ti_handle_new_msr(struct ti_port *tport, __u8 msr); +static void ti_handle_new_msr(struct ti_port *tport, u8 msr); static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); @@ -354,7 +354,7 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, __u16 moduleid, __u16 value, __u8 *data, int size); static int ti_write_byte(struct usb_serial_port *port, struct ti_device *tdev, - unsigned long addr, __u8 mask, __u8 byte); + unsigned long addr, u8 mask, u8 byte); static int ti_download_firmware(struct ti_device *tdev); @@ -647,9 +647,11 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) struct urb *urb; int port_number; int status; - __u16 open_settings = (__u8)(TI_PIPE_MODE_CONTINUOUS | - TI_PIPE_TIMEOUT_ENABLE | - (TI_TRANSFER_TIMEOUT << 2)); + u16 open_settings; + + open_settings = (TI_PIPE_MODE_CONTINUOUS | + TI_PIPE_TIMEOUT_ENABLE | + (TI_TRANSFER_TIMEOUT << 2)); if (tport == NULL) return -ENODEV; @@ -959,6 +961,8 @@ static void ti_set_termios(struct tty_struct *tty, int status; int port_number = port->port_number; unsigned int mcr; + u16 wbaudrate; + u16 wflags = 0; cflag = tty->termios.c_cflag; iflag = tty->termios.c_iflag; @@ -974,12 +978,10 @@ static void ti_set_termios(struct tty_struct *tty, if (!config) return; - config->wFlags = 0; - /* these flags must be set */ - config->wFlags |= TI_UART_ENABLE_MS_INTS; - config->wFlags |= TI_UART_ENABLE_AUTO_START_DMA; - config->bUartMode = (__u8)(tport->tp_uart_mode); + wflags |= TI_UART_ENABLE_MS_INTS; + wflags |= TI_UART_ENABLE_AUTO_START_DMA; + config->bUartMode = tport->tp_uart_mode; switch (cflag & CSIZE) { case CS5: @@ -1002,14 +1004,14 @@ static void ti_set_termios(struct tty_struct *tty, if (cflag & PARENB) { if (cflag & PARODD) { - config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING; + wflags |= TI_UART_ENABLE_PARITY_CHECKING; config->bParity = TI_UART_ODD_PARITY; } else { - config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING; + wflags |= TI_UART_ENABLE_PARITY_CHECKING; config->bParity = TI_UART_EVEN_PARITY; } } else { - config->wFlags &= ~TI_UART_ENABLE_PARITY_CHECKING; + wflags &= ~TI_UART_ENABLE_PARITY_CHECKING; config->bParity = TI_UART_NO_PARITY; } @@ -1021,8 +1023,8 @@ static void ti_set_termios(struct tty_struct *tty, if (cflag & CRTSCTS) { /* RTS flow control must be off to drop RTS for baud rate B0 */ if ((cflag & CBAUD) != B0) - config->wFlags |= TI_UART_ENABLE_RTS_IN; - config->wFlags |= TI_UART_ENABLE_CTS_OUT; + wflags |= TI_UART_ENABLE_RTS_IN; + wflags |= TI_UART_ENABLE_CTS_OUT; } else { ti_restart_read(tport, tty); } @@ -1032,21 +1034,21 @@ static void ti_set_termios(struct tty_struct *tty, config->cXoff = STOP_CHAR(tty); if (I_IXOFF(tty)) - config->wFlags |= TI_UART_ENABLE_X_IN; + wflags |= TI_UART_ENABLE_X_IN; else ti_restart_read(tport, tty); if (I_IXON(tty)) - config->wFlags |= TI_UART_ENABLE_X_OUT; + wflags |= TI_UART_ENABLE_X_OUT; } baud = tty_get_baud_rate(tty); if (!baud) baud = 9600; if (tport->tp_tdev->td_is_3410) - config->wBaudRate = (__u16)((923077 + baud/2) / baud); + wbaudrate = (923077 + baud/2) / baud; else - config->wBaudRate = (__u16)((461538 + baud/2) / baud); + wbaudrate = (461538 + baud/2) / baud; /* FIXME: Should calculate resulting baud here and report it back */ if ((cflag & CBAUD) != B0) @@ -1054,12 +1056,12 @@ static void ti_set_termios(struct tty_struct *tty, dev_dbg(&port->dev, "%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n", - __func__, baud, config->wBaudRate, config->wFlags, + __func__, baud, wbaudrate, wflags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode); - cpu_to_be16s(&config->wBaudRate); - cpu_to_be16s(&config->wFlags); + config->wBaudRate = cpu_to_be16(wbaudrate); + config->wFlags = cpu_to_be16(wflags); status = ti_command_out_sync(tport->tp_tdev, TI_SET_CONFIG, (__u8)(TI_UART1_PORT + port_number), 0, (__u8 *)config, @@ -1189,7 +1191,7 @@ static void ti_interrupt_callback(struct urb *urb) int function; int status = urb->status; int retval; - __u8 msr; + u8 msr; switch (status) { case 0: @@ -1522,7 +1524,7 @@ static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, } -static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) +static void ti_handle_new_msr(struct ti_port *tport, u8 msr) { struct async_icount *icount; struct tty_struct *tty; @@ -1634,8 +1636,8 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, static int ti_write_byte(struct usb_serial_port *port, - struct ti_device *tdev, unsigned long addr, - __u8 mask, __u8 byte) + struct ti_device *tdev, unsigned long addr, + u8 mask, u8 byte) { int status; unsigned int size; @@ -1679,11 +1681,10 @@ static int ti_do_download(struct usb_device *dev, int pipe, int len; for (pos = sizeof(struct ti_firmware_header); pos < size; pos++) - cs = (__u8)(cs + buffer[pos]); + cs = (u8)(cs + buffer[pos]); header = (struct ti_firmware_header *)buffer; - header->wLength = cpu_to_le16((__u16)(size - - sizeof(struct ti_firmware_header))); + header->wLength = cpu_to_le16(size - sizeof(*header)); header->bCheckSum = cs; dev_dbg(&dev->dev, "%s - downloading firmware\n", __func__); @@ -1701,7 +1702,7 @@ static int ti_download_firmware(struct ti_device *tdev) { int status; int buffer_size; - __u8 *buffer; + u8 *buffer; struct usb_device *dev = tdev->td_serial->dev; unsigned int pipe = usb_sndbulkpipe(dev, tdev->td_serial->port[0]->bulk_out_endpointAddress); From 14e3c97c2db8735b5304379dd4e6cfe1d68a7a49 Mon Sep 17 00:00:00 2001 From: Mathieu OTHACEHE Date: Tue, 26 Jul 2016 19:59:42 +0200 Subject: [PATCH 067/343] USB: serial: ti_usb_3410_5052: remove useless dev_dbg messages Remove useless or redundant dev_dbg messages. Signed-off-by: Mathieu OTHACEHE [ johan: drop an unrelated change ] Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 7f3d2c71bb54..4dc2514526d1 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -688,7 +688,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ti_set_termios(tty, port, &tty->termios); - dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); if (status) { @@ -697,7 +696,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } - dev_dbg(&port->dev, "%s - sending TI_START_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_START_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) { @@ -706,7 +704,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } - dev_dbg(&port->dev, "%s - sending TI_PURGE_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_PURGE_PORT, (__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0); if (status) { @@ -730,7 +727,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ti_set_termios(tty, port, &tty->termios); - dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT (2)\n", __func__); status = ti_command_out_sync(tdev, TI_OPEN_PORT, (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); if (status) { @@ -739,7 +735,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) goto unlink_int_urb; } - dev_dbg(&port->dev, "%s - sending TI_START_PORT (2)\n", __func__); status = ti_command_out_sync(tdev, TI_START_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) { @@ -749,7 +744,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) } /* start read urb */ - dev_dbg(&port->dev, "%s - start read urb\n", __func__); urb = port->read_urb; if (!urb) { dev_err(&port->dev, "%s - no read urb\n", __func__); @@ -775,7 +769,6 @@ unlink_int_urb: usb_kill_urb(port->serial->port[0]->interrupt_in_urb); release_lock: mutex_unlock(&tdev->td_open_close_lock); - dev_dbg(&port->dev, "%s - exit %d\n", __func__, status); return status; } @@ -805,7 +798,6 @@ static void ti_close(struct usb_serial_port *port) port_number = port->port_number; - dev_dbg(&port->dev, "%s - sending TI_CLOSE_PORT\n", __func__); status = ti_command_out_sync(tdev, TI_CLOSE_PORT, (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); if (status) @@ -832,7 +824,6 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, struct ti_port *tport = usb_get_serial_port_data(port); if (count == 0) { - dev_dbg(&port->dev, "%s - write request of 0 bytes\n", __func__); return 0; } @@ -939,11 +930,9 @@ static int ti_ioctl(struct tty_struct *tty, switch (cmd) { case TIOCGSERIAL: - dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); return ti_get_serial_info(tport, (struct serial_struct __user *)arg); case TIOCSSERIAL: - dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__); return ti_set_serial_info(tty, tport, (struct serial_struct __user *)arg); } From 98ba0853e7c8266fe48490d466c88d68121a0917 Mon Sep 17 00:00:00 2001 From: Mathieu OTHACEHE Date: Tue, 26 Jul 2016 19:59:44 +0200 Subject: [PATCH 068/343] USB: serial: ti_usb_3410_5052: remove useless NULL-testing It is useless to check the return of usb_get_serial_port_data in the tty and tty-port callbacks. No need to check interface private data in close() either. Signed-off-by: Mathieu OTHACEHE [ johan: amend commit message ] Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 34 +-------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 4dc2514526d1..cbd67edff7aa 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -653,9 +653,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) TI_PIPE_TIMEOUT_ENABLE | (TI_TRANSFER_TIMEOUT << 2)); - if (tport == NULL) - return -ENODEV; - dev = port->serial->dev; tdev = tport->tp_tdev; @@ -784,8 +781,6 @@ static void ti_close(struct usb_serial_port *port) tdev = usb_get_serial_data(port->serial); tport = usb_get_serial_port_data(port); - if (tdev == NULL || tport == NULL) - return; tport->tp_is_open = 0; @@ -827,7 +822,7 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, return 0; } - if (tport == NULL || !tport->tp_is_open) + if (!tport->tp_is_open) return -ENODEV; count = kfifo_in_locked(&port->write_fifo, data, count, @@ -845,9 +840,6 @@ static int ti_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - if (tport == NULL) - return 0; - spin_lock_irqsave(&tport->tp_lock, flags); room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); @@ -864,9 +856,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - if (tport == NULL) - return 0; - spin_lock_irqsave(&tport->tp_lock, flags); chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); @@ -893,9 +882,6 @@ static void ti_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - if (tport == NULL) - return; - if (I_IXOFF(tty) || C_CRTSCTS(tty)) ti_stop_read(tport, tty); @@ -908,9 +894,6 @@ static void ti_unthrottle(struct tty_struct *tty) struct ti_port *tport = usb_get_serial_port_data(port); int status; - if (tport == NULL) - return; - if (I_IXOFF(tty) || C_CRTSCTS(tty)) { status = ti_restart_read(tport, tty); if (status) @@ -925,9 +908,6 @@ static int ti_ioctl(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - if (tport == NULL) - return -ENODEV; - switch (cmd) { case TIOCGSERIAL: return ti_get_serial_info(tport, @@ -960,9 +940,6 @@ static void ti_set_termios(struct tty_struct *tty, dev_dbg(&port->dev, "%s - old clfag %08x, old iflag %08x\n", __func__, old_termios->c_cflag, old_termios->c_iflag); - if (tport == NULL) - return; - config = kmalloc(sizeof(*config), GFP_KERNEL); if (!config) return; @@ -1083,9 +1060,6 @@ static int ti_tiocmget(struct tty_struct *tty) unsigned int mcr; unsigned long flags; - if (tport == NULL) - return -ENODEV; - spin_lock_irqsave(&tport->tp_lock, flags); msr = tport->tp_msr; mcr = tport->tp_shadow_mcr; @@ -1113,9 +1087,6 @@ static int ti_tiocmset(struct tty_struct *tty, unsigned int mcr; unsigned long flags; - if (tport == NULL) - return -ENODEV; - spin_lock_irqsave(&tport->tp_lock, flags); mcr = tport->tp_shadow_mcr; @@ -1146,9 +1117,6 @@ static void ti_break(struct tty_struct *tty, int break_state) dev_dbg(&port->dev, "%s - state = %d\n", __func__, break_state); - if (tport == NULL) - return; - status = ti_write_byte(port, tport->tp_tdev, tport->tp_uart_base_addr + TI_UART_OFFSET_LCR, TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0); From 38d6d23f31a20a6557174d2ab4bdaa0cc713d67c Mon Sep 17 00:00:00 2001 From: Mathieu OTHACEHE Date: Tue, 26 Jul 2016 19:59:45 +0200 Subject: [PATCH 069/343] USB: serial: ti_usb_3410_5052: use C_X macros Use C_X tty.h macros to avoid direct manipulation of termios c_cflag variable. Signed-off-by: Mathieu OTHACEHE Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index cbd67edff7aa..5c7b27a04b56 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -949,7 +949,7 @@ static void ti_set_termios(struct tty_struct *tty, wflags |= TI_UART_ENABLE_AUTO_START_DMA; config->bUartMode = tport->tp_uart_mode; - switch (cflag & CSIZE) { + switch (C_CSIZE(tty)) { case CS5: config->bDataBits = TI_UART_5_DATA_BITS; break; @@ -968,8 +968,8 @@ static void ti_set_termios(struct tty_struct *tty, /* CMSPAR isn't supported by this driver */ tty->termios.c_cflag &= ~CMSPAR; - if (cflag & PARENB) { - if (cflag & PARODD) { + if (C_PARENB(tty)) { + if (C_PARODD(tty)) { wflags |= TI_UART_ENABLE_PARITY_CHECKING; config->bParity = TI_UART_ODD_PARITY; } else { @@ -981,14 +981,14 @@ static void ti_set_termios(struct tty_struct *tty, config->bParity = TI_UART_NO_PARITY; } - if (cflag & CSTOPB) + if (C_CSTOPB(tty)) config->bStopBits = TI_UART_2_STOP_BITS; else config->bStopBits = TI_UART_1_STOP_BITS; - if (cflag & CRTSCTS) { + if (C_CRTSCTS(tty)) { /* RTS flow control must be off to drop RTS for baud rate B0 */ - if ((cflag & CBAUD) != B0) + if ((C_BAUD(tty)) != B0) wflags |= TI_UART_ENABLE_RTS_IN; wflags |= TI_UART_ENABLE_CTS_OUT; } else { @@ -1017,7 +1017,7 @@ static void ti_set_termios(struct tty_struct *tty, wbaudrate = (461538 + baud/2) / baud; /* FIXME: Should calculate resulting baud here and report it back */ - if ((cflag & CBAUD) != B0) + if ((C_BAUD(tty)) != B0) tty_encode_baud_rate(tty, baud, baud); dev_dbg(&port->dev, @@ -1039,7 +1039,7 @@ static void ti_set_termios(struct tty_struct *tty, /* SET_CONFIG asserts RTS and DTR, reset them correctly */ mcr = tport->tp_shadow_mcr; /* if baud rate is B0, clear RTS and DTR */ - if ((cflag & CBAUD) == B0) + if (C_BAUD(tty) == B0) mcr &= ~(TI_MCR_DTR | TI_MCR_RTS); status = ti_set_mcr(tport, mcr); if (status) From 61fc51366b395f1441c7cd3615fb18837a4fa2f8 Mon Sep 17 00:00:00 2001 From: Mathieu OTHACEHE Date: Tue, 26 Jul 2016 19:59:46 +0200 Subject: [PATCH 070/343] USB: serial: ti_usb_3410_5052: remove unused variables Remove variables affected but never read. Also drop the now unused TI_SET_SERIAL_FLAGS define. Signed-off-by: Mathieu OTHACEHE [ johan: drop TI_SET_SERIAL_FLAGS ] Signed-off-by: Johan Hovold --- drivers/usb/serial/ti_usb_3410_5052.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 5c7b27a04b56..a8b9bdba314f 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -276,9 +276,6 @@ struct ti_firmware_header { #define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */ -/* supported setserial flags */ -#define TI_SET_SERIAL_FLAGS 0 - /* read urb states */ #define TI_READ_URB_RUNNING 0 #define TI_READ_URB_STOPPING 1 @@ -292,7 +289,6 @@ struct ti_port { u8 tp_shadow_mcr; u8 tp_uart_mode; /* 232 or 485 modes */ unsigned int tp_uart_base_addr; - int tp_flags; struct ti_device *tp_tdev; struct usb_serial_port *tp_port; spinlock_t tp_lock; @@ -306,7 +302,6 @@ struct ti_device { struct usb_serial *td_serial; int td_is_3410; bool td_rs485_only; - int td_urb_error; }; static int ti_startup(struct usb_serial *serial); @@ -1157,11 +1152,9 @@ static void ti_interrupt_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); - tdev->td_urb_error = 1; return; default: dev_err(dev, "%s - nonzero urb status, %d\n", __func__, status); - tdev->td_urb_error = 1; goto exit; } @@ -1234,12 +1227,10 @@ static void ti_bulk_in_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: dev_dbg(dev, "%s - urb shutting down, %d\n", __func__, status); - tport->tp_tdev->td_urb_error = 1; return; default: dev_err(dev, "%s - nonzero urb status, %d\n", __func__, status); - tport->tp_tdev->td_urb_error = 1; } if (status == -EPIPE) @@ -1294,12 +1285,10 @@ static void ti_bulk_out_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: dev_dbg(&port->dev, "%s - urb shutting down, %d\n", __func__, status); - tport->tp_tdev->td_urb_error = 1; return; default: dev_err_console(port, "%s - nonzero urb status, %d\n", __func__, status); - tport->tp_tdev->td_urb_error = 1; } /* send any buffered data */ @@ -1449,7 +1438,6 @@ static int ti_get_serial_info(struct ti_port *tport, ret_serial.type = PORT_16550A; ret_serial.line = port->minor; ret_serial.port = port->port_number; - ret_serial.flags = tport->tp_flags; ret_serial.xmit_fifo_size = kfifo_size(&port->write_fifo); ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; ret_serial.closing_wait = cwait; @@ -1474,7 +1462,6 @@ static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, if (cwait != ASYNC_CLOSING_WAIT_NONE) cwait = msecs_to_jiffies(10 * new_serial.closing_wait); - tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS; tport->tp_port->port.closing_wait = cwait; return 0; From 1f512119a08c0d4d37c6f7865da378349d244ecc Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:17:27 +0300 Subject: [PATCH 071/343] usb: dwc3: gadget: add remaining sg entries to ring Upon transfer completion after a full ring, let's add more TRBs to our ring in order to complete our request successfully. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 90b3d7965136..c18bf1caad54 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -888,14 +888,13 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, struct dwc3_request *req, unsigned int trbs_left) { - struct usb_request *request = &req->request; - struct scatterlist *sg = request->sg; + struct scatterlist *sg = req->sg; struct scatterlist *s; unsigned int length; dma_addr_t dma; int i; - for_each_sg(sg, s, request->num_mapped_sgs, i) { + for_each_sg(sg, s, req->num_pending_sgs, i) { unsigned chain = true; length = sg_dma_len(s); @@ -945,7 +944,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep) return; list_for_each_entry_safe(req, n, &dep->pending_list, list) { - if (req->request.num_mapped_sgs > 0) + if (req->num_pending_sgs > 0) dwc3_prepare_one_trb_sg(dep, req, trbs_left--); else dwc3_prepare_one_trb_linear(dep, req, trbs_left--); @@ -1071,6 +1070,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if (ret) return ret; + req->sg = req->request.sg; + req->num_pending_sgs = req->request.num_mapped_sgs; + list_add_tail(&req->list, &dep->pending_list); if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && @@ -1935,22 +1937,30 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, int ret; list_for_each_entry_safe(req, n, &dep->started_list, list) { - + unsigned length; + unsigned actual; int chain; - chain = req->request.num_mapped_sgs > 0; + length = req->request.length; + chain = req->num_pending_sgs > 0; if (chain) { - struct scatterlist *sg = req->request.sg; + struct scatterlist *sg = req->sg; struct scatterlist *s; + unsigned int pending = req->num_pending_sgs; unsigned int i; - for_each_sg(sg, s, req->request.num_mapped_sgs, i) { + for_each_sg(sg, s, pending, i) { trb = &dep->trb_pool[dep->trb_dequeue]; count += trb->size & DWC3_TRB_SIZE_MASK; dwc3_ep_inc_deq(dep); + req->sg = sg_next(s); + req->num_pending_sgs--; + ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); + if (ret) + break; } } else { trb = &dep->trb_pool[dep->trb_dequeue]; @@ -1968,7 +1978,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, * should receive and we simply bounce the request back to the * gadget driver for further processing. */ - req->request.actual += req->request.length - count; + actual = length - req->request.actual; + req->request.actual = actual; + + if (ret && chain && (actual < length) && req->num_pending_sgs) + return __dwc3_gadget_kick_transfer(dep, 0); + dwc3_gadget_giveback(dep, req, status); if (ret) From f99f53f24d87d88c1f6e7c7785599cb3e4015839 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:19:20 +0300 Subject: [PATCH 072/343] usb: dwc3: gadget: remove condition that never happens We don't use LST bit anymore, so this condition will never trigger. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c18bf1caad54..835a5dcb8460 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1918,13 +1918,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, if (s_pkt && !chain) return 1; - if ((event->status & DEPEVT_STATUS_LST) && - (trb->ctrl & (DWC3_TRB_CTRL_LST | - DWC3_TRB_CTRL_HWO))) - return 1; + if ((event->status & DEPEVT_STATUS_IOC) && (trb->ctrl & DWC3_TRB_CTRL_IOC)) return 1; + return 0; } From dc55c67e9c95e89ef5e384fb1f70520a5383c9dd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 12 Aug 2016 13:20:32 +0300 Subject: [PATCH 073/343] usb: dwc3: gadget: improve increment request->actual No functional changes, just a slight cosmetic change. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 835a5dcb8460..0288ea99c85a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1860,6 +1860,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, unsigned int trb_status; dep->queued_requests--; + dwc3_ep_inc_deq(dep); trace_dwc3_complete_trb(dep, trb); /* @@ -1879,6 +1880,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; count = trb->size & DWC3_TRB_SIZE_MASK; + req->request.actual += count; if (dep->direction) { if (count) { @@ -1931,7 +1933,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, { struct dwc3_request *req, *n; struct dwc3_trb *trb; - int count = 0; int ret; list_for_each_entry_safe(req, n, &dep->started_list, list) { @@ -1949,8 +1950,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, for_each_sg(sg, s, pending, i) { trb = &dep->trb_pool[dep->trb_dequeue]; - count += trb->size & DWC3_TRB_SIZE_MASK; - dwc3_ep_inc_deq(dep); req->sg = sg_next(s); req->num_pending_sgs--; @@ -1962,9 +1961,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, } } else { trb = &dep->trb_pool[dep->trb_dequeue]; - count += trb->size & DWC3_TRB_SIZE_MASK; - dwc3_ep_inc_deq(dep); - ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, event, status, chain); } From 0c0e287d454a2dbfaea4159ed45f7b146010f88b Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 8 Jul 2016 22:09:05 +0200 Subject: [PATCH 074/343] usb: gadget: pxa27x: add phy notifier event handler In the legacy behavior, and USB phy, upon detection a VBus signal, was calling usb_gadget_vbus_(dis)connect(). This model doesn't work if the phy is generic and doesn't have an adherence to the gadget API. Instead of relying on the phy to call the gadget API, hook up the phy notifier to report the VBus event, and upon it call the usb gadget API ourselves. This brings a new ordering problem, as before even if the usb_get_phy() was failing because the UDC was probed before the phy, the phy would call the gadget anyway, making the VBus connection event forwarded to the gadget. Now we rely on the notifier, we have to ensure the xxx_get_phy() does indeed work. In order to cope with this, it is assumed that : - for legacy platform_data machine, as the ordering cannot be ensured, the phy must call usb_gadget_vbus_(dis)connect, such as phy-gpio-vbus-usb.c - for new devicetree platforms, we'll rely on the probe deferral, and the phy can be gadget API agnostic. Signed-off-by: Robert Jarzmik Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pxa27x_udc.c | 51 +++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index ad140aa00132..7fa60f5b7ae4 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "pxa27x_udc.h" @@ -1655,6 +1656,37 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) return -EOPNOTSUPP; } +/** + * pxa_udc_phy_event - Called by phy upon VBus event + * @nb: notifier block + * @action: phy action, is vbus connect or disconnect + * @data: the usb_gadget structure in pxa_udc + * + * Called by the USB Phy when a cable connect or disconnect is sensed. + * + * Returns 0 + */ +static int pxa_udc_phy_event(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct usb_gadget *gadget = data; + + switch (action) { + case USB_EVENT_VBUS: + usb_gadget_vbus_connect(gadget); + return NOTIFY_OK; + case USB_EVENT_NONE: + usb_gadget_vbus_disconnect(gadget); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } +} + +static struct notifier_block pxa27x_udc_phy = { + .notifier_call = pxa_udc_phy_event, +}; + static int pxa27x_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int pxa27x_udc_stop(struct usb_gadget *g); @@ -2432,7 +2464,14 @@ static int pxa_udc_probe(struct platform_device *pdev) return udc->irq; udc->dev = &pdev->dev; - udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + if (of_have_populated_dt()) { + udc->transceiver = + devm_usb_get_phy_by_phandle(udc->dev, "phys", 0); + if (IS_ERR(udc->transceiver)) + return PTR_ERR(udc->transceiver); + } else { + udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); + } if (IS_ERR(udc->gpiod)) { dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n", @@ -2465,14 +2504,20 @@ static int pxa_udc_probe(struct platform_device *pdev) goto err; } + if (!IS_ERR_OR_NULL(udc->transceiver)) + usb_register_notifier(udc->transceiver, &pxa27x_udc_phy); retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (retval) - goto err; + goto err_add_gadget; pxa_init_debugfs(udc); if (should_enable_udc(udc)) udc_enable(udc); return 0; + +err_add_gadget: + if (!IS_ERR_OR_NULL(udc->transceiver)) + usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy); err: clk_unprepare(udc->clk); return retval; @@ -2489,6 +2534,8 @@ static int pxa_udc_remove(struct platform_device *_dev) usb_del_gadget_udc(&udc->gadget); pxa_cleanup_debugfs(udc); + if (!IS_ERR_OR_NULL(udc->transceiver)) + usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy); usb_put_phy(udc->transceiver); udc->transceiver = NULL; From 9835a6ef1a96b203278629bbcf5099622070c32b Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 8 Jul 2016 22:09:06 +0200 Subject: [PATCH 075/343] usb: phy: generic: cope with initial state In the gpio based case, the status of the phy is known at start by reading the VBus gpio. Actually, this is a fix, as this initial state, when not set up, prevents a gadget to answer to the enumeration phase, as there is no notification in this case (the VBus is already high when kernel boots) so no interrupt is triggered, and the flow is : - gadget initializes - gadget gets its phy-generic with a xxx_get_phy_xxx() call type - gadget does a "set_peripheral()" call type => here if the otg->state is correctly filled, the proper vbus handling will be called, and the gadget will be aware it should answer enumeration and go forth Without this fix, the USB cable must be removed and replugged for any gadget relying on phy-generic and its gpio vbus handling to work. The problem was seen on a pxa27x architecture based board on a devicetree build. Signed-off-by: Robert Jarzmik Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-generic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 980c9dee09eb..41b8aff9b925 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -322,6 +322,8 @@ static int usb_phy_generic_probe(struct platform_device *pdev) gpiod_to_irq(nop->gpiod_vbus), err); return err; } + nop->phy.otg->state = gpiod_get_value(nop->gpiod_vbus) ? + OTG_STATE_B_PERIPHERAL : OTG_STATE_B_IDLE; } nop->phy.init = usb_gen_phy_init; From 77e012ac865037e5a227e69a294326b6ce93f9a4 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 8 Jul 2016 22:09:07 +0200 Subject: [PATCH 076/343] usb: phy: generic: remove the vbus dependency As the last known user, ie. pxa27x_udc relying on calls to usb_gadget_xxx() was amended to use the phy notifier, remove a bit the USB stack adherence. Actually the driver still uses the gadget API for structures definition, but the implementation of USB gadget specific function usb_gadget_*() is not necessary anymore. Signed-off-by: Robert Jarzmik Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-generic.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index 41b8aff9b925..c14e767a3fbf 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -118,8 +118,6 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data) status = USB_EVENT_VBUS; otg->state = OTG_STATE_B_PERIPHERAL; nop->phy.last_event = status; - if (otg->gadget) - usb_gadget_vbus_connect(otg->gadget); /* drawing a "unit load" is *always* OK, except for OTG */ nop_set_vbus_draw(nop, 100); @@ -129,8 +127,6 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data) } else { nop_set_vbus_draw(nop, 0); - if (otg->gadget) - usb_gadget_vbus_disconnect(otg->gadget); status = USB_EVENT_NONE; otg->state = OTG_STATE_B_IDLE; nop->phy.last_event = status; @@ -187,7 +183,8 @@ static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) otg->gadget = gadget; if (otg->state == OTG_STATE_B_PERIPHERAL) - usb_gadget_vbus_connect(gadget); + atomic_notifier_call_chain(&otg->usb_phy->notifier, + USB_EVENT_VBUS, otg->gadget); else otg->state = OTG_STATE_B_IDLE; return 0; From a08f5dbf877a4594816dbb499c4af18fce936110 Mon Sep 17 00:00:00 2001 From: Romain Izard Date: Tue, 26 Jul 2016 18:21:46 +0200 Subject: [PATCH 077/343] usb: gadget: configfs: log function unbinding as information Disabling USB gadget functions configured through configfs is something that can happen in normal use cases. Keep the existing log for this type of event, but only as information, not as an error. Signed-off-by: Romain Izard Signed-off-by: Felipe Balbi --- drivers/usb/gadget/configfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index f9237fe2be05..de844d44b998 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1211,8 +1211,9 @@ static void purge_configs_funcs(struct gadget_info *gi) list_move_tail(&f->list, &cfg->func_list); if (f->unbind) { - dev_err(&gi->cdev.gadget->dev, "unbind function" - " '%s'/%p\n", f->name, f); + dev_info(&gi->cdev.gadget->dev, + "unbind function '%s'/%p\n", + f->name, f); f->unbind(c, f); } } From f510b5a1d00bba1c908a4886e4c3309aca0abc8c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 25 Jul 2016 22:57:36 +0100 Subject: [PATCH 078/343] usb: gadget: remove redundant self assignment The assignment ret = ret is redundant and can be removed. Reviewed-by: Peter Chen Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 934f83881c30..d8e6686a84b7 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -107,10 +107,8 @@ int usb_ep_enable(struct usb_ep *ep) goto out; ret = ep->ops->enable(ep, ep->desc); - if (ret) { - ret = ret; + if (ret) goto out; - } ep->enabled = true; From 8dc7d30dbaa6e8020de90fb6791ebe9f35e75d75 Mon Sep 17 00:00:00 2001 From: Bhaktipriya Shridhar Date: Thu, 28 Jul 2016 13:57:29 +0530 Subject: [PATCH 079/343] usb: dwc2: Remove deprecated create_singlethread_workqueue alloc_ordered_workqueue replaces the deprecated create_singlethread_workqueue. There are multiple work items on the work queue, which require ordering. Hence, an ordered workqueue has been used. The workqueue "wq_otg" is not being used on a memory reclaim path. Hence, WQ_MEM_RECLAIM has not been set. Acked-by: John Youn Signed-off-by: Bhaktipriya Shridhar Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 2df3d04d26f5..df5a06578005 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -5040,7 +5040,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) /* Create new workqueue and init work */ retval = -ENOMEM; - hsotg->wq_otg = create_singlethread_workqueue("dwc2"); + hsotg->wq_otg = alloc_ordered_workqueue("dwc2", 0); if (!hsotg->wq_otg) { dev_err(hsotg->dev, "Failed to create workqueue\n"); goto error2; From 1650113888fe7b7e16604a5019c32dd3ddeb3af2 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 12 Aug 2016 17:28:05 +0300 Subject: [PATCH 080/343] usb: gadget: f_ncm: add SuperSpeed descriptors for CDC NCM Patch enables SuperSpeed for NCM gadget. Tested with USB3380 and measured TCP throughput with two Intel PCs: udc to host: 920 Mbit/s host to udc: 550 Mbit/s Signed-off-by: Jussi Kivilinna Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_ncm.c | 82 ++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 97f0a9bc84df..08cff495195f 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -90,7 +90,9 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f) /* peak (theoretical) bulk transfer rate in bits-per-second */ static inline unsigned ncm_bitrate(struct usb_gadget *g) { - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) + return 13 * 1024 * 8 * 1000 * 8; + else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return 13 * 512 * 8 * 1000 * 8; else return 19 * 64 * 1 * 1000 * 8; @@ -333,6 +335,76 @@ static struct usb_descriptor_header *ncm_hs_function[] = { NULL, }; + +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_ncm_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT), + .bInterval = USB_MS_TO_HS_INTERVAL(NCM_STATUS_INTERVAL_MS) +}; + +static struct usb_ss_ep_comp_descriptor ss_ncm_notify_comp_desc = { + .bLength = sizeof(ss_ncm_notify_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 3 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ + .wBytesPerInterval = cpu_to_le16(NCM_STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor ss_ncm_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_ncm_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_ncm_bulk_comp_desc = { + .bLength = sizeof(ss_ncm_bulk_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + /* the following 2 values can be tweaked if necessary */ + /* .bMaxBurst = 0, */ + /* .bmAttributes = 0, */ +}; + +static struct usb_descriptor_header *ncm_ss_function[] = { + (struct usb_descriptor_header *) &ncm_iad_desc, + /* CDC NCM control descriptors */ + (struct usb_descriptor_header *) &ncm_control_intf, + (struct usb_descriptor_header *) &ncm_header_desc, + (struct usb_descriptor_header *) &ncm_union_desc, + (struct usb_descriptor_header *) &ecm_desc, + (struct usb_descriptor_header *) &ncm_desc, + (struct usb_descriptor_header *) &ss_ncm_notify_desc, + (struct usb_descriptor_header *) &ss_ncm_notify_comp_desc, + /* data interface, altsettings 0 and 1 */ + (struct usb_descriptor_header *) &ncm_data_nop_intf, + (struct usb_descriptor_header *) &ncm_data_intf, + (struct usb_descriptor_header *) &ss_ncm_in_desc, + (struct usb_descriptor_header *) &ss_ncm_bulk_comp_desc, + (struct usb_descriptor_header *) &ss_ncm_out_desc, + (struct usb_descriptor_header *) &ss_ncm_bulk_comp_desc, + NULL, +}; + /* string descriptors: */ #define STRING_CTRL_IDX 0 @@ -1431,8 +1503,13 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) hs_ncm_notify_desc.bEndpointAddress = fs_ncm_notify_desc.bEndpointAddress; + ss_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress; + ss_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress; + ss_ncm_notify_desc.bEndpointAddress = + fs_ncm_notify_desc.bEndpointAddress; + status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function, - NULL, NULL); + ncm_ss_function, NULL); if (status) goto fail; @@ -1450,6 +1527,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm->task_timer.function = ncm_tx_timeout; DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n", + gadget_is_superspeed(c->cdev->gadget) ? "super" : gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", ncm->port.in_ep->name, ncm->port.out_ep->name, ncm->notify->name); From 1de2ebfb8cd522ad7d0deae94ae47592f975e017 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 12 Aug 2016 17:29:34 +0300 Subject: [PATCH 081/343] usb: gadget: net2280: fix infinite loop in irq handler With SuperSpeed CDC NCM gadget, net2280 would get stuck in 'handle_ep_small' function. Triggering issue requires large TCP transfer from host to USB3380. Patch adds check for stuck condition and prevents hard lockup. Signed-off-by: Jussi Kivilinna Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 40 +++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 614ab951a4ae..cd876bff5106 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1137,8 +1137,10 @@ dma_done(struct net2280_ep *ep, struct net2280_request *req, u32 dmacount, done(ep, req, status); } -static void scan_dma_completions(struct net2280_ep *ep) +static int scan_dma_completions(struct net2280_ep *ep) { + int num_completed = 0; + /* only look at descriptors that were "naturally" retired, * so fifo and list head state won't matter */ @@ -1166,6 +1168,7 @@ static void scan_dma_completions(struct net2280_ep *ep) break; /* single transfer mode */ dma_done(ep, req, tmp, 0); + num_completed++; break; } else if (!ep->is_in && (req->req.length % ep->ep.maxpacket) && @@ -1194,7 +1197,10 @@ static void scan_dma_completions(struct net2280_ep *ep) } } dma_done(ep, req, tmp, 0); + num_completed++; } + + return num_completed; } static void restart_dma(struct net2280_ep *ep) @@ -2547,8 +2553,11 @@ static void handle_ep_small(struct net2280_ep *ep) /* manual DMA queue advance after short OUT */ if (likely(ep->dma)) { if (t & BIT(SHORT_PACKET_TRANSFERRED_INTERRUPT)) { - u32 count; + struct net2280_request *stuck_req = NULL; int stopped = ep->stopped; + int num_completed; + int stuck = 0; + u32 count; /* TRANSFERRED works around OUT_DONE erratum 0112. * we expect (N <= maxpacket) bytes; host wrote M. @@ -2560,7 +2569,7 @@ static void handle_ep_small(struct net2280_ep *ep) /* any preceding dma transfers must finish. * dma handles (M >= N), may empty the queue */ - scan_dma_completions(ep); + num_completed = scan_dma_completions(ep); if (unlikely(list_empty(&ep->queue) || ep->out_overflow)) { req = NULL; @@ -2580,6 +2589,31 @@ static void handle_ep_small(struct net2280_ep *ep) req = NULL; break; } + + /* Escape loop if no dma transfers completed + * after few retries. + */ + if (num_completed == 0) { + if (stuck_req == req && + readl(&ep->dma->dmadesc) != + req->td_dma && stuck++ > 5) { + count = readl( + &ep->dma->dmacount); + count &= DMA_BYTE_COUNT_MASK; + req = NULL; + ep_dbg(ep->dev, "%s escape stuck %d, count %u\n", + ep->ep.name, stuck, + count); + break; + } else if (stuck_req != req) { + stuck_req = req; + stuck = 0; + } + } else { + stuck_req = NULL; + stuck = 0; + } + udelay(1); } From 17f6ed62b0dbe58ca9f527d87612de04ed2cce8b Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 12 Aug 2016 17:29:35 +0300 Subject: [PATCH 082/343] usb: gadget: net2280: match interrupt endpoints to PIO endpoints and DMA to bulk With composite gadget (ACM + NCM), USB3380 to host TCP transfer speed dropped to 150 Mbit/s compared to 900 Mbit/s with NCM gadget. Problem seems to be that net2280/USB3380 has only four DMA channels and those DMA channels are allocated to first HW endpoints. Endpoint match function was mapping endpoint names directly, so NCM did not get DMA for bulk endpoints. This patch changed match_ep to prefer DMA enabled hw endpoints for bulk usb endpoints and PIO for interrupt usb endpoints. Signed-off-by: Jussi Kivilinna Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index cd876bff5106..a28eb87078ae 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1573,6 +1573,44 @@ static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget, return ep; } + /* USB3380: Only first four endpoints have DMA channels. Allocate + * slower interrupt endpoints from PIO hw endpoints, to allow bulk/isoc + * endpoints use DMA hw endpoints. + */ + if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT && + usb_endpoint_dir_in(desc)) { + ep = gadget_find_ep_by_name(_gadget, "ep2in"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + ep = gadget_find_ep_by_name(_gadget, "ep4in"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + } else if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT && + !usb_endpoint_dir_in(desc)) { + ep = gadget_find_ep_by_name(_gadget, "ep1out"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + ep = gadget_find_ep_by_name(_gadget, "ep3out"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + } else if (usb_endpoint_type(desc) != USB_ENDPOINT_XFER_BULK && + usb_endpoint_dir_in(desc)) { + ep = gadget_find_ep_by_name(_gadget, "ep1in"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + ep = gadget_find_ep_by_name(_gadget, "ep3in"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + } else if (usb_endpoint_type(desc) != USB_ENDPOINT_XFER_BULK && + !usb_endpoint_dir_in(desc)) { + ep = gadget_find_ep_by_name(_gadget, "ep2out"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + ep = gadget_find_ep_by_name(_gadget, "ep4out"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + } + /* USB3380: use same address for usb and hardware endpoints */ snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), usb_endpoint_dir_in(desc) ? "in" : "out"); From 16199f33893922db8de8d3460384291b853051ec Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 16 Aug 2016 22:44:37 +0800 Subject: [PATCH 083/343] usb: dwc3: add dis_u2_freeclk_exists_quirk Add a quirk to clear the GUSB2PHYCFG.U2_FREECLK_EXISTS bit, which specifies whether the USB2.0 PHY provides a free-running PHY clock, which is active when the clock control input is active. Signed-off-by: William Wu Acked-by: Rob Herring Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 3 +++ drivers/usb/dwc3/core.c | 5 +++++ drivers/usb/dwc3/core.h | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 7d7ce089b003..020b0e935fd3 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -39,6 +39,9 @@ Optional properties: disabling the suspend signal to the PHY. - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection in PHY P3 power state. + - snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists + in GUSB2PHYCFG, specify that USB2 PHY doesn't provide + a free-running PHY clock. - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal utmi_l1_suspend_n, false when asserts utmi_sleep_n - snps,hird-threshold: HIRD threshold diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 946643157b78..0b7bfd2cd550 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -500,6 +500,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_enblslpm_quirk) reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; + if (dwc->dis_u2_freeclk_exists_quirk) + reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); return 0; @@ -924,6 +927,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,dis_enblslpm_quirk"); dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev, "snps,dis_rxdet_inp3_quirk"); + dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev, + "snps,dis-u2-freeclk-exists-quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 1a6cc48fc7c4..08ed9e04db61 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -199,6 +199,7 @@ /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) +#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS (1 << 30) #define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) #define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4) #define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) @@ -803,6 +804,9 @@ struct dwc3_scratchpad_array { * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG, * disabling the suspend signal to the PHY. + * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists + * in GUSB2PHYCFG, specify that USB2 PHY doesn't + * provide a free-running PHY clock. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -946,6 +950,7 @@ struct dwc3 { unsigned dis_u2_susphy_quirk:1; unsigned dis_enblslpm_quirk:1; unsigned dis_rxdet_inp3_quirk:1; + unsigned dis_u2_freeclk_exists_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; From 32f2ed864dd523bca2ee804effa9f3f43aa03ba6 Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 16 Aug 2016 22:44:38 +0800 Subject: [PATCH 084/343] usb: dwc3: make usb2 phy utmi interface configurable Support to configure the UTMI+ PHY with an 8- or 16-bit interface via DT. The UTMI+ PHY interface is a hardware capability, and it's platform dependent. Normally, the PHYIF can be configured during coreconsultant. But for some specific USB cores(e.g. rk3399 SoC DWC3), the default PHYIF configuration value is false, so we need to reconfigure it by software. Signed-off-by: William Wu Acked-by: Rob Herring Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/generic.txt | 6 ++++++ drivers/usb/dwc3/core.c | 18 ++++++++++++++++++ drivers/usb/dwc3/core.h | 12 ++++++++++++ 3 files changed, 36 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/generic.txt b/Documentation/devicetree/bindings/usb/generic.txt index bba825711873..bfadeb1c3bab 100644 --- a/Documentation/devicetree/bindings/usb/generic.txt +++ b/Documentation/devicetree/bindings/usb/generic.txt @@ -11,6 +11,11 @@ Optional properties: "peripheral" and "otg". In case this attribute isn't passed via DT, USB DRD controllers should default to OTG. + - phy_type: tells USB controllers that we want to configure the core to support + a UTMI+ PHY with an 8- or 16-bit interface if UTMI+ is + selected. Valid arguments are "utmi" and "utmi_wide". + In case this isn't passed via DT, USB controllers should + default to HW capability. - otg-rev: tells usb driver the release number of the OTG and EH supplement with which the device and its descriptors are compliant, in binary-coded decimal (i.e. 2.0 is 0200H). This @@ -34,6 +39,7 @@ dwc3@4a030000 { usb-phy = <&usb2_phy>, <&usb3,phy>; maximum-speed = "super-speed"; dr_mode = "otg"; + phy_type = "utmi_wide"; otg-rev = <0x0200>; adp-disable; }; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 0b7bfd2cd550..edbca03df60c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -485,6 +485,23 @@ static int dwc3_phy_setup(struct dwc3 *dwc) break; } + switch (dwc->hsphy_mode) { + case USBPHY_INTERFACE_MODE_UTMI: + reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | + DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); + reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_8_BIT) | + DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_8_BIT); + break; + case USBPHY_INTERFACE_MODE_UTMIW: + reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK | + DWC3_GUSB2PHYCFG_USBTRDTIM_MASK); + reg |= DWC3_GUSB2PHYCFG_PHYIF(UTMI_PHYIF_16_BIT) | + DWC3_GUSB2PHYCFG_USBTRDTIM(USBTRDTIM_UTMI_16_BIT); + break; + default: + break; + } + /* * Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to * '0' during coreConsultant configuration. So default value will @@ -891,6 +908,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->dr_mode = usb_get_dr_mode(dev); + dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node); dwc->has_lpm_erratum = device_property_read_bool(dev, "snps,has-lpm-erratum"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 08ed9e04db61..cc4f55123ca8 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -203,6 +203,14 @@ #define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) #define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4) #define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) +#define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3) +#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1) +#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10) +#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK DWC3_GUSB2PHYCFG_USBTRDTIM(0xf) +#define USBTRDTIM_UTMI_8_BIT 9 +#define USBTRDTIM_UTMI_16_BIT 5 +#define UTMI_PHYIF_16_BIT 1 +#define UTMI_PHYIF_8_BIT 0 /* Global USB2 PHY Vendor Control Register */ #define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25) @@ -748,6 +756,9 @@ struct dwc3_scratchpad_array { * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents * @dr_mode: requested mode of operation + * @hsphy_mode: UTMI phy mode, one of following: + * - USBPHY_INTERFACE_MODE_UTMI + * - USBPHY_INTERFACE_MODE_UTMIW * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY * @usb2_generic_phy: pointer to USB2 PHY @@ -853,6 +864,7 @@ struct dwc3 { size_t regs_size; enum usb_dr_mode dr_mode; + enum usb_phy_interface hsphy_mode; u32 fladj; u32 irq_gadget; From 00fe081dc3a37032c05e308c40d241d60c05ebe6 Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 16 Aug 2016 22:44:39 +0800 Subject: [PATCH 085/343] usb: dwc3: add dis_del_phy_power_chg_quirk Add a quirk to clear the GUSB3PIPECTL.DELAYP1TRANS bit, which specifies whether disable delay PHY power change from P0 to P1/P2/P3 when link state changing from U0 to U1/U2/U3 respectively. Signed-off-by: William Wu Acked-by: Rob Herring Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ drivers/usb/dwc3/core.c | 5 +++++ drivers/usb/dwc3/core.h | 3 +++ 3 files changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 020b0e935fd3..e96bfc20907e 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -42,6 +42,8 @@ Optional properties: - snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists in GUSB2PHYCFG, specify that USB2 PHY doesn't provide a free-running PHY clock. + - snps,dis-del-phy-power-chg-quirk: when set core will change PHY power + from P0 to P1/P2/P3 without delay. - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal utmi_l1_suspend_n, false when asserts utmi_sleep_n - snps,hird-threshold: HIRD threshold diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index edbca03df60c..b5e0ccc2d88a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -448,6 +448,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_u3_susphy_quirk) reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + if (dwc->dis_del_phy_power_chg_quirk) + reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE; + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); @@ -947,6 +950,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,dis_rxdet_inp3_quirk"); dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev, "snps,dis-u2-freeclk-exists-quirk"); + dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev, + "snps,dis-del-phy-power-chg-quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index cc4f55123ca8..3d94acd14897 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -818,6 +818,8 @@ struct dwc3_scratchpad_array { * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists * in GUSB2PHYCFG, specify that USB2 PHY doesn't * provide a free-running PHY clock. + * @dis_del_phy_power_chg_quirk: set if we disable delay phy power + * change quirk. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk * @tx_de_emphasis: Tx de-emphasis value * 0 - -6dB de-emphasis @@ -963,6 +965,7 @@ struct dwc3 { unsigned dis_enblslpm_quirk:1; unsigned dis_rxdet_inp3_quirk:1; unsigned dis_u2_freeclk_exists_quirk:1; + unsigned dis_del_phy_power_chg_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; From 76bf85cc2c2d5af1be477a3c0d3a6bb8e67d707c Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 16 Aug 2016 22:46:41 +0800 Subject: [PATCH 086/343] usb: dwc3: rockchip: add devicetree bindings documentation This patch adds the devicetree documentation required for Rockchip USB3.0 core wrapper consisting of USB3.0 IP from Synopsys. It supports DRD mode, and could operate in device mode (SS, HS, FS) and host mode (SS, HS, FS, LS). Signed-off-by: William Wu Acked-by: Rob Herring Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/rockchip,dwc3.txt | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt new file mode 100644 index 000000000000..0536a938e3ab --- /dev/null +++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt @@ -0,0 +1,59 @@ +Rockchip SuperSpeed DWC3 USB SoC controller + +Required properties: +- compatible: should contain "rockchip,rk3399-dwc3" for rk3399 SoC +- clocks: A list of phandle + clock-specifier pairs for the + clocks listed in clock-names +- clock-names: Should contain the following: + "ref_clk" Controller reference clk, have to be 24 MHz + "suspend_clk" Controller suspend clk, have to be 24 MHz or 32 KHz + "bus_clk" Master/Core clock, have to be >= 62.5 MHz for SS + operation and >= 30MHz for HS operation + "grf_clk" Controller grf clk + +Required child node: +A child node must exist to represent the core DWC3 IP block. The name of +the node is not important. The content of the node is defined in dwc3.txt. + +Phy documentation is provided in the following places: +Documentation/devicetree/bindings/phy/rockchip,dwc3-usb-phy.txt + +Example device nodes: + + usbdrd3_0: usb@fe800000 { + compatible = "rockchip,rk3399-dwc3"; + clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>, + <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_GRF>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk", "grf_clk"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + usbdrd_dwc3_0: dwc3@fe800000 { + compatible = "snps,dwc3"; + reg = <0x0 0xfe800000 0x0 0x100000>; + interrupts = ; + dr_mode = "otg"; + status = "disabled"; + }; + }; + + usbdrd3_1: usb@fe900000 { + compatible = "rockchip,rk3399-dwc3"; + clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>, + <&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_GRF>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk", "grf_clk"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + usbdrd_dwc3_1: dwc3@fe900000 { + compatible = "snps,dwc3"; + reg = <0x0 0xfe900000 0x0 0x100000>; + interrupts = ; + dr_mode = "otg"; + status = "disabled"; + }; + }; From f652191be3f6bc997bbaf9bd4e8ec6dc96f44433 Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 16 Aug 2016 22:44:36 +0800 Subject: [PATCH 087/343] usb: dwc3: of-simple: add compatible for rockchip rk3399 Rockchip platform merely enable usb3 clocks and populate its children. So we can use this generic glue layer to support Rockchip dwc3. Signed-off-by: William Wu Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-of-simple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index e56d59b19a0e..283f9980a260 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -162,6 +162,7 @@ static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = { static const struct of_device_id of_dwc3_simple_match[] = { { .compatible = "qcom,dwc3" }, + { .compatible = "rockchip,rk3399-dwc3" }, { .compatible = "xlnx,zynqmp-dwc3" }, { /* Sentinel */ } }; From 6ac47090eef0c4358b04a974c4a5ac3d9bf44f79 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 1 Aug 2016 17:04:19 +0200 Subject: [PATCH 088/343] usb: gadget: Add per-lun inquiry string Introduce an attribute "inquiry_string" to the lun. In some environments, e. g. BIOS boot menus, the inquiry string is the only information about devices presented to the user. The default string depends on the "cdrom" bit of the first lun as well as the kernel version and allows no further customization. So without access to the client it is not obvious which gadget is active at a given point and what any of the available luns might contain. If "inquiry_string" is ignored or set to the empty string, the old behavior is preserved. Signed-off-by: Philipp Gesang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 28 +++++++++++++++----- drivers/usb/gadget/function/f_mass_storage.h | 1 + drivers/usb/gadget/function/storage_common.c | 24 +++++++++++++++++ drivers/usb/gadget/function/storage_common.h | 10 +++++++ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 2505117e88e8..8f3659b65f53 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -311,11 +311,7 @@ struct fsg_common { /* Gadget's private data. */ void *private_data; - /* - * Vendor (8 chars), product (16 chars), release (4 - * hexadecimal digits) and NUL byte - */ - char inquiry_string[8 + 16 + 4 + 1]; + char inquiry_string[INQUIRY_STRING_LEN]; struct kref ref; }; @@ -1107,7 +1103,12 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) buf[5] = 0; /* No special options */ buf[6] = 0; buf[7] = 0; - memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string); + if (curlun->inquiry_string[0]) + memcpy(buf + 8, curlun->inquiry_string, + sizeof(curlun->inquiry_string)); + else + memcpy(buf + 8, common->inquiry_string, + sizeof(common->inquiry_string)); return 36; } @@ -3209,12 +3210,27 @@ static ssize_t fsg_lun_opts_nofua_store(struct config_item *item, CONFIGFS_ATTR(fsg_lun_opts_, nofua); +static ssize_t fsg_lun_opts_inquiry_string_show(struct config_item *item, + char *page) +{ + return fsg_show_inquiry_string(to_fsg_lun_opts(item)->lun, page); +} + +static ssize_t fsg_lun_opts_inquiry_string_store(struct config_item *item, + const char *page, size_t len) +{ + return fsg_store_inquiry_string(to_fsg_lun_opts(item)->lun, page, len); +} + +CONFIGFS_ATTR(fsg_lun_opts_, inquiry_string); + static struct configfs_attribute *fsg_lun_attrs[] = { &fsg_lun_opts_attr_file, &fsg_lun_opts_attr_ro, &fsg_lun_opts_attr_removable, &fsg_lun_opts_attr_cdrom, &fsg_lun_opts_attr_nofua, + &fsg_lun_opts_attr_inquiry_string, NULL, }; diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index b6a9918eaefb..d3902313b8ac 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -100,6 +100,7 @@ struct fsg_lun_config { char removable; char cdrom; char nofua; + char inquiry_string[INQUIRY_STRING_LEN]; }; struct fsg_config { diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index 990df221c629..8fbf6861690d 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -369,6 +369,12 @@ ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) } EXPORT_SYMBOL_GPL(fsg_show_removable); +ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf) +{ + return sprintf(buf, "%s\n", curlun->inquiry_string); +} +EXPORT_SYMBOL_GPL(fsg_show_inquiry_string); + /* * The caller must hold fsg->filesem for reading when calling this function. */ @@ -499,4 +505,22 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, } EXPORT_SYMBOL_GPL(fsg_store_removable); +ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf, + size_t count) +{ + const size_t len = min(count, sizeof(curlun->inquiry_string)); + + if (len == 0 || buf[0] == '\n') { + curlun->inquiry_string[0] = 0; + } else { + snprintf(curlun->inquiry_string, + sizeof(curlun->inquiry_string), "%-28s", buf); + if (curlun->inquiry_string[len-1] == '\n') + curlun->inquiry_string[len-1] = ' '; + } + + return count; +} +EXPORT_SYMBOL_GPL(fsg_store_inquiry_string); + MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h index c3544e61da66..e69848994cb4 100644 --- a/drivers/usb/gadget/function/storage_common.h +++ b/drivers/usb/gadget/function/storage_common.h @@ -88,6 +88,12 @@ do { \ #define ASC(x) ((u8) ((x) >> 8)) #define ASCQ(x) ((u8) (x)) +/* + * Vendor (8 chars), product (16 chars), release (4 hexadecimal digits) and NUL + * byte + */ +#define INQUIRY_STRING_LEN ((size_t) (8 + 16 + 4 + 1)) + struct fsg_lun { struct file *filp; loff_t file_length; @@ -112,6 +118,7 @@ struct fsg_lun { struct device dev; const char *name; /* "lun.name" */ const char **name_pfx; /* "function.name" */ + char inquiry_string[INQUIRY_STRING_LEN]; }; static inline bool fsg_lun_is_open(struct fsg_lun *curlun) @@ -210,6 +217,7 @@ ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf); ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf); ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, char *buf); +ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf); ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf); ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf); ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, @@ -221,5 +229,7 @@ ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, const char *buf, size_t count); ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count); +ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf, + size_t count); #endif /* USB_STORAGE_COMMON_H */ From 16b114a6d7973cf027e4c2b23eae1076eaf98c25 Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Mon, 8 Aug 2016 21:30:04 +0100 Subject: [PATCH 089/343] usb: gadget: fix usb_ep_align_maybe endianness and new usb_ep_align USB spec specifies wMaxPacketSize to be little endian (as other properties), so when using this variable in the driver we should convert to the current CPU endianness if necessary. This patch also introduces usb_ep_align() which does always returns the aligned buffer size for an endpoint. This is useful to be used by USB requests allocator functions. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- include/linux/usb/gadget.h | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 612dbdfa388e..3cc93237ff98 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -417,9 +417,21 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) #define gadget_for_each_ep(tmp, gadget) \ list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) +/** + * usb_ep_align - returns @len aligned to ep's maxpacketsize. + * @ep: the endpoint whose maxpacketsize is used to align @len + * @len: buffer size's length to align to @ep's maxpacketsize + * + * This helper is used to align buffer's size to an ep's maxpacketsize. + */ +static inline size_t usb_ep_align(struct usb_ep *ep, size_t len) +{ + return round_up(len, (size_t)le16_to_cpu(ep->desc->wMaxPacketSize)); +} + /** * usb_ep_align_maybe - returns @len aligned to ep's maxpacketsize if gadget - * requires quirk_ep_out_aligned_size, otherwise reguens len. + * requires quirk_ep_out_aligned_size, otherwise returns len. * @g: controller to check for quirk * @ep: the endpoint whose maxpacketsize is used to align @len * @len: buffer size's length to align to @ep's maxpacketsize @@ -430,8 +442,7 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) static inline size_t usb_ep_align_maybe(struct usb_gadget *g, struct usb_ep *ep, size_t len) { - return !g->quirk_ep_out_aligned_size ? len : - round_up(len, (size_t)ep->desc->wMaxPacketSize); + return g->quirk_ep_out_aligned_size ? usb_ep_align(ep, len) : len; } /** From 69bb99738b5c6d56d2b1a75db9cbb4d187453c1a Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Mon, 8 Aug 2016 21:30:05 +0100 Subject: [PATCH 090/343] usb: gadget: change len to size_t on alloc_ep_req() Length of buffers should be of type size_t whenever possible. Altough recommended, this change has no real practical change, unless a driver has a uses a huge or negative buffer size - it might help find these bugs. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/u_f.c | 2 +- drivers/usb/gadget/u_f.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index 4bc7eea8bfc8..6811761fec64 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -13,7 +13,7 @@ #include "u_f.h" -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len) +struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len) { struct usb_request *req; diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 4247cc098a89..21b75710c4a4 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -48,7 +48,7 @@ struct usb_ep; struct usb_request; /* Requests allocated via alloc_ep_req() must be freed by free_ep_req(). */ -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len); +struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len); static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req) { kfree(req->buf); From e0466156ee2e944fb47a3fa00932c3698a6d2c67 Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Mon, 8 Aug 2016 21:30:06 +0100 Subject: [PATCH 091/343] usb: gadget: align buffer size when allocating for OUT endpoint Using usb_ep_align() makes sure that the buffer size for OUT endpoints is always aligned with wMaxPacketSize (512 usually). This makes sure that no buffer has the wrong size, which can cause nasty bugs. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/u_f.c | 3 +++ drivers/usb/gadget/u_f.h | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index 6811761fec64..907f8144813c 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -12,6 +12,7 @@ */ #include "u_f.h" +#include struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len) { @@ -20,6 +21,8 @@ struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len) req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (req) { req->length = len ?: default_len; + if (usb_endpoint_dir_out(ep->desc)) + req->length = usb_ep_align(ep, req->length); req->buf = kmalloc(req->length, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request(ep, req); diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 21b75710c4a4..69a1d10df04f 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -47,8 +47,22 @@ struct usb_ep; struct usb_request; -/* Requests allocated via alloc_ep_req() must be freed by free_ep_req(). */ +/** + * alloc_ep_req - returns a usb_request allocated by the gadget driver and + * allocates the request's buffer. + * + * @ep: the endpoint to allocate a usb_request + * @len: usb_requests's buffer suggested size + * @default_len: used if @len is not provided, ie, is 0 + * + * In case @ep direction is OUT, the @len will be aligned to ep's + * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use + * usb_requests's length (req->length) to refer to the allocated buffer size. + * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req(). + */ struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len); + +/* Frees a usb_request previously allocated by alloc_ep_req() */ static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req) { kfree(req->buf); From 4a655f152e7932e43356b683958200094b368d5a Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Mon, 8 Aug 2016 21:30:07 +0100 Subject: [PATCH 092/343] usb: gadget: f_midi: remove alignment code for OUT endpoint The new version of alloc_ep_req() already aligns the buffer size to wMaxPacketSize on OUT endpoints. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 58fc199a18ec..39018dea7035 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -360,9 +360,8 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* allocate a bunch of read buffers and queue them all at once. */ for (i = 0; i < midi->qlen && err == 0; i++) { struct usb_request *req = - midi_alloc_ep_req(midi->out_ep, - max_t(unsigned, midi->buflen, - bulk_out_desc.wMaxPacketSize)); + midi_alloc_ep_req(midi->out_ep, midi->buflen); + if (req == NULL) return -ENOMEM; From 7ea9fde7605c3d224ba28cd17ffd8ac408453a96 Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Mon, 8 Aug 2016 21:30:08 +0100 Subject: [PATCH 093/343] usb: gadget: f_midi: defaults buflen sizes to 512 512 is the value used by wMaxPacketSize, as specified by the USB Spec. This makes sure this driver uses, by default, the most optimal value for IN and OUT endpoint requests. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 2 +- drivers/usb/gadget/legacy/gmidi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 39018dea7035..a7b50ac947f8 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1122,7 +1122,7 @@ static struct usb_function_instance *f_midi_alloc_inst(void) opts->func_inst.free_func_inst = f_midi_free_inst; opts->index = SNDRV_DEFAULT_IDX1; opts->id = SNDRV_DEFAULT_STR1; - opts->buflen = 256; + opts->buflen = 512; opts->qlen = 32; opts->in_ports = 1; opts->out_ports = 1; diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index fc2ac150f5ff..0bf39c3ccdb1 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -47,7 +47,7 @@ static char *id = SNDRV_DEFAULT_STR1; module_param(id, charp, S_IRUGO); MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter."); -static unsigned int buflen = 256; +static unsigned int buflen = 512; module_param(buflen, uint, S_IRUGO); MODULE_PARM_DESC(buflen, "MIDI buffer length"); From f42ab18cc8aed6b5a3532c468f99285de9eabab5 Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Mon, 8 Aug 2016 21:30:09 +0100 Subject: [PATCH 094/343] usb: gadget: f_midi: refactor state machine This refactor results in a cleaner state machine code and promotes consistency, readability, and maintanability of this driver. This refactor state machine was well tested and it is currently running in production code and devices. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 204 +++++++++++++++++---------- 1 file changed, 129 insertions(+), 75 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index a7b50ac947f8..09d769e18b50 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -51,6 +51,19 @@ static const char f_midi_longname[] = "MIDI Gadget"; */ #define MAX_PORTS 16 +/* MIDI message states */ +enum { + STATE_INITIAL = 0, /* pseudo state */ + STATE_1PARAM, + STATE_2PARAM_1, + STATE_2PARAM_2, + STATE_SYSEX_0, + STATE_SYSEX_1, + STATE_SYSEX_2, + STATE_REAL_TIME, + STATE_FINISHED, /* pseudo state */ +}; + /* * This is a gadget, and the IN/OUT naming is from the host's perspective. * USB -> OUT endpoint -> rawmidi @@ -61,13 +74,6 @@ struct gmidi_in_port { int active; uint8_t cable; uint8_t state; -#define STATE_UNKNOWN 0 -#define STATE_1PARAM 1 -#define STATE_2PARAM_1 2 -#define STATE_2PARAM_2 3 -#define STATE_SYSEX_0 4 -#define STATE_SYSEX_1 5 -#define STATE_SYSEX_2 6 uint8_t data[2]; }; @@ -403,118 +409,166 @@ static int f_midi_snd_free(struct snd_device *device) return 0; } -static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0, - uint8_t p1, uint8_t p2, uint8_t p3) -{ - unsigned length = req->length; - u8 *buf = (u8 *)req->buf + length; - - buf[0] = p0; - buf[1] = p1; - buf[2] = p2; - buf[3] = p3; - req->length = length + 4; -} - /* * Converts MIDI commands to USB MIDI packets. */ static void f_midi_transmit_byte(struct usb_request *req, struct gmidi_in_port *port, uint8_t b) { - uint8_t p0 = port->cable << 4; + uint8_t p[4] = { port->cable << 4, 0, 0, 0 }; + uint8_t next_state = STATE_INITIAL; - if (b >= 0xf8) { - f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0); - } else if (b >= 0xf0) { + switch (b) { + case 0xf8 ... 0xff: + /* System Real-Time Messages */ + p[0] |= 0x0f; + p[1] = b; + next_state = port->state; + port->state = STATE_REAL_TIME; + break; + + case 0xf7: + /* End of SysEx */ + switch (port->state) { + case STATE_SYSEX_0: + p[0] |= 0x05; + p[1] = 0xf7; + next_state = STATE_FINISHED; + break; + case STATE_SYSEX_1: + p[0] |= 0x06; + p[1] = port->data[0]; + p[2] = 0xf7; + next_state = STATE_FINISHED; + break; + case STATE_SYSEX_2: + p[0] |= 0x07; + p[1] = port->data[0]; + p[2] = port->data[1]; + p[3] = 0xf7; + next_state = STATE_FINISHED; + break; + default: + /* Ignore byte */ + next_state = port->state; + port->state = STATE_INITIAL; + } + break; + + case 0xf0 ... 0xf6: + /* System Common Messages */ + port->data[0] = port->data[1] = 0; + port->state = STATE_INITIAL; switch (b) { case 0xf0: port->data[0] = b; - port->state = STATE_SYSEX_1; + port->data[1] = 0; + next_state = STATE_SYSEX_1; break; case 0xf1: case 0xf3: port->data[0] = b; - port->state = STATE_1PARAM; + next_state = STATE_1PARAM; break; case 0xf2: port->data[0] = b; - port->state = STATE_2PARAM_1; + next_state = STATE_2PARAM_1; break; case 0xf4: case 0xf5: - port->state = STATE_UNKNOWN; + next_state = STATE_INITIAL; break; case 0xf6: - f_midi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0); - port->state = STATE_UNKNOWN; - break; - case 0xf7: - switch (port->state) { - case STATE_SYSEX_0: - f_midi_transmit_packet(req, - p0 | 0x05, 0xf7, 0, 0); - break; - case STATE_SYSEX_1: - f_midi_transmit_packet(req, - p0 | 0x06, port->data[0], 0xf7, 0); - break; - case STATE_SYSEX_2: - f_midi_transmit_packet(req, - p0 | 0x07, port->data[0], - port->data[1], 0xf7); - break; - } - port->state = STATE_UNKNOWN; + p[0] |= 0x05; + p[1] = 0xf6; + next_state = STATE_FINISHED; break; } - } else if (b >= 0x80) { + break; + + case 0x80 ... 0xef: + /* + * Channel Voice Messages, Channel Mode Messages + * and Control Change Messages. + */ port->data[0] = b; + port->data[1] = 0; + port->state = STATE_INITIAL; if (b >= 0xc0 && b <= 0xdf) - port->state = STATE_1PARAM; + next_state = STATE_1PARAM; else - port->state = STATE_2PARAM_1; - } else { /* b < 0x80 */ + next_state = STATE_2PARAM_1; + break; + + case 0x00 ... 0x7f: + /* Message parameters */ switch (port->state) { case STATE_1PARAM: - if (port->data[0] < 0xf0) { - p0 |= port->data[0] >> 4; - } else { - p0 |= 0x02; - port->state = STATE_UNKNOWN; - } - f_midi_transmit_packet(req, p0, port->data[0], b, 0); + if (port->data[0] < 0xf0) + p[0] |= port->data[0] >> 4; + else + p[0] |= 0x02; + + p[1] = port->data[0]; + p[2] = b; + /* This is to allow Running State Messages */ + next_state = STATE_1PARAM; break; case STATE_2PARAM_1: port->data[1] = b; - port->state = STATE_2PARAM_2; + next_state = STATE_2PARAM_2; break; case STATE_2PARAM_2: - if (port->data[0] < 0xf0) { - p0 |= port->data[0] >> 4; - port->state = STATE_2PARAM_1; - } else { - p0 |= 0x03; - port->state = STATE_UNKNOWN; - } - f_midi_transmit_packet(req, - p0, port->data[0], port->data[1], b); + if (port->data[0] < 0xf0) + p[0] |= port->data[0] >> 4; + else + p[0] |= 0x03; + + p[1] = port->data[0]; + p[2] = port->data[1]; + p[3] = b; + /* This is to allow Running State Messages */ + next_state = STATE_2PARAM_1; break; case STATE_SYSEX_0: port->data[0] = b; - port->state = STATE_SYSEX_1; + next_state = STATE_SYSEX_1; break; case STATE_SYSEX_1: port->data[1] = b; - port->state = STATE_SYSEX_2; + next_state = STATE_SYSEX_2; break; case STATE_SYSEX_2: - f_midi_transmit_packet(req, - p0 | 0x04, port->data[0], port->data[1], b); - port->state = STATE_SYSEX_0; + p[0] |= 0x04; + p[1] = port->data[0]; + p[2] = port->data[1]; + p[3] = b; + next_state = STATE_SYSEX_0; break; } + break; } + + /* States where we have to write into the USB request */ + if (next_state == STATE_FINISHED || + port->state == STATE_SYSEX_2 || + port->state == STATE_1PARAM || + port->state == STATE_2PARAM_2 || + port->state == STATE_REAL_TIME) { + + unsigned int length = req->length; + u8 *buf = (u8 *)req->buf + length; + + memcpy(buf, p, sizeof(p)); + req->length = length + sizeof(p); + + if (next_state == STATE_FINISHED) { + next_state = STATE_INITIAL; + port->data[0] = port->data[1] = 0; + } + } + + port->state = next_state; } static void f_midi_drop_out_substreams(struct f_midi *midi) @@ -641,7 +695,7 @@ static int f_midi_in_open(struct snd_rawmidi_substream *substream) VDBG(midi, "%s()\n", __func__); port = midi->in_ports_array + substream->number; port->substream = substream; - port->state = STATE_UNKNOWN; + port->state = STATE_INITIAL; return 0; } From f8ca46aeb7b422b8c22e286e25269e4fefc560bd Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Mon, 8 Aug 2016 21:30:10 +0100 Subject: [PATCH 095/343] usb: gadget: f_midi: drop substreams when disabling endpoint This change makes sure that the ALSA buffers are cleaned if an endpoint becomes disabled. Before this change, if the internal ALSA buffer did overflow, the MIDI function would stop sending MIDI to the host. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 09d769e18b50..3a47596afcab 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -305,6 +305,19 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req) } } +static void f_midi_drop_out_substreams(struct f_midi *midi) +{ + unsigned int i; + + for (i = 0; i < midi->in_ports; i++) { + struct gmidi_in_port *port = midi->in_ports_array + i; + struct snd_rawmidi_substream *substream = port->substream; + + if (port->active && substream) + snd_rawmidi_drop_output(substream); + } +} + static int f_midi_start_ep(struct f_midi *midi, struct usb_function *f, struct usb_ep *ep) @@ -402,6 +415,8 @@ static void f_midi_disable(struct usb_function *f) /* release IN requests */ while (kfifo_get(&midi->in_req_fifo, &req)) free_ep_req(midi->in_ep, req); + + f_midi_drop_out_substreams(midi); } static int f_midi_snd_free(struct snd_device *device) @@ -571,18 +586,6 @@ static void f_midi_transmit_byte(struct usb_request *req, port->state = next_state; } -static void f_midi_drop_out_substreams(struct f_midi *midi) -{ - unsigned int i; - - for (i = 0; i < midi->in_ports; i++) { - struct gmidi_in_port *port = midi->in_ports_array + i; - struct snd_rawmidi_substream *substream = port->substream; - if (port->active && substream) - snd_rawmidi_drop_output(substream); - } -} - static int f_midi_do_transmit(struct f_midi *midi, struct usb_ep *ep) { struct usb_request *req = NULL; From 00af62330c39a6c88615a08e7f9d068944e4af69 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Fri, 15 Jul 2016 17:13:27 +0800 Subject: [PATCH 096/343] usb: dwc3: core: Move the mode setting to the right place When dwc3 core enters into suspend mode, the system (especially for mobile device) may power off the dwc3 controller for power saving, that will cause dwc3 controller lost the mode operation when resuming dwc3 core. Thus we can move the mode setting into dwc3_core_init() function to avoid this issue. Signed-off-by: Baolin Wang Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b5e0ccc2d88a..25e424e40462 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -689,6 +689,21 @@ static int dwc3_core_init(struct dwc3 *dwc) goto err4; } + switch (dwc->dr_mode) { + case USB_DR_MODE_PERIPHERAL: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + break; + case USB_DR_MODE_HOST: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); + break; + case USB_DR_MODE_OTG: + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); + break; + default: + dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode); + break; + } + return 0; err4: @@ -786,7 +801,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); ret = dwc3_gadget_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -795,7 +809,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_HOST: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) @@ -804,7 +817,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) } break; case USB_DR_MODE_OTG: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); ret = dwc3_host_init(dwc); if (ret) { if (ret != -EPROBE_DEFER) From ed6fe1f50f0c0fdea674dfa739af50011034bdfa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Jun 2016 22:28:54 +0200 Subject: [PATCH 097/343] usb: gadget: f_hid: add dev to configfs Even if the /dev/hidg* chardev is automatically created, one has to guess which one belongs to which function. In the case of multiple HID functions, or maybe even multiple peripherals, this becomes difficult. Add the dev (with major and minor number) to configfs to allow looking up (or even creating) the right device node for each function. This file is read-only. Signed-off-by: Johannes Berg Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_hid.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 51980c50546d..4cd486600a9b 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -809,11 +809,21 @@ end: CONFIGFS_ATTR(f_hid_opts_, report_desc); +static ssize_t f_hid_opts_dev_show(struct config_item *item, char *page) +{ + struct f_hid_opts *opts = to_f_hid_opts(item); + + return sprintf(page, "%d:%d\n", major, opts->minor); +} + +CONFIGFS_ATTR_RO(f_hid_opts_, dev); + static struct configfs_attribute *hid_attrs[] = { &f_hid_opts_attr_subclass, &f_hid_opts_attr_protocol, &f_hid_opts_attr_report_length, &f_hid_opts_attr_report_desc, + &f_hid_opts_attr_dev, NULL, }; From 54dfce6d07b0391e23d006579bba488de4f7d6aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20H=C3=A4dicke?= Date: Wed, 22 Jun 2016 01:12:07 +0200 Subject: [PATCH 098/343] usb: gadget: f_fs: handle control requests not directed to interface or endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces a new FunctionFS descriptor flag named FUNCTIONFS_ALL_CTRL_RECIP. When this flag is enabled, control requests, which are not explicitly directed to an interface or endpoint, can be handled. This allows FunctionFS userspace drivers to process non-standard control requests. Signed-off-by: Felix Hädicke Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 34 +++++++++++++++++++++++++---- include/uapi/linux/usb/functionfs.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 5c8429f23a89..d7acab873836 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -98,6 +98,8 @@ static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); static void ffs_func_disable(struct usb_function *); static int ffs_func_setup(struct usb_function *, const struct usb_ctrlrequest *); +static bool ffs_func_req_match(struct usb_function *, + const struct usb_ctrlrequest *); static void ffs_func_suspend(struct usb_function *); static void ffs_func_resume(struct usb_function *); @@ -2243,7 +2245,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC | FUNCTIONFS_VIRTUAL_ADDR | - FUNCTIONFS_EVENTFD)) { + FUNCTIONFS_EVENTFD | + FUNCTIONFS_ALL_CTRL_RECIP)) { ret = -ENOSYS; goto error; } @@ -3094,8 +3097,9 @@ static int ffs_func_setup(struct usb_function *f, * handle them. All other either handled by composite or * passed to usb_configuration->setup() (if one is set). No * matter, we will handle requests directed to endpoint here - * as well (as it's straightforward) but what to do with any - * other request? + * as well (as it's straightforward). Other request recipient + * types are only handled when the user flag FUNCTIONFS_ALL_CTRL_RECIP + * is being used. */ if (ffs->state != FFS_ACTIVE) return -ENODEV; @@ -3116,7 +3120,10 @@ static int ffs_func_setup(struct usb_function *f, break; default: - return -EOPNOTSUPP; + if (func->ffs->user_flags & FUNCTIONFS_ALL_CTRL_RECIP) + ret = le16_to_cpu(creq->wIndex); + else + return -EOPNOTSUPP; } spin_lock_irqsave(&ffs->ev.waitq.lock, flags); @@ -3128,6 +3135,24 @@ static int ffs_func_setup(struct usb_function *f, return 0; } +static bool ffs_func_req_match(struct usb_function *f, + const struct usb_ctrlrequest *creq) +{ + struct ffs_function *func = ffs_func_from_usb(f); + + switch (creq->bRequestType & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + return ffs_func_revmap_intf(func, + le16_to_cpu(creq->wIndex) >= 0); + case USB_RECIP_ENDPOINT: + return ffs_func_revmap_ep(func, + le16_to_cpu(creq->wIndex) >= 0); + default: + return (bool) (func->ffs->user_flags & + FUNCTIONFS_ALL_CTRL_RECIP); + } +} + static void ffs_func_suspend(struct usb_function *f) { ENTER(); @@ -3378,6 +3403,7 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi) func->function.set_alt = ffs_func_set_alt; func->function.disable = ffs_func_disable; func->function.setup = ffs_func_setup; + func->function.req_match = ffs_func_req_match; func->function.suspend = ffs_func_suspend; func->function.resume = ffs_func_resume; func->function.free_func = ffs_free; diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h index 108dd7997014..93da4ca82dc7 100644 --- a/include/uapi/linux/usb/functionfs.h +++ b/include/uapi/linux/usb/functionfs.h @@ -21,6 +21,7 @@ enum functionfs_flags { FUNCTIONFS_HAS_MS_OS_DESC = 8, FUNCTIONFS_VIRTUAL_ADDR = 16, FUNCTIONFS_EVENTFD = 32, + FUNCTIONFS_ALL_CTRL_RECIP = 64, }; /* Descriptor of an non-audio endpoint */ From 1a00b457a5482c3822bfc0fd64c088b2dba93e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20H=C3=A4dicke?= Date: Wed, 22 Jun 2016 01:12:08 +0200 Subject: [PATCH 099/343] usb: gadget: composite: let USB functions process ctrl reqs in cfg0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It can sometimes be necessary for gadget drivers to process non-standard control requests, which host devices can send without having sent USB_REQ_SET_CONFIGURATION. Therefore, the req_match() usb_function method is enhanced with the new parameter "config0". When a USB configuration is active, this parameter is false. When a non-core control request is processed in composite_setup(), without an active configuration, req_match() of the USB functions of all available configurations which implement this function, is called with config0=true. Then the control request gets processed by the first usb_function instance whose req_match() returns true. Signed-off-by: Felix Hädicke Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 16 ++++++++++------ drivers/usb/gadget/function/f_fs.c | 9 +++++++-- drivers/usb/gadget/function/f_printer.c | 6 +++++- include/linux/usb/composite.h | 3 ++- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5ebe6af7976e..32176f779861 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1893,17 +1893,21 @@ unknown: /* functions always handle their interfaces and endpoints... * punt other recipients (other, WUSB, ...) to the current * configuration code. - * - * REVISIT it could make sense to let the composite device - * take such requests too, if that's ever needed: to work - * in config 0, etc. */ if (cdev->config) { list_for_each_entry(f, &cdev->config->functions, list) - if (f->req_match && f->req_match(f, ctrl)) + if (f->req_match && + f->req_match(f, ctrl, false)) goto try_fun_setup; - f = NULL; + } else { + struct usb_configuration *c; + list_for_each_entry(c, &cdev->configs, list) + list_for_each_entry(f, &c->functions, list) + if (f->req_match && + f->req_match(f, ctrl, true)) + goto try_fun_setup; } + f = NULL; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d7acab873836..d8f46f6233ac 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -99,7 +99,8 @@ static void ffs_func_disable(struct usb_function *); static int ffs_func_setup(struct usb_function *, const struct usb_ctrlrequest *); static bool ffs_func_req_match(struct usb_function *, - const struct usb_ctrlrequest *); + const struct usb_ctrlrequest *, + bool config0); static void ffs_func_suspend(struct usb_function *); static void ffs_func_resume(struct usb_function *); @@ -3136,10 +3137,14 @@ static int ffs_func_setup(struct usb_function *f, } static bool ffs_func_req_match(struct usb_function *f, - const struct usb_ctrlrequest *creq) + const struct usb_ctrlrequest *creq, + bool config0) { struct ffs_function *func = ffs_func_from_usb(f); + if (config0) + return false; + switch (creq->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: return ffs_func_revmap_intf(func, diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 64706a789580..0de36cda6e41 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -889,13 +889,17 @@ static void printer_soft_reset(struct printer_dev *dev) /*-------------------------------------------------------------------------*/ static bool gprinter_req_match(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) + const struct usb_ctrlrequest *ctrl, + bool config0) { struct printer_dev *dev = func_to_printer(f); u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); + if (config0) + return false; + if ((ctrl->bRequestType & USB_RECIP_MASK) != USB_RECIP_INTERFACE || (ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) return false; diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 2b81b24eb5aa..4616a49a1c2e 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -220,7 +220,8 @@ struct usb_function { int (*setup)(struct usb_function *, const struct usb_ctrlrequest *); bool (*req_match)(struct usb_function *, - const struct usb_ctrlrequest *); + const struct usb_ctrlrequest *, + bool config0); void (*suspend)(struct usb_function *); void (*resume)(struct usb_function *); From 4368c28ae7acb0744968e58c81be561b44aacd57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20H=C3=A4dicke?= Date: Wed, 22 Jun 2016 01:12:09 +0200 Subject: [PATCH 100/343] usb: gadget: f_fs: handle control requests in config 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces a new FunctionFS descriptor flag named FUNCTIONFS_CONFIG0_SETUP. When this flag is enabled, FunctionFS userspace drivers can process non-standard control requests in configuration 0. Signed-off-by: Felix Hädicke Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 5 +++-- include/uapi/linux/usb/functionfs.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d8f46f6233ac..998697bd80ac 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2247,7 +2247,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, FUNCTIONFS_HAS_MS_OS_DESC | FUNCTIONFS_VIRTUAL_ADDR | FUNCTIONFS_EVENTFD | - FUNCTIONFS_ALL_CTRL_RECIP)) { + FUNCTIONFS_ALL_CTRL_RECIP | + FUNCTIONFS_CONFIG0_SETUP)) { ret = -ENOSYS; goto error; } @@ -3142,7 +3143,7 @@ static bool ffs_func_req_match(struct usb_function *f, { struct ffs_function *func = ffs_func_from_usb(f); - if (config0) + if (config0 && !(func->ffs->user_flags & FUNCTIONFS_CONFIG0_SETUP)) return false; switch (creq->bRequestType & USB_RECIP_MASK) { diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h index 93da4ca82dc7..acc63697a0cc 100644 --- a/include/uapi/linux/usb/functionfs.h +++ b/include/uapi/linux/usb/functionfs.h @@ -22,6 +22,7 @@ enum functionfs_flags { FUNCTIONFS_VIRTUAL_ADDR = 16, FUNCTIONFS_EVENTFD = 32, FUNCTIONFS_ALL_CTRL_RECIP = 64, + FUNCTIONFS_CONFIG0_SETUP = 128, }; /* Descriptor of an non-audio endpoint */ From 512e47572f7d6c9bb43a03fee26928763447728b Mon Sep 17 00:00:00 2001 From: John Youn Date: Fri, 19 Aug 2016 11:57:52 -0700 Subject: [PATCH 101/343] usb: dwc3: Add revision numbers for the USB 3.0 IP Add revision number constants for the 3.00a and 3.10a releases. Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 3d94acd14897..002e6477d586 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -902,6 +902,8 @@ struct dwc3 { #define DWC3_REVISION_260A 0x5533260a #define DWC3_REVISION_270A 0x5533270a #define DWC3_REVISION_280A 0x5533280a +#define DWC3_REVISION_300A 0x5533300a +#define DWC3_REVISION_310A 0x5533310a /* * NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really From e51163690eaa6fd36abca2878bd6c53dcd423fd1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 18 Aug 2016 14:37:16 -0700 Subject: [PATCH 102/343] Documentation: dt: dwc3: note the supported phy-names The dwc3 driver expicitly looks for "usb2-phy" or "usb3-phy", but we never noted these names in the documentation. Acked-by: Rob Herring Signed-off-by: Brian Norris Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index e96bfc20907e..e3e6983288e3 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -13,7 +13,8 @@ Optional properties: in the array is expected to be a handle to the USB2/HS PHY and the second element is expected to be a handle to the USB3/SS PHY - phys: from the *Generic PHY* bindings - - phy-names: from the *Generic PHY* bindings + - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy" + or "usb3-phy". - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable - snps,disable_scramble_quirk: true when SW should disable data scrambling. Only really useful for FPGA builds. From da605f5f842163921f851e34402da6f5829a6328 Mon Sep 17 00:00:00 2001 From: Jaret Cantu Date: Tue, 16 Aug 2016 18:31:48 -0400 Subject: [PATCH 103/343] usb: phy: mxs: Add DT bindings to configure TX settings The TX settings can be calibrated for particular hardware. The phy is reset by Linux, so this cannot be handled by the bootloader. The TRM mentions that the maximum resistance should be used for the DN/DP calibration in order to pass USB certification. The values for the TX registers are poorly described in the TRM. The meanings of the register values were taken from another NXP-provided document: https://community.nxp.com/message/566147#comment-566912 Acked-by: Peter Chen Acked-by: Rob Herring Signed-off-by: Jaret Cantu Signed-off-by: Felipe Balbi --- .../devicetree/bindings/phy/mxs-usb-phy.txt | 10 +++ drivers/usb/phy/phy-mxs-usb.c | 61 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt b/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt index 379b84a567cc..1d25b04cd05e 100644 --- a/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/mxs-usb-phy.txt @@ -12,6 +12,16 @@ Required properties: - interrupts: Should contain phy interrupt - fsl,anatop: phandle for anatop register, it is only for imx6 SoC series +Optional properties: +- fsl,tx-cal-45-dn-ohms: Integer [30-55]. Resistance (in ohms) of switchable + high-speed trimming resistor connected in parallel with the 45 ohm resistor + that terminates the DN output signal. Default: 45 +- fsl,tx-cal-45-dp-ohms: Integer [30-55]. Resistance (in ohms) of switchable + high-speed trimming resistor connected in parallel with the 45 ohm resistor + that terminates the DP output signal. Default: 45 +- fsl,tx-d-cal: Integer [79-119]. Current trimming value (as a percentage) of + the 17.78mA TX reference current. Default: 100 + Example: usbphy1: usbphy@020c9000 { compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 00bfea01be65..0e2f1a36d315 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -27,6 +27,7 @@ #define DRIVER_NAME "mxs_phy" #define HW_USBPHY_PWD 0x00 +#define HW_USBPHY_TX 0x10 #define HW_USBPHY_CTRL 0x30 #define HW_USBPHY_CTRL_SET 0x34 #define HW_USBPHY_CTRL_CLR 0x38 @@ -38,6 +39,10 @@ #define HW_USBPHY_IP_SET 0x94 #define HW_USBPHY_IP_CLR 0x98 +#define GM_USBPHY_TX_TXCAL45DP(x) (((x) & 0xf) << 16) +#define GM_USBPHY_TX_TXCAL45DN(x) (((x) & 0xf) << 8) +#define GM_USBPHY_TX_D_CAL(x) (((x) & 0xf) << 0) + #define BM_USBPHY_CTRL_SFTRST BIT(31) #define BM_USBPHY_CTRL_CLKGATE BIT(30) #define BM_USBPHY_CTRL_OTG_ID_VALUE BIT(27) @@ -115,6 +120,12 @@ */ #define MXS_PHY_NEED_IP_FIX BIT(3) +/* Minimum and maximum values for device tree entries */ +#define MXS_PHY_TX_CAL45_MIN 30 +#define MXS_PHY_TX_CAL45_MAX 55 +#define MXS_PHY_TX_D_CAL_MIN 79 +#define MXS_PHY_TX_D_CAL_MAX 119 + struct mxs_phy_data { unsigned int flags; }; @@ -164,6 +175,8 @@ struct mxs_phy { const struct mxs_phy_data *data; struct regmap *regmap_anatop; int port_id; + u32 tx_reg_set; + u32 tx_reg_mask; }; static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy) @@ -185,6 +198,20 @@ static void mxs_phy_clock_switch_delay(void) usleep_range(300, 400); } +static void mxs_phy_tx_init(struct mxs_phy *mxs_phy) +{ + void __iomem *base = mxs_phy->phy.io_priv; + u32 phytx; + + /* Update TX register if there is anything to write */ + if (mxs_phy->tx_reg_mask) { + phytx = readl(base + HW_USBPHY_TX); + phytx &= ~mxs_phy->tx_reg_mask; + phytx |= mxs_phy->tx_reg_set; + writel(phytx, base + HW_USBPHY_TX); + } +} + static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) { int ret; @@ -214,6 +241,8 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX) writel(BM_USBPHY_IP_FIX, base + HW_USBPHY_IP_SET); + mxs_phy_tx_init(mxs_phy); + return 0; } @@ -459,6 +488,7 @@ static int mxs_phy_probe(struct platform_device *pdev) int ret; const struct of_device_id *of_id; struct device_node *np = pdev->dev.of_node; + u32 val; of_id = of_match_device(mxs_phy_dt_ids, &pdev->dev); if (!of_id) @@ -491,6 +521,37 @@ static int mxs_phy_probe(struct platform_device *pdev) } } + /* Precompute which bits of the TX register are to be updated, if any */ + if (!of_property_read_u32(np, "fsl,tx-cal-45-dn-ohms", &val) && + val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) { + /* Scale to a 4-bit value */ + val = (MXS_PHY_TX_CAL45_MAX - val) * 0xF + / (MXS_PHY_TX_CAL45_MAX - MXS_PHY_TX_CAL45_MIN); + mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DN(~0); + mxs_phy->tx_reg_set |= GM_USBPHY_TX_TXCAL45DN(val); + } + + if (!of_property_read_u32(np, "fsl,tx-cal-45-dp-ohms", &val) && + val >= MXS_PHY_TX_CAL45_MIN && val <= MXS_PHY_TX_CAL45_MAX) { + /* Scale to a 4-bit value. */ + val = (MXS_PHY_TX_CAL45_MAX - val) * 0xF + / (MXS_PHY_TX_CAL45_MAX - MXS_PHY_TX_CAL45_MIN); + mxs_phy->tx_reg_mask |= GM_USBPHY_TX_TXCAL45DP(~0); + mxs_phy->tx_reg_set |= GM_USBPHY_TX_TXCAL45DP(val); + } + + if (!of_property_read_u32(np, "fsl,tx-d-cal", &val) && + val >= MXS_PHY_TX_D_CAL_MIN && val <= MXS_PHY_TX_D_CAL_MAX) { + /* Scale to a 4-bit value. Round up the values and heavily + * weight the rounding by adding 2/3 of the denominator. + */ + val = ((MXS_PHY_TX_D_CAL_MAX - val) * 0xF + + (MXS_PHY_TX_D_CAL_MAX - MXS_PHY_TX_D_CAL_MIN) * 2/3) + / (MXS_PHY_TX_D_CAL_MAX - MXS_PHY_TX_D_CAL_MIN); + mxs_phy->tx_reg_mask |= GM_USBPHY_TX_D_CAL(~0); + mxs_phy->tx_reg_set |= GM_USBPHY_TX_D_CAL(val); + } + ret = of_alias_get_id(np, "usbphy"); if (ret < 0) dev_dbg(&pdev->dev, "failed to get alias id, errno %d\n", ret); From 06281d460fc5d8df843786341ded16d85f50dd3d Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 22 Aug 2016 15:39:13 -0700 Subject: [PATCH 104/343] usb: dwc3: Add ENDXFER command polling ENDXFER polling is available on version 3.10a and later of the DWC_usb3 (USB 3.0) controller. With this feature, the software can poll the CMDACT bit in the DEPCMD register after issuing an ENDXFER command. This feature is enabled by writing GUCTL2[14]. This feature is NOT available on the DWC_usb31 (USB 3.1) IP. Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 11 +++++++++++ drivers/usb/dwc3/core.h | 4 ++++ drivers/usb/dwc3/gadget.c | 16 +++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 25e424e40462..d6d3fa0fa528 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -704,6 +704,17 @@ static int dwc3_core_init(struct dwc3 *dwc) break; } + /* + * ENDXFER polling is available on version 3.10a and later of + * the DWC_usb3 controller. It is NOT available in the + * DWC_usb31 controller. + */ + if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg |= DWC3_GUCTL2_RST_ACTBITLATER; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } + return 0; err4: diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 002e6477d586..b2317e702f57 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -109,6 +109,7 @@ #define DWC3_GPRTBIMAP_HS1 0xc184 #define DWC3_GPRTBIMAP_FS0 0xc188 #define DWC3_GPRTBIMAP_FS1 0xc18c +#define DWC3_GUCTL2 0xc19c #define DWC3_VER_NUMBER 0xc1a0 #define DWC3_VER_TYPE 0xc1a4 @@ -288,6 +289,9 @@ #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) #define DWC3_GFLADJ_30MHZ_MASK 0x3f +/* Global User Control Register 2 */ +#define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14) + /* Device Configuration Register */ #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0288ea99c85a..161a6bfcb84e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2228,6 +2228,18 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) * * - Issue EndTransfer WITH CMDIOC bit set * - Wait 100us + * + * As of IP version 3.10a of the DWC_usb3 IP, the controller + * supports a mode to work around the above limitation. The + * software can poll the CMDACT bit in the DEPCMD register + * after issuing a EndTransfer command. This mode is enabled + * by writing GUCTL2[14]. This polling is already done in the + * dwc3_send_gadget_ep_cmd() function so if the mode is + * enabled, the EndTransfer command will have completed upon + * returning from this function and we don't need to delay for + * 100us. + * + * This mode is NOT available on the DWC_usb31 IP. */ cmd = DWC3_DEPCMD_ENDTRANSFER; @@ -2239,7 +2251,9 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force) WARN_ON_ONCE(ret); dep->resource_index = 0; dep->flags &= ~DWC3_EP_BUSY; - udelay(100); + + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) + udelay(100); } static void dwc3_stop_active_transfers(struct dwc3 *dwc) From aadbe812463f8af1751debb0eaaeec8a778d7ff1 Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Tue, 23 Aug 2016 18:24:49 +0100 Subject: [PATCH 105/343] usb: gadget: remove useless parameter in alloc_ep_req() The default_length parameter of alloc_ep_req was not really necessary and gadget drivers would almost always create an inline function to pass the same value to len and default_len. This patch removes that parameter and updates all calls to alloc_ep_req() to use the new API. Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_hid.c | 2 +- drivers/usb/gadget/function/f_loopback.c | 6 ++---- drivers/usb/gadget/function/f_midi.c | 2 +- drivers/usb/gadget/function/f_sourcesink.c | 6 ++---- drivers/usb/gadget/u_f.c | 7 +++---- drivers/usb/gadget/u_f.h | 3 +-- 6 files changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 4cd486600a9b..fa807ce7fc0e 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -365,7 +365,7 @@ static int f_hidg_open(struct inode *inode, struct file *fd) static inline struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, unsigned length) { - return alloc_ep_req(ep, length, length); + return alloc_ep_req(ep, length); } static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index 3a9f8f9c77bd..ddb8c896eaa3 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c @@ -308,9 +308,7 @@ static void disable_loopback(struct f_loopback *loop) static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len) { - struct f_loopback *loop = ep->driver_data; - - return alloc_ep_req(ep, len, loop->buflen); + return alloc_ep_req(ep, len); } static int alloc_requests(struct usb_composite_dev *cdev, @@ -333,7 +331,7 @@ static int alloc_requests(struct usb_composite_dev *cdev, if (!in_req) goto fail; - out_req = lb_alloc_ep_req(loop->out_ep, 0); + out_req = lb_alloc_ep_req(loop->out_ep, loop->buflen); if (!out_req) goto fail_in; diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 3a47596afcab..a5719f271bf0 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -211,7 +211,7 @@ static struct usb_gadget_strings *midi_strings[] = { static inline struct usb_request *midi_alloc_ep_req(struct usb_ep *ep, unsigned length) { - return alloc_ep_req(ep, length, length); + return alloc_ep_req(ep, length); } static const uint8_t f_midi_cin_length[] = { diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index df0189ddfdd5..8784fa12ea2c 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -293,9 +293,7 @@ static struct usb_gadget_strings *sourcesink_strings[] = { static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len) { - struct f_sourcesink *ss = ep->driver_data; - - return alloc_ep_req(ep, len, ss->buflen); + return alloc_ep_req(ep, len); } static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) @@ -606,7 +604,7 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, } else { ep = is_in ? ss->in_ep : ss->out_ep; qlen = ss->bulk_qlen; - size = 0; + size = ss->buflen; } for (i = 0; i < qlen; i++) { diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c index 907f8144813c..18839732c840 100644 --- a/drivers/usb/gadget/u_f.c +++ b/drivers/usb/gadget/u_f.c @@ -14,15 +14,14 @@ #include "u_f.h" #include -struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len) +struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len) { struct usb_request *req; req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (req) { - req->length = len ?: default_len; - if (usb_endpoint_dir_out(ep->desc)) - req->length = usb_ep_align(ep, req->length); + req->length = usb_endpoint_dir_out(ep->desc) ? + usb_ep_align(ep, len) : len; req->buf = kmalloc(req->length, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request(ep, req); diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 69a1d10df04f..7d53a4773d1a 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -53,14 +53,13 @@ struct usb_request; * * @ep: the endpoint to allocate a usb_request * @len: usb_requests's buffer suggested size - * @default_len: used if @len is not provided, ie, is 0 * * In case @ep direction is OUT, the @len will be aligned to ep's * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use * usb_requests's length (req->length) to refer to the allocated buffer size. * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req(). */ -struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len, int default_len); +struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len); /* Frees a usb_request previously allocated by alloc_ep_req() */ static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req) From 14794d7133d0f16b4901207a489f04e4e700166a Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Tue, 23 Aug 2016 18:24:50 +0100 Subject: [PATCH 106/343] usb: gadget: f_hid: use free_ep_req() We should always use free_ep_req() when allocating requests with alloc_ep_req(). Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_hid.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index fa807ce7fc0e..aa1c19946d10 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -677,11 +677,8 @@ fail_free_descs: usb_free_all_descriptors(f); fail: ERROR(f->config->cdev, "hidg_bind FAILED\n"); - if (hidg->req != NULL) { - kfree(hidg->req->buf); - if (hidg->in_ep != NULL) - usb_ep_free_request(hidg->in_ep, hidg->req); - } + if (hidg->req != NULL) + free_ep_req(hidg->in_ep, hidg->req); return status; } @@ -920,8 +917,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) /* disable/free request and end point */ usb_ep_disable(hidg->in_ep); - kfree(hidg->req->buf); - usb_ep_free_request(hidg->in_ep, hidg->req); + free_ep_req(hidg->in_ep, hidg->req); usb_free_all_descriptors(f); } From ba1582f22231821c57534e87b077d84adbc15dbd Mon Sep 17 00:00:00 2001 From: "Felipe F. Tonello" Date: Tue, 23 Aug 2016 18:24:51 +0100 Subject: [PATCH 107/343] usb: gadget: f_hid: use alloc_ep_req() Use gadget's framework allocation function instead of directly calling usb_ep_alloc_request(). Signed-off-by: Felipe F. Tonello Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_hid.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index aa1c19946d10..e2966f87c860 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -617,14 +617,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) /* preallocate request and buffer */ status = -ENOMEM; - hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL); + hidg->req = alloc_ep_req(hidg->in_ep, hidg->report_length); if (!hidg->req) goto fail; - hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL); - if (!hidg->req->buf) - goto fail; - /* set descriptor dynamic values */ hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; From 7ae7df4982af6aed25c5e9e71b91027a494149de Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Aug 2016 14:37:22 +0300 Subject: [PATCH 108/343] usb: dwc3: gadget: abolish trbs_left Instead, we can always rely on dwc3_calc_trbs_left() directly. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 161a6bfcb84e..104b145f506d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -886,7 +886,7 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) } static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left) + struct dwc3_request *req) { struct scatterlist *sg = req->sg; struct scatterlist *s; @@ -906,13 +906,13 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, dwc3_prepare_one_trb(dep, req, dma, length, chain, i); - if (!trbs_left--) + if (!dwc3_calc_trbs_left(dep)) break; } } static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trbs_left) + struct dwc3_request *req) { unsigned int length; dma_addr_t dma; @@ -935,21 +935,19 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, static void dwc3_prepare_trbs(struct dwc3_ep *dep) { struct dwc3_request *req, *n; - u32 trbs_left; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); - trbs_left = dwc3_calc_trbs_left(dep); - if (!trbs_left) + if (!dwc3_calc_trbs_left(dep)) return; list_for_each_entry_safe(req, n, &dep->pending_list, list) { if (req->num_pending_sgs > 0) - dwc3_prepare_one_trb_sg(dep, req, trbs_left--); + dwc3_prepare_one_trb_sg(dep, req); else - dwc3_prepare_one_trb_linear(dep, req, trbs_left--); + dwc3_prepare_one_trb_linear(dep, req); - if (!trbs_left) + if (!dwc3_calc_trbs_left(dep)) return; } } From 594e121f25689baaf1c8c9b006701e66744d5838 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 24 Aug 2016 14:38:10 +0300 Subject: [PATCH 109/343] usb: dwc3: gadget: stop kicking if we run out of space In case our TRB ring is full, we can avoid trying to kick transfers which won't start and just add requests to the queue. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 104b145f506d..37a86522fa88 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1082,6 +1082,9 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) return 0; } + if (!dwc3_calc_trbs_left(dep)) + return 0; + ret = __dwc3_gadget_kick_transfer(dep, 0); if (ret && ret != -EBUSY) dwc3_trace(trace_dwc3_gadget, From bc49d1d17dcffd38bd872a4089e86bb7b2bb7eee Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 26 Aug 2016 12:21:34 +0300 Subject: [PATCH 110/343] usb: gadget: don't couple configfs to legacy gadgets It's perfectly fine to have all configfs functions built-in while having modular legacy gadgets. Let's allow for that. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 3c3f31ceece7..2ea3fc3c41b9 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -209,25 +209,6 @@ config USB_F_PRINTER config USB_F_TCM tristate -choice - tristate "USB Gadget Drivers" - default USB_ETH - help - A Linux "Gadget Driver" talks to the USB Peripheral Controller - driver through the abstract "gadget" API. Some other operating - systems call these "client" drivers, of which "class drivers" - are a subset (implementing a USB device class specification). - A gadget driver implements one or more USB functions using - the peripheral hardware. - - Gadget drivers are hardware-neutral, or "platform independent", - except that they sometimes must understand quirks or limitations - of the particular controllers they work with. For example, when - a controller doesn't support alternate configurations or provide - enough of the right types of endpoints, the gadget driver might - not be able work with that controller, or might need to implement - a less common variant of a device class protocol. - # this first set of drivers all depend on bulk-capable hardware. config USB_CONFIGFS @@ -475,6 +456,25 @@ config USB_CONFIGFS_F_TCM Both protocols can work on USB2.0 and USB3.0. UAS utilizes the USB 3.0 feature called streams support. +choice + tristate "USB Gadget Drivers" + default USB_ETH + help + A Linux "Gadget Driver" talks to the USB Peripheral Controller + driver through the abstract "gadget" API. Some other operating + systems call these "client" drivers, of which "class drivers" + are a subset (implementing a USB device class specification). + A gadget driver implements one or more USB functions using + the peripheral hardware. + + Gadget drivers are hardware-neutral, or "platform independent", + except that they sometimes must understand quirks or limitations + of the particular controllers they work with. For example, when + a controller doesn't support alternate configurations or provide + enough of the right types of endpoints, the gadget driver might + not be able work with that controller, or might need to implement + a less common variant of a device class protocol. + source "drivers/usb/gadget/legacy/Kconfig" endchoice From 7eee236c3818023d65502b59f1affe153eba3073 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 28 Aug 2016 12:16:19 +0100 Subject: [PATCH 111/343] usb: phy: ab8500-usb: fix spelling mistake "regester" -> "register" Trivial fix to spelling mistakes in dev_err messages. Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-ab8500-usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 0c912d3950a5..a03caf4b1327 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -1248,7 +1248,7 @@ static void ab8500_usb_set_ab8500_tuning_values(struct ab8500_usb *ab) err = abx500_set_register_interruptible(ab->dev, AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x78); if (err < 0) - dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n", + dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n", err); /* Switch to normal mode/disable Bank 0x12 access */ @@ -1290,7 +1290,7 @@ static void ab8500_usb_set_ab8505_tuning_values(struct ab8500_usb *ab) 0xFC, 0x80); if (err < 0) - dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n", + dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n", err); /* Switch to normal mode/disable Bank 0x12 access */ @@ -1321,7 +1321,7 @@ static void ab8500_usb_set_ab8540_tuning_values(struct ab8500_usb *ab) err = abx500_set_register_interruptible(ab->dev, AB8540_DEBUG, AB8500_USB_PHY_TUNE3, 0x90); if (err < 0) - dev_err(ab->dev, "Failed to set PHY_TUNE3 regester ret=%d\n", + dev_err(ab->dev, "Failed to set PHY_TUNE3 register ret=%d\n", err); } @@ -1351,7 +1351,7 @@ static void ab8500_usb_set_ab9540_tuning_values(struct ab8500_usb *ab) err = abx500_set_register_interruptible(ab->dev, AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x80); if (err < 0) - dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n", + dev_err(ab->dev, "Failed to set PHY_TUNE3 register err=%d\n", err); /* Switch to normal mode/disable Bank 0x12 access */ From 8bae0f8c3aa98ea2eb15c0430de5f2d58c9006bb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:02 +0200 Subject: [PATCH 112/343] usb: dwc2: gadget: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index af46adfae41c..2ff03ae08e14 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3908,17 +3908,13 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); - if (!hsotg->ctrl_buff) { - dev_err(dev, "failed to allocate ctrl request buff\n"); + if (!hsotg->ctrl_buff) return -ENOMEM; - } hsotg->ep0_buff = devm_kzalloc(hsotg->dev, DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); - if (!hsotg->ep0_buff) { - dev_err(dev, "failed to allocate ctrl reply buff\n"); + if (!hsotg->ep0_buff) return -ENOMEM; - } ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED, dev_name(hsotg->dev), hsotg); From b8246caf895ed99c365585c11f5b5627653b2756 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:03 +0200 Subject: [PATCH 113/343] usb: gadget: udc: fsl_qe_udc: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_qe_udc.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index cf8819a5c5b2..9d6b2c8eed42 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -421,10 +421,8 @@ static int qe_ep_rxbd_update(struct qe_ep *ep) bd = ep->rxbase; ep->rxframe = kmalloc(sizeof(*ep->rxframe), GFP_ATOMIC); - if (ep->rxframe == NULL) { - dev_err(ep->udc->dev, "malloc rxframe failed\n"); + if (!ep->rxframe) return -ENOMEM; - } qe_frame_init(ep->rxframe); @@ -435,9 +433,7 @@ static int qe_ep_rxbd_update(struct qe_ep *ep) size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (bdring_len + 1); ep->rxbuffer = kzalloc(size, GFP_ATOMIC); - if (ep->rxbuffer == NULL) { - dev_err(ep->udc->dev, "malloc rxbuffer failed,size=%d\n", - size); + if (!ep->rxbuffer) { kfree(ep->rxframe); return -ENOMEM; } @@ -668,10 +664,8 @@ static int qe_ep_init(struct qe_udc *udc, if ((ep->tm == USBP_TM_CTL) || (ep->dir == USB_DIR_IN)) { ep->txframe = kmalloc(sizeof(*ep->txframe), GFP_ATOMIC); - if (ep->txframe == NULL) { - dev_err(udc->dev, "malloc txframe failed\n"); + if (!ep->txframe) goto en_done2; - } qe_frame_init(ep->txframe); } @@ -2347,10 +2341,8 @@ static struct qe_udc *qe_udc_config(struct platform_device *ofdev) u32 offset; udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (udc == NULL) { - dev_err(&ofdev->dev, "malloc udc failed\n"); + if (!udc) goto cleanup; - } udc->dev = &ofdev->dev; From 1a7c1d58c60cbd3a7b41e894108cf4c401fa7b33 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:04 +0200 Subject: [PATCH 114/343] usb: gadget: udc: goku_udc: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/goku_udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index d2205d9e0c8b..1400415fe67a 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -1767,8 +1767,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* alloc, and start init */ dev = kzalloc (sizeof *dev, GFP_KERNEL); - if (dev == NULL){ - pr_debug("enomem %s\n", pci_name(pdev)); + if (!dev) { retval = -ENOMEM; goto err; } From c4d6618e882c64ed43a8d5bd58f9cd6b4810cef1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:05 +0200 Subject: [PATCH 115/343] usb: gadget: udc: udc-xilinx: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/udc-xilinx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index f8bf290f1894..588e2531b8b8 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -973,10 +973,8 @@ static struct usb_request *xudc_ep_alloc_request(struct usb_ep *_ep, udc = ep->udc; req = kzalloc(sizeof(*req), gfp_flags); - if (!req) { - dev_err(udc->dev, "%s:not enough memory", __func__); + if (!req) return NULL; - } req->ep = ep; INIT_LIST_HEAD(&req->queue); From cb73db7d719b29e944e1394808fc5891604b908a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:28 +0200 Subject: [PATCH 116/343] usb: renesas_usbhs: mod_gadget: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 92bc83b92d10..8e326ac00c9f 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -335,7 +335,6 @@ static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv, buf = kmalloc(sizeof(*buf), GFP_ATOMIC); if (!buf) { usb_ep_free_request(&dcp->ep, req); - dev_err(dev, "recip data allocation fail\n"); return; } @@ -1062,14 +1061,11 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) int ret; gpriv = kzalloc(sizeof(struct usbhsg_gpriv), GFP_KERNEL); - if (!gpriv) { - dev_err(dev, "Could not allocate gadget priv\n"); + if (!gpriv) return -ENOMEM; - } uep = kzalloc(sizeof(struct usbhsg_uep) * pipe_size, GFP_KERNEL); if (!uep) { - dev_err(dev, "Could not allocate ep\n"); ret = -ENOMEM; goto usbhs_mod_gadget_probe_err_gpriv; } From 22184917ab61e97ce5f0025027d414ce33edc752 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:29 +0200 Subject: [PATCH 117/343] usb: renesas_usbhs: mod_host: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_host.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 3bf0b72eb359..165e81bfd93a 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -166,14 +166,10 @@ static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, gfp_t mem_flags) { struct usbhsh_request *ureq; - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); - if (!ureq) { - dev_err(dev, "ureq alloc fail\n"); + if (!ureq) return NULL; - } usbhs_pkt_init(&ureq->pkt); ureq->urb = urb; @@ -388,10 +384,8 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, unsigned long flags; uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); - if (!uep) { - dev_err(dev, "usbhsh_ep alloc fail\n"); + if (!uep) return -ENOMEM; - } /******************** spin lock ********************/ usbhs_lock(priv, flags); From 01da51981d0e80ef6ccc44e48a278f70a88f6187 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:30 +0200 Subject: [PATCH 118/343] usb: renesas_usbhs: pipe: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/pipe.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index c238772b9e9e..9396a8c14af8 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -804,10 +804,8 @@ int usbhs_pipe_probe(struct usbhs_priv *priv) } info->pipe = kzalloc(sizeof(struct usbhs_pipe) * pipe_size, GFP_KERNEL); - if (!info->pipe) { - dev_err(dev, "Could not allocate pipe\n"); + if (!info->pipe) return -ENOMEM; - } info->size = pipe_size; From 2a334cfaf393187d592999d1039135e000a68e9a Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Fri, 26 Aug 2016 03:06:02 +0300 Subject: [PATCH 119/343] usb: gadget: goku_udc: fix memory leak in goku_probe() Memory allocated for goku_udc device is not deallocated at error paths in goku_probe(), because gadget_release() destructor is not registered yet. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/goku_udc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 1400415fe67a..5107987bd353 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -1838,6 +1838,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) err: if (dev) goku_remove (pdev); + /* gadget_release is not registered yet, kfree explicitly */ + kfree(dev); return retval; } From 1328f7b928e3fc41e019903a56d7253b04d7e4de Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2016 11:25:09 -0400 Subject: [PATCH 120/343] usbip: vudc: Fix apparent cut-n-paste error Coverity picked up that this looks like a cut-n-paste from an almost identical sequence below that didn't get its variable renamed. Signed-off-by: Dave Jones Reviewed-by: Krzysztof Opasiak Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vudc_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c index 8994a13819ab..7091848df6c8 100644 --- a/drivers/usb/usbip/vudc_dev.c +++ b/drivers/usb/usbip/vudc_dev.c @@ -450,7 +450,7 @@ static void vudc_shutdown(struct usbip_device *ud) if (ud->tcp_socket) kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); - if (ud->tcp_tx) { + if (ud->tcp_rx) { kthread_stop_put(ud->tcp_rx); ud->tcp_rx = NULL; } From 832fbe077cb4aacfb965adfe3d973056a012fb76 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:37 +0200 Subject: [PATCH 121/343] media: dvb-frontends: rtl2832_sdr: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb-frontends/rtl2832_sdr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 6e22af36b637..e038e886731b 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -392,7 +392,6 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_dev *dev) dev_dbg(&pdev->dev, "alloc urb=%d\n", i); dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!dev->urb_list[i]) { - dev_dbg(&pdev->dev, "failed\n"); for (j = 0; j < i; j++) usb_free_urb(dev->urb_list[j]); return -ENOMEM; From 9b8c2b68f16d509ba04018c4729fa4df4e729329 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:38 +0200 Subject: [PATCH 122/343] media: radio: si470x: radio-si470x-usb: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/radio/si470x/radio-si470x-usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 091d793f6583..4b132c29f290 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -627,7 +627,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!radio->int_in_urb) { - dev_info(&intf->dev, "could not allocate int_in_urb"); retval = -ENOMEM; goto err_intbuffer; } From 75ee1cb92b0027cd27b433a011929c749b0bd894 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:39 +0200 Subject: [PATCH 123/343] media: rc: imon: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/imon.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 65f80b8b9f7a..86cc70fe2534 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2211,16 +2211,11 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf, goto exit; } rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rx_urb) { - dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__); + if (!rx_urb) goto rx_urb_alloc_failed; - } tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!tx_urb) { - dev_err(dev, "%s: usb_alloc_urb failed for display urb", - __func__); + if (!tx_urb) goto tx_urb_alloc_failed; - } mutex_init(&ictx->lock); spin_lock_init(&ictx->kc_lock); @@ -2305,10 +2300,8 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, int ret = -ENOMEM; rx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rx_urb) { - pr_err("usb_alloc_urb failed for IR urb\n"); + if (!rx_urb) goto rx_urb_alloc_failed; - } mutex_lock(&ictx->lock); From 5414c2d6afac4d3037fb204b8806250f983e05da Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:40 +0200 Subject: [PATCH 124/343] media: rc: redrat3: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/redrat3.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 399f44d89a29..ec8016d9b009 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -970,10 +970,8 @@ static int redrat3_dev_probe(struct usb_interface *intf, /* set up bulk-in endpoint */ rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rr3->read_urb) { - dev_err(dev, "Read urb allocation failure\n"); + if (!rr3->read_urb) goto error; - } rr3->ep_in = ep_in; rr3->bulk_in_buf = usb_alloc_coherent(udev, From 05476e6469740fd961bc3a3665cf2ff52548e41b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:41 +0200 Subject: [PATCH 125/343] media: usb: airspy: airspy: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/airspy/airspy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index fe031b06935f..3c556ee306cd 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -426,7 +426,6 @@ static int airspy_alloc_urbs(struct airspy *s) dev_dbg(s->dev, "alloc urb=%d\n", i); s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!s->urb_list[i]) { - dev_dbg(s->dev, "failed\n"); for (j = 0; j < i; j++) usb_free_urb(s->urb_list[j]); return -ENOMEM; From 0f578d7cc67a124b3e5e8338c51f8c1e11aeb3f0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:42 +0200 Subject: [PATCH 126/343] media: usb: as102: as102_usb_drv: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/as102/as102_usb_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c index 0e8030c071b8..68c3a80ce349 100644 --- a/drivers/media/usb/as102/as102_usb_drv.c +++ b/drivers/media/usb/as102/as102_usb_drv.c @@ -270,8 +270,6 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) urb = usb_alloc_urb(0, GFP_ATOMIC); if (urb == NULL) { - dev_dbg(&dev->bus_adap.usb_dev->dev, - "%s: usb_alloc_urb failed\n", __func__); as102_free_usb_stream_buffer(dev); return -ENOMEM; } From b4d920de70cb19960e6da688cda2b4c1e0ab4ff8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:43 +0200 Subject: [PATCH 127/343] media: usb: au0828: au0828-video: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/au0828/au0828-video.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 82b026985868..13b8387082f2 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -245,7 +245,6 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { urb = usb_alloc_urb(max_packets, GFP_KERNEL); if (!urb) { - au0828_isocdbg("cannot alloc isoc_ctl.urb %i\n", i); au0828_uninit_isoc(dev); return -ENOMEM; } From d41b2d5d4696ca4ba9968211d7dc24eac69964f5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:44 +0200 Subject: [PATCH 128/343] media: usb: cpia2: cpia2_usb: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/cpia2/cpia2_usb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index c1aa1ab2ece9..13620cdf0599 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -662,7 +662,6 @@ static int submit_urbs(struct camera_data *cam) } urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); if (!urb) { - ERR("%s: usb_alloc_urb error!\n", __func__); for (j = 0; j < i; j++) usb_free_urb(cam->sbuf[j].urb); return -ENOMEM; From 1fbfc53cddf47d61c5cfb7c7dc786b8eef52bfe0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:45 +0200 Subject: [PATCH 129/343] media: usb: cx231xx: cx231xx-audio: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/cx231xx/cx231xx-audio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index a6a9508418f8..4cd5fa91612f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -293,7 +293,6 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev) memset(dev->adev.transfer_buffer[i], 0x80, sb_size); urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC); if (!urb) { - dev_err(dev->dev, "usb_alloc_urb failed!\n"); for (j = 0; j < i; j++) { usb_free_urb(dev->adev.urb[j]); kfree(dev->adev.transfer_buffer[j]); @@ -355,7 +354,6 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev) memset(dev->adev.transfer_buffer[i], 0x80, sb_size); urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); if (!urb) { - dev_err(dev->dev, "usb_alloc_urb failed!\n"); for (j = 0; j < i; j++) { usb_free_urb(dev->adev.urb[j]); kfree(dev->adev.transfer_buffer[j]); From 15c0709119030ada50f279774170779d7260cb60 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:46 +0200 Subject: [PATCH 130/343] media: usb: cx231xx: cx231xx-core: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/cx231xx/cx231xx-core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 630f4fc5155f..8ec05cb306d8 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -1035,8 +1035,6 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets, for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) { urb = usb_alloc_urb(max_packets, GFP_KERNEL); if (!urb) { - dev_err(dev->dev, - "cannot alloc isoc_ctl.urb %i\n", i); cx231xx_uninit_isoc(dev); return -ENOMEM; } @@ -1172,8 +1170,6 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) { urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { - dev_err(dev->dev, - "cannot alloc bulk_ctl.urb %i\n", i); cx231xx_uninit_bulk(dev); return -ENOMEM; } From 91fb3ee6f390832f6992b5aade1064102e0dd613 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:47 +0200 Subject: [PATCH 131/343] media: usb: cx231xx: cx231xx-vbi: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/cx231xx/cx231xx-vbi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 15bb573b78ac..76e901920f6f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -442,8 +442,6 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { - dev_err(dev->dev, - "cannot alloc bulk_ctl.urb %i\n", i); cx231xx_uninit_vbi_isoc(dev); return -ENOMEM; } From 5cdf8c34948e8b16fb05913a9c6d3c0be23b7e0c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:48 +0200 Subject: [PATCH 132/343] media: usb: dvb-usb: dib0700_core: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/dvb-usb/dib0700_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index bf890c3d9cda..26797979ebce 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -783,10 +783,8 @@ int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ purb = usb_alloc_urb(0, GFP_KERNEL); - if (purb == NULL) { - err("rc usb alloc urb failed"); + if (purb == NULL) return -ENOMEM; - } purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL); if (purb->transfer_buffer == NULL) { From 47cb39ebcf24907dec40a815ddd09e990bb75a7a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:49 +0200 Subject: [PATCH 133/343] media: usb: em28xx: em28xx-audio: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/em28xx/em28xx-audio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 49a5f9532bd8..78f3687772bf 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -850,7 +850,6 @@ static int em28xx_audio_urb_init(struct em28xx *dev) urb = usb_alloc_urb(npackets, GFP_ATOMIC); if (!urb) { - em28xx_errdev("usb_alloc_urb failed!\n"); em28xx_audio_free_urb(dev); return -ENOMEM; } From 9ebaee44a6c16487d5147eb15d858dee929b4fc1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:50 +0200 Subject: [PATCH 134/343] media: usb: em28xx: em28xx-core: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/em28xx/em28xx-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 37456079f490..eebd5d7088d0 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -934,7 +934,6 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, for (i = 0; i < usb_bufs->num_bufs; i++) { urb = usb_alloc_urb(usb_bufs->num_packets, GFP_KERNEL); if (!urb) { - em28xx_err("cannot alloc usb_ctl.urb %i\n", i); em28xx_uninit_usb_xfer(dev, mode); return -ENOMEM; } From 37fac9692fb06b4b58640b42c734671dbdcf0746 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:51 +0200 Subject: [PATCH 135/343] media: usb: gspca: benq: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/gspca/benq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/gspca/benq.c b/drivers/media/usb/gspca/benq.c index 790baed33963..5fa67b78ad49 100644 --- a/drivers/media/usb/gspca/benq.c +++ b/drivers/media/usb/gspca/benq.c @@ -95,10 +95,8 @@ static int sd_start(struct gspca_dev *gspca_dev) #define SD_NPKT 32 for (n = 0; n < 4; n++) { urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); - if (!urb) { - pr_err("usb_alloc_urb failed\n"); + if (!urb) return -ENOMEM; - } gspca_dev->urb[n] = urb; urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, SD_PKT_SZ * SD_NPKT, From b2a057b053514705c2d7b09b990def715c7f7ed8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:52 +0200 Subject: [PATCH 136/343] media: usb: gspca: gspca: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/gspca/gspca.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index b17bd7ebcb47..af2395a76d8b 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -795,10 +795,8 @@ static int create_urbs(struct gspca_dev *gspca_dev, for (n = 0; n < nurbs; n++) { urb = usb_alloc_urb(npkt, GFP_KERNEL); - if (!urb) { - pr_err("usb_alloc_urb failed\n"); + if (!urb) return -ENOMEM; - } gspca_dev->urb[n] = urb; urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, bsize, From e8407a5995fed4e9fa66397808f1f2060ecf9e65 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:53 +0200 Subject: [PATCH 137/343] media: usb: gspca: konica: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/gspca/konica.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c index 0712b1bc90b4..40aaaa9c5f30 100644 --- a/drivers/media/usb/gspca/konica.c +++ b/drivers/media/usb/gspca/konica.c @@ -208,10 +208,8 @@ static int sd_start(struct gspca_dev *gspca_dev) packet_size = le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize); urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL); - if (!urb) { - pr_err("usb_alloc_urb failed\n"); + if (!urb) return -ENOMEM; - } gspca_dev->urb[n] = urb; urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev, packet_size * SD_NPKT, From 604f517e46b1c04185e18d6ec1bc224b4032c5c8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:54 +0200 Subject: [PATCH 138/343] media: usb: hackrf: hackrf: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/hackrf/hackrf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index b1e229a44192..c2c8d12e9498 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -691,7 +691,6 @@ static int hackrf_alloc_urbs(struct hackrf_dev *dev, bool rcv) dev_dbg(dev->dev, "alloc urb=%d\n", i); dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!dev->urb_list[i]) { - dev_dbg(dev->dev, "failed\n"); for (j = 0; j < i; j++) usb_free_urb(dev->urb_list[j]); return -ENOMEM; From 908316624fba7be9fc3ff25ab457a9d1b194b404 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:55 +0200 Subject: [PATCH 139/343] media: usb: hdpvr: hdpvr-video: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/hdpvr/hdpvr-video.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 2a3a8b470555..6d43d75493ea 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -155,10 +155,8 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count) buf->dev = dev; urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - v4l2_err(&dev->v4l2_dev, "cannot allocate urb\n"); + if (!urb) goto exit_urb; - } buf->urb = urb; mem = usb_alloc_coherent(dev->udev, dev->bulk_in_size, GFP_KERNEL, From ec691d0a8b4a8e18bed47f7854f2c0720aac42ee Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:56 +0200 Subject: [PATCH 140/343] media: usb: msi2500: msi2500: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/msi2500/msi2500.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index e7f167d44c61..367eb7e2a31d 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -509,7 +509,6 @@ static int msi2500_isoc_init(struct msi2500_dev *dev) for (i = 0; i < MAX_ISO_BUFS; i++) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { - dev_err(dev->dev, "Failed to allocate urb %d\n", i); msi2500_isoc_cleanup(dev); return -ENOMEM; } From 0ecf16674d05038f40ea5a53d64a7ae310d8fb14 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:57 +0200 Subject: [PATCH 141/343] media: usb: pwc: pwc-if: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/pwc/pwc-if.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index b51b27a3fd61..c4454c928776 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -410,7 +410,6 @@ retry: for (i = 0; i < MAX_ISO_BUFS; i++) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { - PWC_ERROR("Failed to allocate urb %d\n", i); pwc_isoc_cleanup(pdev); return -ENOMEM; } From 3b2630dcf4ce925cfd6aa376766f5a2d59c5f74b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:58 +0200 Subject: [PATCH 142/343] media: usb: s2255: s2255drv: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/s2255/s2255drv.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 43ba71a7d02b..9458eb0ef66f 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -2113,11 +2113,8 @@ static int s2255_start_readpipe(struct s2255_dev *dev) pipe_info->state = 1; pipe_info->err_count = 0; pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pipe_info->stream_urb) { - dev_err(&dev->udev->dev, - "ReadStream: Unable to alloc URB\n"); + if (!pipe_info->stream_urb) return -ENOMEM; - } /* transfer buffer allocated in board_init */ usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev, pipe, @@ -2290,10 +2287,8 @@ static int s2255_probe(struct usb_interface *interface, } dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->fw_data->fw_urb) { - dev_err(&interface->dev, "out of memory!\n"); + if (!dev->fw_data->fw_urb) goto errorFWURB; - } dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); if (!dev->fw_data->pfw_data) { From ec70abd1fa1095d4a389914a5fcb99d7dc2a1375 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:59 +0200 Subject: [PATCH 143/343] media: usb: stk1160: stk1160-video: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/stk1160/stk1160-video.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 6ecb0b48423f..ce8ebbe395a6 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -457,10 +457,8 @@ int stk1160_alloc_isoc(struct stk1160 *dev) for (i = 0; i < num_bufs; i++) { urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - stk1160_err("cannot alloc urb[%d]\n", i); + if (!urb) goto free_i_bufs; - } dev->isoc_ctl.urb[i] = urb; #ifndef CONFIG_DMA_NONCOHERENT From 7164c590c22af881797dc56b2d96aced719f68a4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:04:00 +0200 Subject: [PATCH 144/343] media: usb: stkwebcam: stk-webcam: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/stkwebcam/stk-webcam.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index c21c4c004f97..db200c9d796d 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -452,10 +452,8 @@ static int stk_prepare_iso(struct stk_camera *dev) STK_ERROR("isobuf data already allocated\n"); if (dev->isobufs[i].urb == NULL) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); - if (urb == NULL) { - STK_ERROR("Failed to allocate URB %d\n", i); + if (urb == NULL) goto isobufs_out; - } dev->isobufs[i].urb = urb; } else { STK_ERROR("Killing URB\n"); From 5d54a42ed7624cb6578ca7ff2238e670179734fd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:04:01 +0200 Subject: [PATCH 145/343] media: usb: tm6000: tm6000-dvb: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/tm6000/tm6000-dvb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 095f5db1a790..0426b210383b 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -129,10 +129,8 @@ static int tm6000_start_stream(struct tm6000_core *dev) } dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); - if (dvb->bulk_urb == NULL) { - printk(KERN_ERR "tm6000: couldn't allocate urb\n"); + if (dvb->bulk_urb == NULL) return -ENOMEM; - } pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); From a438612953ba82a887fc238466d2506eebc3c078 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:04:02 +0200 Subject: [PATCH 146/343] media: usb: tm6000: tm6000-video: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/tm6000/tm6000-video.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index fa5e8bda2ae4..dee7e7d3d47d 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -635,7 +635,6 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev) for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { urb = usb_alloc_urb(max_packets, GFP_KERNEL); if (!urb) { - tm6000_err("cannot alloc isoc_ctl.urb %i\n", i); tm6000_uninit_isoc(dev); usb_free_urb(urb); return -ENOMEM; From 44d6d61220e728cc5cad42ee861f3994723456e0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:04:03 +0200 Subject: [PATCH 147/343] media: usb: usbvision: usbvision-core: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/usbvision/usbvision-core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index 52ac4391582c..c23bf73a68ea 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -2303,11 +2303,8 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) struct urb *urb; urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); - if (urb == NULL) { - dev_err(&usbvision->dev->dev, - "%s: usb_alloc_urb() failed\n", __func__); + if (urb == NULL) return -ENOMEM; - } usbvision->sbuf[buf_idx].urb = urb; usbvision->sbuf[buf_idx].data = usb_alloc_coherent(usbvision->dev, From 4e9f037e20cede653e9404e021b1c48f05908195 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:04:04 +0200 Subject: [PATCH 148/343] media: usb: zr364xx: zr364xx: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/zr364xx/zr364xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 7433ba5c4bad..cc128db85723 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1045,10 +1045,8 @@ static int zr364xx_start_readpipe(struct zr364xx_camera *cam) pipe_info->state = 1; pipe_info->err_count = 0; pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pipe_info->stream_urb) { - dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n"); + if (!pipe_info->stream_urb) return -ENOMEM; - } /* transfer buffer allocated in board_init */ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev, pipe, From 78a4a0d22f7cfdf743eee76d177dffc0f8decb8d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:23:40 +0200 Subject: [PATCH 149/343] watchdog: pcwd_usb: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Reviewed-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/pcwd_usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c index 68952d9ccf83..99ebf6ea3de6 100644 --- a/drivers/watchdog/pcwd_usb.c +++ b/drivers/watchdog/pcwd_usb.c @@ -666,10 +666,8 @@ static int usb_pcwd_probe(struct usb_interface *interface, /* allocate the urb's */ usb_pcwd->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!usb_pcwd->intr_urb) { - pr_err("Out of memory\n"); + if (!usb_pcwd->intr_urb) goto error; - } /* initialise the intr urb's */ usb_fill_int_urb(usb_pcwd->intr_urb, udev, pipe, From 04e75e49564426624adfd912ac58cd18ac4e1ff0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:38:53 +0200 Subject: [PATCH 150/343] usb: atm: cxacru: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 18b281d73a39..f9fe86b6f7b5 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -1139,10 +1139,8 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, /* instance init */ instance = kzalloc(sizeof(*instance), GFP_KERNEL); - if (!instance) { - usb_dbg(usbatm_instance, "cxacru_bind: no memory for instance data\n"); + if (!instance) return -ENOMEM; - } instance->usbatm = usbatm_instance; instance->modem_type = (struct cxacru_modem_type *) id->driver_info; From 8b80c106a0c8b42115c15979b472b25dfecfac32 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:38:54 +0200 Subject: [PATCH 151/343] usb: atm: speedtch: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/speedtch.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 0270d1312f83..5083eb5b0d5e 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -817,7 +817,6 @@ static int speedtch_bind(struct usbatm_data *usbatm, instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (!instance) { - usb_err(usbatm, "%s: no memory for instance data!\n", __func__); ret = -ENOMEM; goto fail_release; } From 59e1200ecb5bfc42da895f423b16b01f9cf92e64 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:38:55 +0200 Subject: [PATCH 152/343] usb: atm: ueagle-atm: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index f198291630d7..df67815f74e6 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2196,11 +2196,8 @@ static int uea_boot(struct uea_softc *sc) load_XILINX_firmware(sc); intr = kmalloc(size, GFP_KERNEL); - if (!intr) { - uea_err(INS_TO_USBDEV(sc), - "cannot allocate interrupt package\n"); + if (!intr) goto err0; - } sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); if (!sc->urb_int) @@ -2559,10 +2556,8 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, } sc = kzalloc(sizeof(struct uea_softc), GFP_KERNEL); - if (!sc) { - uea_err(usb, "uea_init: not enough memory !\n"); + if (!sc) return -ENOMEM; - } sc->usb_dev = usb; usbatm->driver_data = sc; From 52879bb190bbda82603c857d37e3826b3aa2832a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:38:56 +0200 Subject: [PATCH 153/343] usb: atm: usbatm: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 5e4f46c5a300..4dec9df8764b 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -819,7 +819,6 @@ static int usbatm_atm_open(struct atm_vcc *vcc) new = kzalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL); if (!new) { - atm_err(instance, "%s: no memory for vcc_data!\n", __func__); ret = -ENOMEM; goto fail; } @@ -1032,10 +1031,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, /* instance init */ instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL); - if (!instance) { - dev_err(dev, "%s: no memory for instance data!\n", __func__); + if (!instance) return -ENOMEM; - } /* public fields */ @@ -1150,7 +1147,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, /* zero the tx padding to avoid leaking information */ buffer = kzalloc(channel->buf_size, GFP_KERNEL); if (!buffer) { - dev_err(dev, "%s: no memory for buffer %d!\n", __func__, i); error = -ENOMEM; goto fail_unbind; } @@ -1181,7 +1177,6 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, instance->cell_buf = kmalloc(instance->rx_channel.stride, GFP_KERNEL); if (!instance->cell_buf) { - dev_err(dev, "%s: no memory for cell buffer!\n", __func__); error = -ENOMEM; goto fail_unbind; } From f6b6f8a09f60e668de013eadc8d2a3d52bf36795 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:38:57 +0200 Subject: [PATCH 154/343] usb: class: usbtmc: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 22c235adacb3..da4f2509f567 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1476,10 +1476,8 @@ static int usbtmc_probe(struct usb_interface *intf, /* allocate buffer for interrupt in */ data->iin_buffer = kmalloc(data->iin_wMaxPacketSize, GFP_KERNEL); - if (!data->iin_buffer) { - dev_err(&intf->dev, "Failed to allocate int buf\n"); + if (!data->iin_buffer) goto error_register; - } /* fill interrupt urb */ usb_fill_int_urb(data->iin_urb, data->usb_dev, From 36af2db8709246a00670314feca728a014e320bd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:38:58 +0200 Subject: [PATCH 155/343] usb: core: hcd: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index d2e3f655c26f..a0c87b617edd 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2517,10 +2517,8 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, struct usb_hcd *hcd; hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); - if (!hcd) { - dev_dbg (dev, "hcd alloc failed\n"); + if (!hcd) return NULL; - } if (primary_hcd == NULL) { hcd->address0_mutex = kmalloc(sizeof(*hcd->address0_mutex), GFP_KERNEL); From b74e7062366af5b372b0f8ee5781c5e713ef67ad Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:38:59 +0200 Subject: [PATCH 156/343] usb: core: hub: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1d5fc32d06d0..b48dc76385b6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1823,10 +1823,8 @@ descriptor_error: dev_info(&intf->dev, "USB hub found\n"); hub = kzalloc(sizeof(*hub), GFP_KERNEL); - if (!hub) { - dev_dbg(&intf->dev, "couldn't kmalloc hub struct\n"); + if (!hub) return -ENOMEM; - } kref_init(&hub->kref); hub->intfdev = &intf->dev; @@ -5337,11 +5335,10 @@ static int descriptors_changed(struct usb_device *udev, } buf = kmalloc(len, GFP_NOIO); - if (buf == NULL) { - dev_err(&udev->dev, "no mem to re-read configs after reset\n"); + if (!buf) /* assume the worst */ return 1; - } + for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, From 93fab7955eb3af2de4c51f15f15a0881bf97c907 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:00 +0200 Subject: [PATCH 157/343] usb: core: message: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 0406a59f0551..5ab5c1a81462 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1760,17 +1760,14 @@ int usb_set_configuration(struct usb_device *dev, int configuration) nintf = cp->desc.bNumInterfaces; new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), GFP_NOIO); - if (!new_interfaces) { - dev_err(&dev->dev, "Out of memory\n"); + if (!new_interfaces) return -ENOMEM; - } for (; n < nintf; ++n) { new_interfaces[n] = kzalloc( sizeof(struct usb_interface), GFP_NOIO); if (!new_interfaces[n]) { - dev_err(&dev->dev, "Out of memory\n"); ret = -ENOMEM; free_interfaces: while (--n >= 0) From b62a7a99b89970b66ebc1b1fd8ad29116ffc3519 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:01 +0200 Subject: [PATCH 158/343] usb: core: urb: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/urb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c601e25b609f..a9039696476e 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -68,10 +68,8 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) urb = kmalloc(sizeof(struct urb) + iso_packets * sizeof(struct usb_iso_packet_descriptor), mem_flags); - if (!urb) { - printk(KERN_ERR "alloc_urb: kmalloc failed\n"); + if (!urb) return NULL; - } usb_init_urb(urb); return urb; } From 648e0bc96169668531ef6ea9524b8c0a81c92324 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:02 +0200 Subject: [PATCH 159/343] usb: dwc2: gadget: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/gadget.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index af46adfae41c..2ff03ae08e14 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3908,17 +3908,13 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) hsotg->ctrl_buff = devm_kzalloc(hsotg->dev, DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); - if (!hsotg->ctrl_buff) { - dev_err(dev, "failed to allocate ctrl request buff\n"); + if (!hsotg->ctrl_buff) return -ENOMEM; - } hsotg->ep0_buff = devm_kzalloc(hsotg->dev, DWC2_CTRL_BUFF_SIZE, GFP_KERNEL); - if (!hsotg->ep0_buff) { - dev_err(dev, "failed to allocate ctrl reply buff\n"); + if (!hsotg->ep0_buff) return -ENOMEM; - } ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED, dev_name(hsotg->dev), hsotg); From d9116ca87e8dfee907106dbc912a926c3b67c52c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:03 +0200 Subject: [PATCH 160/343] usb: gadget: udc: fsl_qe_udc: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/fsl_qe_udc.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index cf8819a5c5b2..9d6b2c8eed42 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -421,10 +421,8 @@ static int qe_ep_rxbd_update(struct qe_ep *ep) bd = ep->rxbase; ep->rxframe = kmalloc(sizeof(*ep->rxframe), GFP_ATOMIC); - if (ep->rxframe == NULL) { - dev_err(ep->udc->dev, "malloc rxframe failed\n"); + if (!ep->rxframe) return -ENOMEM; - } qe_frame_init(ep->rxframe); @@ -435,9 +433,7 @@ static int qe_ep_rxbd_update(struct qe_ep *ep) size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (bdring_len + 1); ep->rxbuffer = kzalloc(size, GFP_ATOMIC); - if (ep->rxbuffer == NULL) { - dev_err(ep->udc->dev, "malloc rxbuffer failed,size=%d\n", - size); + if (!ep->rxbuffer) { kfree(ep->rxframe); return -ENOMEM; } @@ -668,10 +664,8 @@ static int qe_ep_init(struct qe_udc *udc, if ((ep->tm == USBP_TM_CTL) || (ep->dir == USB_DIR_IN)) { ep->txframe = kmalloc(sizeof(*ep->txframe), GFP_ATOMIC); - if (ep->txframe == NULL) { - dev_err(udc->dev, "malloc txframe failed\n"); + if (!ep->txframe) goto en_done2; - } qe_frame_init(ep->txframe); } @@ -2347,10 +2341,8 @@ static struct qe_udc *qe_udc_config(struct platform_device *ofdev) u32 offset; udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (udc == NULL) { - dev_err(&ofdev->dev, "malloc udc failed\n"); + if (!udc) goto cleanup; - } udc->dev = &ofdev->dev; From e2088ec002ce36ee36a0b6fbe2d6299e1c1c8325 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:04 +0200 Subject: [PATCH 161/343] usb: gadget: udc: goku_udc: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/goku_udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index d2205d9e0c8b..1400415fe67a 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -1767,8 +1767,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* alloc, and start init */ dev = kzalloc (sizeof *dev, GFP_KERNEL); - if (dev == NULL){ - pr_debug("enomem %s\n", pci_name(pdev)); + if (!dev) { retval = -ENOMEM; goto err; } From c86af711a6945ac00d005c66b4f29faba82bafe9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:05 +0200 Subject: [PATCH 162/343] usb: gadget: udc: udc-xilinx: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/udc-xilinx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index f8bf290f1894..588e2531b8b8 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -973,10 +973,8 @@ static struct usb_request *xudc_ep_alloc_request(struct usb_ep *_ep, udc = ep->udc; req = kzalloc(sizeof(*req), gfp_flags); - if (!req) { - dev_err(udc->dev, "%s:not enough memory", __func__); + if (!req) return NULL; - } req->ep = ep; INIT_LIST_HEAD(&req->queue); From 2652de71c5cb4f90819d8f59887bc1099956446e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:06 +0200 Subject: [PATCH 163/343] usb: host: fhci-hcd: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fhci-hcd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 0960f41f945a..55a0ae6f2d74 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -310,10 +310,8 @@ static struct fhci_usb *fhci_create_lld(struct fhci_hcd *fhci) /* allocate memory for SCC data structure */ usb = kzalloc(sizeof(*usb), GFP_KERNEL); - if (!usb) { - fhci_err(fhci, "no memory for SCC data struct\n"); + if (!usb) return NULL; - } usb->fhci = fhci; usb->hc_list = fhci->hc_list; From 13dcf7800594171addb343c7a00493daaab4ed97 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:07 +0200 Subject: [PATCH 164/343] usb: host: max3421-hcd: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/max3421-hcd.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 2f7690092a7f..369869a29ebd 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1856,15 +1856,11 @@ max3421_probe(struct spi_device *spi) INIT_LIST_HEAD(&max3421_hcd->ep_list); max3421_hcd->tx = kmalloc(sizeof(*max3421_hcd->tx), GFP_KERNEL); - if (!max3421_hcd->tx) { - dev_err(&spi->dev, "failed to kmalloc tx buffer\n"); + if (!max3421_hcd->tx) goto error; - } max3421_hcd->rx = kmalloc(sizeof(*max3421_hcd->rx), GFP_KERNEL); - if (!max3421_hcd->rx) { - dev_err(&spi->dev, "failed to kmalloc rx buffer\n"); + if (!max3421_hcd->rx) goto error; - } max3421_hcd->spi_thread = kthread_run(max3421_spi_thread, hcd, "max3421_spi_thread"); From 314e672506e87d263404c69c6343b97ca2c59ded Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:08 +0200 Subject: [PATCH 165/343] usb: host: uhci-hcd: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-hcd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index a7de8e8bb458..5d3d914ab4fb 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -601,11 +601,8 @@ static int uhci_start(struct usb_hcd *hcd) uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu), GFP_KERNEL); - if (!uhci->frame_cpu) { - dev_err(uhci_dev(uhci), - "unable to allocate memory for frame pointers\n"); + if (!uhci->frame_cpu) goto err_alloc_frame_cpu; - } uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci), sizeof(struct uhci_td), 16, 0); From a35234b2a67363f0174322b9cf8b385d236e8822 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:09 +0200 Subject: [PATCH 166/343] usb: host: xhci-tegra: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 0f53ae0f464e..d39b37be71f0 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1033,7 +1033,6 @@ static int tegra_xusb_probe(struct platform_device *pdev) tegra->phys = devm_kcalloc(&pdev->dev, tegra->num_phys, sizeof(*tegra->phys), GFP_KERNEL); if (!tegra->phys) { - dev_err(&pdev->dev, "failed to allocate PHY array\n"); err = -ENOMEM; goto put_padctl; } From f4c46f119ac6edbff2ec8ca8aad4beffc5631eac Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:10 +0200 Subject: [PATCH 167/343] usb: host: xhci: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 01d96c9b3a75..1a4ca02729c2 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -295,10 +295,8 @@ static int xhci_setup_msix(struct xhci_hcd *xhci) xhci->msix_entries = kmalloc((sizeof(struct msix_entry))*xhci->msix_count, GFP_KERNEL); - if (!xhci->msix_entries) { - xhci_err(xhci, "Failed to allocate MSI-X entries\n"); + if (!xhci->msix_entries) return -ENOMEM; - } for (i = 0; i < xhci->msix_count; i++) { xhci->msix_entries[i].entry = i; From a02b55c8db5a35059fda254a7a5bddacc9fd4cef Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:11 +0200 Subject: [PATCH 168/343] usb: misc: adutux: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index c34a0b6980cd..564268fca07a 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -672,8 +672,7 @@ static int adu_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (!dev) { retval = -ENOMEM; goto exit; } @@ -710,7 +709,6 @@ static int adu_probe(struct usb_interface *interface, dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL); if (!dev->read_buffer_primary) { - dev_err(&interface->dev, "Couldn't allocate read_buffer_primary\n"); retval = -ENOMEM; goto error; } @@ -723,7 +721,6 @@ static int adu_probe(struct usb_interface *interface, dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL); if (!dev->read_buffer_secondary) { - dev_err(&interface->dev, "Couldn't allocate read_buffer_secondary\n"); retval = -ENOMEM; goto error; } @@ -735,10 +732,8 @@ static int adu_probe(struct usb_interface *interface, memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size); dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL); - if (!dev->interrupt_in_buffer) { - dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n"); + if (!dev->interrupt_in_buffer) goto error; - } /* debug code prime the buffer */ memset(dev->interrupt_in_buffer, 'i', in_end_size); @@ -747,10 +742,8 @@ static int adu_probe(struct usb_interface *interface, if (!dev->interrupt_in_urb) goto error; dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL); - if (!dev->interrupt_out_buffer) { - dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n"); + if (!dev->interrupt_out_buffer) goto error; - } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_out_urb) goto error; From d7f040e92fa0465ff08d2a1e46f0149d9eb65616 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:12 +0200 Subject: [PATCH 169/343] usb: misc: appledisplay: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/appledisplay.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 29569ec2ee50..da5ff401a354 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -238,7 +238,6 @@ static int appledisplay_probe(struct usb_interface *iface, pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL); if (!pdata) { retval = -ENOMEM; - dev_err(&iface->dev, "Out of memory\n"); goto error; } @@ -252,8 +251,6 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); if (!pdata->msgdata) { retval = -ENOMEM; - dev_err(&iface->dev, - "Allocating buffer for control messages failed\n"); goto error; } From e83c06e99df6de5a0ba9710280385a6da4084c76 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:13 +0200 Subject: [PATCH 170/343] usb: misc: cypress_cy7c63: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/cypress_cy7c63.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index 402b94dd2531..5c93a888c40e 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -79,7 +79,6 @@ static int vendor_command(struct cypress *dev, unsigned char request, /* allocate some memory for the i/o buffer*/ iobuf = kzalloc(CYPRESS_MAX_REQSIZE, GFP_KERNEL); if (!iobuf) { - dev_err(&dev->udev->dev, "Out of memory!\n"); retval = -ENOMEM; goto error; } @@ -208,10 +207,8 @@ static int cypress_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory!\n"); + if (!dev) goto error_mem; - } dev->udev = usb_get_dev(interface_to_usbdev(interface)); From 29a99df17bb755bac716177295de7b4b86cb1467 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:14 +0200 Subject: [PATCH 171/343] usb: misc: cytherm: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/cytherm.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c index 9bab1a33bc16..9d8bb8dacdcd 100644 --- a/drivers/usb/misc/cytherm.c +++ b/drivers/usb/misc/cytherm.c @@ -101,10 +101,8 @@ static ssize_t set_brightness(struct device *dev, struct device_attribute *attr, int retval; buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); + if (!buffer) return 0; - } cytherm->brightness = simple_strtoul(buf, NULL, 10); @@ -148,10 +146,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char int temp, sign; buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); + if (!buffer) return 0; - } /* read temperature */ retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8); @@ -192,10 +188,8 @@ static ssize_t show_button(struct device *dev, struct device_attribute *attr, ch unsigned char *buffer; buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); + if (!buffer) return 0; - } /* check button */ retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8); @@ -230,10 +224,8 @@ static ssize_t show_port0(struct device *dev, struct device_attribute *attr, cha unsigned char *buffer; buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); + if (!buffer) return 0; - } retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8); if (retval) @@ -257,10 +249,8 @@ static ssize_t set_port0(struct device *dev, struct device_attribute *attr, cons int tmp; buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); + if (!buffer) return 0; - } tmp = simple_strtoul(buf, NULL, 10); @@ -290,10 +280,8 @@ static ssize_t show_port1(struct device *dev, struct device_attribute *attr, cha unsigned char *buffer; buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); + if (!buffer) return 0; - } retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8); if (retval) @@ -317,10 +305,8 @@ static ssize_t set_port1(struct device *dev, struct device_attribute *attr, cons int tmp; buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); + if (!buffer) return 0; - } tmp = simple_strtoul(buf, NULL, 10); @@ -351,10 +337,8 @@ static int cytherm_probe(struct usb_interface *interface, int retval = -ENOMEM; dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL); - if (dev == NULL) { - dev_err (&interface->dev, "Out of memory\n"); + if (!dev) goto error_mem; - } dev->udev = usb_get_dev(udev); From 524fd35357559381d5e84b6b5af2995579ace0eb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:15 +0200 Subject: [PATCH 172/343] usb: misc: ftdi-elan: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 16765b3e0b1b..9a82f8308ad7 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2730,7 +2730,6 @@ static int ftdi_elan_probe(struct usb_interface *interface, ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!ftdi->bulk_in_buffer) { - dev_err(&ftdi->udev->dev, "Could not allocate bulk_in_buffer\n"); retval = -ENOMEM; goto error; } From 081e303e49d417961f2e55a87badd10959935eac Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:16 +0200 Subject: [PATCH 173/343] usb: misc: idmouse: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/idmouse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 5105397e62fc..2975e80b7a56 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -366,7 +366,6 @@ static int idmouse_probe(struct usb_interface *interface, kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - dev_err(&interface->dev, "Unable to allocate input buffer.\n"); idmouse_delete(dev); return -ENOMEM; } From 3cfb4842fbf4854b5b5a02a0e14a969d6a498aa0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:17 +0200 Subject: [PATCH 174/343] usb: misc: iowarrior: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 7defa34dd4fa..095778ff984d 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -278,7 +278,7 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer, dev = file->private_data; /* verify that the device wasn't unplugged */ - if (dev == NULL || !dev->present) + if (!dev || !dev->present) return -ENODEV; dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", @@ -480,9 +480,8 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, int io_res; /* checks for bytes read/written and copy_to/from_user results */ dev = file->private_data; - if (dev == NULL) { + if (!dev) return -ENODEV; - } buffer = kzalloc(dev->report_size, GFP_KERNEL); if (!buffer) @@ -652,9 +651,8 @@ static int iowarrior_release(struct inode *inode, struct file *file) int retval = 0; dev = file->private_data; - if (dev == NULL) { + if (!dev) return -ENODEV; - } dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor); @@ -764,10 +762,8 @@ static int iowarrior_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (!dev) return retval; - } mutex_init(&dev->mutex); @@ -813,10 +809,8 @@ static int iowarrior_probe(struct usb_interface *interface, if (!dev->int_in_urb) goto error; dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); - if (!dev->int_in_buffer) { - dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n"); + if (!dev->int_in_buffer) goto error; - } usb_fill_int_urb(dev->int_in_urb, dev->udev, usb_rcvintpipe(dev->udev, dev->int_in_endpoint->bEndpointAddress), @@ -827,10 +821,8 @@ static int iowarrior_probe(struct usb_interface *interface, dev->read_queue = kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER), GFP_KERNEL); - if (!dev->read_queue) { - dev_err(&interface->dev, "Couldn't allocate read_queue\n"); + if (!dev->read_queue) goto error; - } /* Get the serial-number of the chip */ memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial, From 6714ffae751868e237d8f887eca1754d08ee814c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:18 +0200 Subject: [PATCH 175/343] usb: misc: ldusb: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ldusb.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 84890791c2f8..9ca595632f17 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -658,10 +658,8 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&intf->dev, "Out of memory\n"); + if (!dev) goto exit; - } mutex_init(&dev->mutex); spin_lock_init(&dev->rbsl); dev->intf = intf; @@ -674,10 +672,8 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_LD_COM3LAB)) && (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) { buffer = kmalloc(256, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&intf->dev, "Couldn't allocate string buffer\n"); + if (!buffer) goto error; - } /* usb_string makes SETUP+STALL to leave always ControlReadLoop */ usb_string(udev, 255, buffer, 256); kfree(buffer); @@ -704,25 +700,19 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint); dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL); - if (!dev->ring_buffer) { - dev_err(&intf->dev, "Couldn't allocate ring_buffer\n"); + if (!dev->ring_buffer) goto error; - } dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); - if (!dev->interrupt_in_buffer) { - dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); + if (!dev->interrupt_in_buffer) goto error; - } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_in_urb) goto error; dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? usb_endpoint_maxp(dev->interrupt_out_endpoint) : udev->descriptor.bMaxPacketSize0; dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); - if (!dev->interrupt_out_buffer) { - dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); + if (!dev->interrupt_out_buffer) goto error; - } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_out_urb) goto error; From 49d8ffab82342904e22f156530649faff9e6baae Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:19 +0200 Subject: [PATCH 176/343] usb: misc: legousbtower: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 52b41fb66792..ece9b3c1eaac 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -817,10 +817,8 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL); - if (dev == NULL) { - dev_err(idev, "Out of memory\n"); + if (!dev) goto exit; - } mutex_init(&dev->lock); @@ -871,23 +869,17 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device } dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL); - if (!dev->read_buffer) { - dev_err(idev, "Couldn't allocate read_buffer\n"); + if (!dev->read_buffer) goto error; - } dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL); - if (!dev->interrupt_in_buffer) { - dev_err(idev, "Couldn't allocate interrupt_in_buffer\n"); + if (!dev->interrupt_in_buffer) goto error; - } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_in_urb) goto error; dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL); - if (!dev->interrupt_out_buffer) { - dev_err(idev, "Couldn't allocate interrupt_out_buffer\n"); + if (!dev->interrupt_out_buffer) goto error; - } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_out_urb) goto error; From 5c47fd6166ce644d403787586eb206b910df7413 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:20 +0200 Subject: [PATCH 177/343] usb: misc: lvstest: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/lvstest.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c index 9c49334c622d..77176511658f 100644 --- a/drivers/usb/misc/lvstest.c +++ b/drivers/usb/misc/lvstest.c @@ -245,10 +245,8 @@ static ssize_t get_dev_desc_store(struct device *dev, int ret; descriptor = kmalloc(sizeof(*descriptor), GFP_KERNEL); - if (!descriptor) { - dev_err(dev, "failed to allocate descriptor memory\n"); + if (!descriptor) return -ENOMEM; - } udev = create_lvs_device(intf); if (!udev) { From 58e61402c7f46c792daa2bb32f4686c45bd15f90 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:21 +0200 Subject: [PATCH 178/343] usb: misc: trancevibrator: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/trancevibrator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 4145314a515b..9795457723d8 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -95,8 +95,7 @@ static int tv_probe(struct usb_interface *interface, int retval; dev = kzalloc(sizeof(struct trancevibrator), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (!dev) { retval = -ENOMEM; goto error; } From a1841732e07e534a2e207c88ae63e7b4a7522d4b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:22 +0200 Subject: [PATCH 179/343] usb: misc: usblcd: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usblcd.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 1184390508e9..9f48419abc46 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -321,10 +321,8 @@ static int lcd_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (!dev) goto error; - } kref_init(&dev->kref); sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); init_usb_anchor(&dev->submitted); @@ -351,11 +349,8 @@ static int lcd_probe(struct usb_interface *interface, dev->bulk_in_size = buffer_size; dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!dev->bulk_in_buffer) { - dev_err(&interface->dev, - "Could not allocate bulk_in_buffer\n"); + if (!dev->bulk_in_buffer) goto error; - } } if (!dev->bulk_out_endpointAddr && From bcf0848dcbc282f76c3ed4f734178392eca2deb2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:23 +0200 Subject: [PATCH 180/343] usb: misc: usbsevseg: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbsevseg.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index 1fe6b73c22f3..a0ba5298160c 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -128,10 +128,8 @@ static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf) return; buffer = kzalloc(MAXLEN, mf); - if (!buffer) { - dev_err(&mydev->udev->dev, "out of memory\n"); + if (!buffer) return; - } /* The device is right to left, where as you write left to right */ for (i = 0; i < mydev->textlength; i++) @@ -346,10 +344,8 @@ static int sevseg_probe(struct usb_interface *interface, int rc = -ENOMEM; mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL); - if (mydev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (!mydev) goto error_mem; - } mydev->udev = usb_get_dev(udev); mydev->intf = interface; From c9220ba512af2c71171251d032b191d6bb9dba62 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:24 +0200 Subject: [PATCH 181/343] usb: misc: uss720: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/uss720.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 256d02da444d..356d312add57 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -150,10 +150,8 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p if (!usbdev) return NULL; rq = kzalloc(sizeof(struct uss720_async_request), mem_flags); - if (!rq) { - dev_err(&usbdev->dev, "submit_async_request out of memory\n"); + if (!rq) return NULL; - } kref_init(&rq->ref_count); INIT_LIST_HEAD(&rq->asynclist); init_completion(&rq->compl); From 0c2bc5c2cb267c41f073132d1817df917ab8ba47 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:25 +0200 Subject: [PATCH 182/343] usb: misc: yurex: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/yurex.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index bb606bdc25e5..54e53ac4c08f 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -200,10 +200,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&interface->dev, "Out of memory\n"); + if (!dev) goto error; - } kref_init(&dev->kref); mutex_init(&dev->io_mutex); spin_lock_init(&dev->lock); @@ -236,10 +234,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate buffer for control req */ dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL); - if (!dev->cntl_req) { - dev_err(&interface->dev, "Could not allocate cntl_req\n"); + if (!dev->cntl_req) goto error; - } /* allocate buffer for control msg */ dev->cntl_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE, From 906f5dc99c93f564f1a17b6f908701efd7e90baa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:26 +0200 Subject: [PATCH 183/343] usb: musb: am35x: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/am35x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index c41fe588d14d..c14577dbedf7 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -474,10 +474,8 @@ static int am35x_probe(struct platform_device *pdev) int ret = -ENOMEM; glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); + if (!glue) goto err0; - } phy_clk = clk_get(&pdev->dev, "fck"); if (IS_ERR(phy_clk)) { From 92c0c4905b651e0c9938802cae0ab30583ead038 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:27 +0200 Subject: [PATCH 184/343] usb: musb: da8xx: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/da8xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index b03d3b867fca..3c4dd1658f28 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -494,10 +494,8 @@ static int da8xx_probe(struct platform_device *pdev) int ret = -ENOMEM; glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); + if (!glue) goto err0; - } clk = clk_get(&pdev->dev, "usb20"); if (IS_ERR(clk)) { From 7d80e4be1e50d2c5c6e314c9c555810374305f82 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:28 +0200 Subject: [PATCH 185/343] usb: renesas_usbhs: mod_gadget: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/mod_gadget.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 92bc83b92d10..8e326ac00c9f 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -335,7 +335,6 @@ static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv, buf = kmalloc(sizeof(*buf), GFP_ATOMIC); if (!buf) { usb_ep_free_request(&dcp->ep, req); - dev_err(dev, "recip data allocation fail\n"); return; } @@ -1062,14 +1061,11 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) int ret; gpriv = kzalloc(sizeof(struct usbhsg_gpriv), GFP_KERNEL); - if (!gpriv) { - dev_err(dev, "Could not allocate gadget priv\n"); + if (!gpriv) return -ENOMEM; - } uep = kzalloc(sizeof(struct usbhsg_uep) * pipe_size, GFP_KERNEL); if (!uep) { - dev_err(dev, "Could not allocate ep\n"); ret = -ENOMEM; goto usbhs_mod_gadget_probe_err_gpriv; } From 93b6cb4504d90f8f5ed35e5b0c2b5726678cedd2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:29 +0200 Subject: [PATCH 186/343] usb: renesas_usbhs: mod_host: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/mod_host.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 3bf0b72eb359..165e81bfd93a 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -166,14 +166,10 @@ static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, gfp_t mem_flags) { struct usbhsh_request *ureq; - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); - if (!ureq) { - dev_err(dev, "ureq alloc fail\n"); + if (!ureq) return NULL; - } usbhs_pkt_init(&ureq->pkt); ureq->urb = urb; @@ -388,10 +384,8 @@ static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, unsigned long flags; uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); - if (!uep) { - dev_err(dev, "usbhsh_ep alloc fail\n"); + if (!uep) return -ENOMEM; - } /******************** spin lock ********************/ usbhs_lock(priv, flags); From c34515f87501fc1cb49ec1a104b9a69e4a263e80 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:30 +0200 Subject: [PATCH 187/343] usb: renesas_usbhs: pipe: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/pipe.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index c238772b9e9e..9396a8c14af8 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -804,10 +804,8 @@ int usbhs_pipe_probe(struct usbhs_priv *priv) } info->pipe = kzalloc(sizeof(struct usbhs_pipe) * pipe_size, GFP_KERNEL); - if (!info->pipe) { - dev_err(dev, "Could not allocate pipe\n"); + if (!info->pipe) return -ENOMEM; - } info->size = pipe_size; From e5cdac9242f58ca0122822e8fd7cab03c7faeb07 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:31 +0200 Subject: [PATCH 188/343] usb: storage: alauda: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/alauda.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index 1d8b03c81030..878b4b8761f5 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -939,10 +939,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address, len = min(sectors, blocksize) * (pagesize + 64); buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "alauda_read_data: Out of memory\n"); + if (!buffer) return USB_STOR_TRANSPORT_ERROR; - } /* Figure out the initial LBA and page */ lba = address >> blockshift; @@ -1033,18 +1031,15 @@ static int alauda_write_data(struct us_data *us, unsigned long address, len = min(sectors, blocksize) * pagesize; buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "alauda_write_data: Out of memory\n"); + if (!buffer) return USB_STOR_TRANSPORT_ERROR; - } /* * We also need a temporary block buffer, where we read in the old data, * overwrite parts with the new data, and manipulate the redundancy data */ blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO); - if (blockbuffer == NULL) { - printk(KERN_WARNING "alauda_write_data: Out of memory\n"); + if (!blockbuffer) { kfree(buffer); return USB_STOR_TRANSPORT_ERROR; } From fd233925ed2fa757cbea6478434fc219732974c9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:32 +0200 Subject: [PATCH 189/343] usb: storage: sddr09: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/sddr09.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index c5797fa2125e..3aeaa536c44f 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -766,10 +766,8 @@ sddr09_read_data(struct us_data *us, len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "sddr09_read_data: Out of memory\n"); + if (!buffer) return -ENOMEM; - } // This could be made much more efficient by checking for // contiguous LBA's. Another exercise left to the student. @@ -1004,10 +1002,8 @@ sddr09_write_data(struct us_data *us, pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); blocklen = (pagelen << info->blockshift); blockbuffer = kmalloc(blocklen, GFP_NOIO); - if (!blockbuffer) { - printk(KERN_WARNING "sddr09_write_data: Out of memory\n"); + if (!blockbuffer) return -ENOMEM; - } /* * Since we don't write the user data directly to the device, @@ -1017,8 +1013,7 @@ sddr09_write_data(struct us_data *us, len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "sddr09_write_data: Out of memory\n"); + if (!buffer) { kfree(blockbuffer); return -ENOMEM; } @@ -1241,8 +1236,7 @@ sddr09_read_map(struct us_data *us) { alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT); alloc_len = (alloc_blocks << CONTROL_SHIFT); buffer = kmalloc(alloc_len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "sddr09_read_map: out of memory\n"); + if (!buffer) { result = -1; goto done; } From dc0c32c93e65cb520831546c912c8cf3f6113059 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:33 +0200 Subject: [PATCH 190/343] usb: usb-skeleton: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 89e02a7529b7..5133a0792eb0 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -499,10 +499,8 @@ static int skel_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&interface->dev, "Out of memory\n"); + if (!dev) goto error; - } kref_init(&dev->kref); sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); mutex_init(&dev->io_mutex); @@ -526,11 +524,8 @@ static int skel_probe(struct usb_interface *interface, dev->bulk_in_size = buffer_size; dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!dev->bulk_in_buffer) { - dev_err(&interface->dev, - "Could not allocate bulk_in_buffer\n"); + if (!dev->bulk_in_buffer) goto error; - } dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->bulk_in_urb) goto error; From 90b613864d414d3c8423fd8d58a956d89ef58770 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:34 +0200 Subject: [PATCH 191/343] usb: wusbcore: crypto: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/crypto.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index 33acd1599e99..79b2b628066d 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -229,10 +229,8 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, zero_padding = sizeof(struct aes_ccm_block) - zero_padding; dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding; dst_buf = kzalloc(dst_size, GFP_KERNEL); - if (dst_buf == NULL) { - printk(KERN_ERR "E: can't alloc destination buffer\n"); + if (!dst_buf) goto error_dst_buf; - } memset(iv, 0, sizeof(iv)); From d919523f97c97859be5d01fb964fd35d3acda489 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:35 +0200 Subject: [PATCH 192/343] usb: wusbcore: security: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/security.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index b66faaf3e842..8c9421b69da0 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -374,10 +374,8 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, struct wusb_keydvt_out keydvt_out; hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL); - if (hs == NULL) { - dev_err(dev, "can't allocate handshake data\n"); + if (!hs) goto error_kzalloc; - } /* We need to turn encryption before beginning the 4way * hshake (WUSB1.0[.3.2.2]) */ From 84f11ce545d464828992036591bbcb78175d509f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 25 Aug 2016 19:39:36 +0200 Subject: [PATCH 193/343] usb: wusbcore: wa-nep: don't print on ENOMEM All kmalloc-based functions print enough information on failures. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/wa-nep.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c index 6140100ad50e..ed4622279c63 100644 --- a/drivers/usb/wusbcore/wa-nep.c +++ b/drivers/usb/wusbcore/wa-nep.c @@ -271,11 +271,8 @@ int wa_nep_create(struct wahc *wa, struct usb_interface *iface) epd = &iface->cur_altsetting->endpoint[0].desc; wa->nep_buffer_size = 1024; wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL); - if (wa->nep_buffer == NULL) { - dev_err(dev, - "Unable to allocate notification's read buffer\n"); + if (!wa->nep_buffer) goto error_nep_buffer; - } wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL); if (wa->nep_urb == NULL) goto error_urb_alloc; From fc8b690d5da86a4b309b74fb706cc1eb75d003e6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 25 Aug 2016 11:30:49 -0400 Subject: [PATCH 194/343] usb-storage: MAINTAINERS: Alan Stern is the new maintainer At Matt Dharm's request, I am taking over maintainership of the usb-storage driver. Signed-off-by: Alan Stern Acked-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0bbe4b105c34..deff5cb58002 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12163,7 +12163,7 @@ S: Maintained F: drivers/net/usb/lan78xx.* USB MASS STORAGE DRIVER -M: Matthew Dharm +M: Alan Stern L: linux-usb@vger.kernel.org L: usb-storage@lists.one-eyed-alien.net S: Maintained From 2e2aa1bc7eff90ecc1dddfc593aef07c57e539d0 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 23 Aug 2016 09:05:29 +0800 Subject: [PATCH 195/343] usb: ohci-at91: Forcibly suspend ports while USB suspend The usb controller does not manage correctly the suspend mode for the ehci. In echi mode, there is no way to suspend without any device connected to it. This is why this specific control is added to fix this issue. Since the suspend mode works in ohci mode, this specific control works by suspend the usb controller in ohci mode. This specific control is by setting the SUSPEND_A/B/C fields of SFR_OHCIICR(OHCI Interrupt Configuration Register) in the SFR while the OHCI USB suspend. This set operation must be done before the USB clock disabled, clear operation after the USB clock enabled. Signed-off-by: Wenyou Yang Reviewed-by: Alexandre Belloni Acked-by: Nicolas Ferre Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 69 +++++++++++++++++++++++++++++++++++- include/soc/at91/atmel-sfr.h | 14 ++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index d177372bb357..31102170c7a0 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -21,8 +21,11 @@ #include #include #include +#include +#include #include #include +#include #include "ohci.h" @@ -51,6 +54,7 @@ struct ohci_at91_priv { struct clk *hclk; bool clocked; bool wakeup; /* Saved wake-up state for resume */ + struct regmap *sfr_regmap; }; /* interface and function clocks; sometimes also an AHB clock */ @@ -134,6 +138,17 @@ static void at91_stop_hc(struct platform_device *pdev) static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); +struct regmap *at91_dt_syscon_sfr(void) +{ + struct regmap *regmap; + + regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(regmap)) + regmap = NULL; + + return regmap; +} + /* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ @@ -197,6 +212,10 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, goto err; } + ohci_at91->sfr_regmap = at91_dt_syscon_sfr(); + if (!ohci_at91->sfr_regmap) + dev_warn(dev, "failed to find sfr node\n"); + board = hcd->self.controller->platform_data; ohci = hcd_to_ohci(hcd); ohci->num_ports = board->ports; @@ -282,6 +301,28 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) return length; } +static int ohci_at91_port_suspend(struct regmap *regmap, u8 set) +{ + u32 regval; + int ret; + + if (!regmap) + return 0; + + ret = regmap_read(regmap, AT91_SFR_OHCIICR, ®val); + if (ret) + return ret; + + if (set) + regval |= AT91_OHCIICR_USB_SUSPEND; + else + regval &= ~AT91_OHCIICR_USB_SUSPEND; + + regmap_write(regmap, AT91_SFR_OHCIICR, regval); + + return 0; +} + /* * Look at the control requests to the root hub and see if we need to override. */ @@ -289,6 +330,7 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); + struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd); struct usb_hub_descriptor *desc; int ret = -EINVAL; u32 *data = (u32 *)buf; @@ -301,7 +343,8 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (typeReq) { case SetPortFeature: - if (wValue == USB_PORT_FEAT_POWER) { + switch (wValue) { + case USB_PORT_FEAT_POWER: dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); if (valid_port(wIndex)) { ohci_at91_usb_set_power(pdata, wIndex, 1); @@ -309,6 +352,15 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } goto out; + + case USB_PORT_FEAT_SUSPEND: + dev_dbg(hcd->self.controller, "SetPortFeat: SUSPEND\n"); + if (valid_port(wIndex)) { + ohci_at91_port_suspend(ohci_at91->sfr_regmap, + 1); + return 0; + } + break; } break; @@ -342,6 +394,16 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ohci_at91_usb_set_power(pdata, wIndex, 0); return 0; } + break; + + case USB_PORT_FEAT_SUSPEND: + dev_dbg(hcd->self.controller, "ClearPortFeature: SUSPEND\n"); + if (valid_port(wIndex)) { + ohci_at91_port_suspend(ohci_at91->sfr_regmap, + 0); + return 0; + } + break; } break; } @@ -599,6 +661,8 @@ ohci_hcd_at91_drv_suspend(struct device *dev) if (ohci_at91->wakeup) enable_irq_wake(hcd->irq); + ohci_at91_port_suspend(ohci_at91->sfr_regmap, 1); + ret = ohci_suspend(hcd, ohci_at91->wakeup); if (ret) { if (ohci_at91->wakeup) @@ -638,6 +702,9 @@ ohci_hcd_at91_drv_resume(struct device *dev) at91_start_clock(ohci_at91); ohci_resume(hcd, false); + + ohci_at91_port_suspend(ohci_at91->sfr_regmap, 0); + return 0; } diff --git a/include/soc/at91/atmel-sfr.h b/include/soc/at91/atmel-sfr.h index 2f9bb984a4df..506ea8ffda19 100644 --- a/include/soc/at91/atmel-sfr.h +++ b/include/soc/at91/atmel-sfr.h @@ -13,6 +13,20 @@ #ifndef _LINUX_MFD_SYSCON_ATMEL_SFR_H #define _LINUX_MFD_SYSCON_ATMEL_SFR_H +#define AT91_SFR_DDRCFG 0x04 /* DDR Configuration Register */ +/* 0x08 ~ 0x0c: Reserved */ +#define AT91_SFR_OHCIICR 0x10 /* OHCI INT Configuration Register */ +#define AT91_SFR_OHCIISR 0x14 /* OHCI INT Status Register */ #define AT91_SFR_I2SCLKSEL 0x90 /* I2SC Register */ +/* Field definitions */ +#define AT91_OHCIICR_SUSPEND_A BIT(8) +#define AT91_OHCIICR_SUSPEND_B BIT(9) +#define AT91_OHCIICR_SUSPEND_C BIT(10) + +#define AT91_OHCIICR_USB_SUSPEND (AT91_OHCIICR_SUSPEND_A | \ + AT91_OHCIICR_SUSPEND_B | \ + AT91_OHCIICR_SUSPEND_C) + + #endif /* _LINUX_MFD_SYSCON_ATMEL_SFR_H */ From 6ebb8f0f83ffc0a482380a84772f35f2548d7eca Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 26 Aug 2016 17:41:32 +0100 Subject: [PATCH 196/343] usb: ohci-sa1111: remove machine_has_neponset() The neponset is a daughter board for the Assabet platform, which has a SA1111 chip on it. If we're initialising the SA1111 OHCI, and we're part of a neponset, the host platform must be an Assabet. This allows us to eliminate machine_has_neponset() from this driver, replacing it instead with machine_is_assabet(), and killing the mach/assabet.h include. Signed-off-by: Russell King Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-sa1111.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 2ac266d692a2..6dc5eaed8551 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -15,7 +15,6 @@ #include #include -#include #include #ifndef CONFIG_SA1111 @@ -127,7 +126,7 @@ static int sa1111_start_hc(struct sa1111_dev *dev) dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n"); if (machine_is_xp860() || - machine_has_neponset() || + machine_is_assabet() || machine_is_pfs168() || machine_is_badge4()) usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; From 70efb643a854b98e7012456b598ae01bc91475dc Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 26 Aug 2016 17:41:37 +0100 Subject: [PATCH 197/343] usb: ohci-sa1111: remove mach/hardware.h include The mach/hardware.h include doesn't seem to be necessary to build ohci-sa1111, so let's remove it to kill off an unnecessary platform specific include. Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-sa1111.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 6dc5eaed8551..3a9ea32508df 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -13,7 +13,6 @@ * This file is licenced under the GPL. */ -#include #include #include From b68824b1a6e13f6b39ba925d1cc596bafceb438e Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 19 Aug 2016 17:31:31 +0100 Subject: [PATCH 198/343] USB: ohci-omap - avoid including mach/irqs.h ohci-omap doesn't need to include mach/irqs.h - nothing within this driver needs anything from this header file. Remove this include. Signed-off-by: Russell King Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-omap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index de7c68602a7e..495c1454b9e8 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -36,7 +36,6 @@ #include #include -#include #include From 238b7bd91b16d5a08326f858db42229b212e53d8 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Tue, 23 Aug 2016 17:13:29 +0200 Subject: [PATCH 199/343] usb: usbip: vudc: fix left shift overflow In v_recv_cmd_submit(), urb_p->urb->pipe has the type unsigned int (which is 32-bit long on x86_64) but 11<<30 results in a 34-bit integer. Therefore the 2 leading bits are truncated and urb_p->urb->pipe &= ~(11 << 30); has the same meaning as urb_p->urb->pipe &= ~(3 << 30); This second statement seems to be how the code was intended to be written, as PIPE_ constants have values between 0 and 3. The overflow has been detected with a clang warning: drivers/usb/usbip/vudc_rx.c:145:27: warning: signed shift result (0x2C0000000) requires 35 bits to represent, but 'int' only has 32 bits [-Wshift-overflow] urb_p->urb->pipe &= ~(11 << 30); ~~ ^ ~~ Fixes: 79c02cb1fd5c ("usbip: vudc: Add vudc_rx") Signed-off-by: Nicolas Iooss Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vudc_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/usbip/vudc_rx.c b/drivers/usb/usbip/vudc_rx.c index 344bd9473475..e429b59f6f8a 100644 --- a/drivers/usb/usbip/vudc_rx.c +++ b/drivers/usb/usbip/vudc_rx.c @@ -142,7 +142,7 @@ static int v_recv_cmd_submit(struct vudc *udc, urb_p->urb->status = -EINPROGRESS; /* FIXME: more pipe setup to please usbip_common */ - urb_p->urb->pipe &= ~(11 << 30); + urb_p->urb->pipe &= ~(3 << 30); switch (urb_p->ep->type) { case USB_ENDPOINT_XFER_BULK: urb_p->urb->pipe |= (PIPE_BULK << 30); From aae819e1bd50195c3adcac337735415cef48b6ba Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 24 Aug 2016 16:39:53 +0900 Subject: [PATCH 200/343] usb: renesas_usbhs: add a compatible string for r8a7796 This patch adds support for r8a7796 (R-Car M3-W). Acked-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/renesas_usbhs.txt | 1 + drivers/usb/renesas_usbhs/common.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index b6040563e51a..9e18e000339e 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt @@ -9,6 +9,7 @@ Required properties: - "renesas,usbhs-r8a7793" for r8a7793 (R-Car M2-N) compatible device - "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device + - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device - "renesas,rcar-gen2-usbhs" for R-Car Gen2 compatible device - "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index ac67bab9124c..012a37aa3e0d 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -481,6 +481,10 @@ static const struct of_device_id usbhs_of_match[] = { .compatible = "renesas,usbhs-r8a7795", .data = (void *)USBHS_TYPE_RCAR_GEN3, }, + { + .compatible = "renesas,usbhs-r8a7796", + .data = (void *)USBHS_TYPE_RCAR_GEN3, + }, { .compatible = "renesas,rcar-gen2-usbhs", .data = (void *)USBHS_TYPE_RCAR_GEN2, From a00c9791a3e4f625840f1f0507ad3f191310abae Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 24 Aug 2016 07:44:19 +0100 Subject: [PATCH 201/343] usb: gadget: net2280: fix typo: "Inavlid" -> "Invalid" trivial typo fix in dev_err message Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index a28eb87078ae..61c938c36d88 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -589,7 +589,7 @@ static void net2280_free_request(struct usb_ep *_ep, struct usb_request *_req) ep = container_of(_ep, struct net2280_ep, ep); if (!_ep || !_req) { - dev_err(&ep->dev->pdev->dev, "%s: Inavlid ep=%p or req=%p\n", + dev_err(&ep->dev->pdev->dev, "%s: Invalid ep=%p or req=%p\n", __func__, _ep, _req); return; } From 60e7396f820fa67a007f2a2eb5d97d3e77a74881 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 22 Aug 2016 17:48:25 +0900 Subject: [PATCH 202/343] usb: gadget: add a new quirk to avoid skb_reserve in u_ether.c Some platforms (e.g. USB-DMAC on R-Car SoCs) has memory alignment restriction. If memory alignment is not match, the usb peripheral driver decides not to use the DMA controller. Then, the performance is not good. In the case of u_ether.c, since it calls skb_reserve() in rx_submit(), it is possible to cause memory alignment mismatch. So, this patch adds a new quirk "quirk_avoids_skb_reserve" to avoid skb_reserve() calling in u_ether.c to improve performance. A peripheral driver will set this flag and network gadget drivers (e.g. f_ncm.c) will reference the flag via gadget_avoids_skb_reserve(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- include/linux/usb/gadget.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3cc93237ff98..8e81f9eb95e4 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -346,6 +346,8 @@ struct usb_gadget_ops { * or B-Peripheral wants to take host role. * @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to * MaxPacketSize. + * @quirk_avoids_skb_reserve: udc/platform wants to avoid skb_reserve() in + * u_ether.c to improve performance. * @is_selfpowered: if the gadget is self-powered. * @deactivated: True if gadget is deactivated - in deactivated state it cannot * be connected. @@ -398,6 +400,7 @@ struct usb_gadget { unsigned quirk_altset_not_supp:1; unsigned quirk_stall_not_supp:1; unsigned quirk_zlp_not_supp:1; + unsigned quirk_avoids_skb_reserve:1; unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; @@ -473,6 +476,16 @@ static inline int gadget_is_zlp_supported(struct usb_gadget *g) return !g->quirk_zlp_not_supp; } +/** + * gadget_avoids_skb_reserve - return true iff the hardware would like to avoid + * skb_reserve to improve performance. + * @g: controller to check for quirk + */ +static inline int gadget_avoids_skb_reserve(struct usb_gadget *g) +{ + return g->quirk_avoids_skb_reserve; +} + /** * gadget_is_dualspeed - return true iff the hardware handles high speed * @g: controller that might support both high and full speeds From 05f6b0ff68429bb7c6b84b35e71b522c3bae76ae Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 22 Aug 2016 17:48:26 +0900 Subject: [PATCH 203/343] usb: gadget: u_ether: add a flag to avoid skb_reserve() calling This patch adds a flag "no_skb_reserve" in struct eth_dev. So, if a peripheral driver sets the quirk_avoids_skb_reserve flag, upper network gadget drivers (e.g. f_ncm.c) can avoid skb_reserve() calling using the flag as well. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_ether.c | 5 ++++- drivers/usb/gadget/function/u_ether.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 5f562c1ec795..3be4b93fd415 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -82,6 +82,7 @@ struct eth_dev { #define WORK_RX_MEMORY 0 bool zlp; + bool no_skb_reserve; u8 host_mac[ETH_ALEN]; u8 dev_mac[ETH_ALEN]; }; @@ -233,7 +234,8 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) * but on at least one, checksumming fails otherwise. Note: * RNDIS headers involve variable numbers of LE32 values. */ - skb_reserve(skb, NET_IP_ALIGN); + if (likely(!dev->no_skb_reserve)) + skb_reserve(skb, NET_IP_ALIGN); req->buf = skb->data; req->length = size; @@ -1063,6 +1065,7 @@ struct net_device *gether_connect(struct gether *link) if (result == 0) { dev->zlp = link->is_zlp_ok; + dev->no_skb_reserve = link->no_skb_reserve; DBG(dev, "qlen %d\n", qlen(dev->gadget, dev->qmult)); dev->header_len = link->header_len; diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index c77145bd6b5b..81d94a7ae4b4 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -64,6 +64,7 @@ struct gether { struct usb_ep *out_ep; bool is_zlp_ok; + bool no_skb_reserve; u16 cdc_filter; From c4824f11fe07835c63209fb035f03f8f82e12827 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 22 Aug 2016 17:48:27 +0900 Subject: [PATCH 204/343] usb: gadget: f_ncm: add support for no_skb_reserve This patch adds to support no_skb_reserve function to improve performance for some platforms. About the detail, please refer to the commit log of "quirk_avoids_skb_reserve" in include/linux/usb/gadget.h. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_ncm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 08cff495195f..639603722709 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -924,6 +924,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) */ ncm->port.is_zlp_ok = gadget_is_zlp_supported(cdev->gadget); + ncm->port.no_skb_reserve = + gadget_avoids_skb_reserve(cdev->gadget); ncm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ncm\n"); net = gether_connect(&ncm->port); From ee5acabf5805612c72084276e0c215367a042d71 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 22 Aug 2016 17:48:28 +0900 Subject: [PATCH 205/343] usb: renesas_usbhs: set quirk_avoids_skb_reserve if USB-DMAC is used This patch sets the quirk_avoids_skb_reserve flag to improve performance of a network gadget driver (e.g. f_ncm.c) if USB-DMAC is used. For example (on r8a7795 board + f_ncm.c + iperf udp mode / receiving): - without this patch: 90.3 Mbits/sec - with this patch: 273 Mbits/sec Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 8e326ac00c9f..5732998de92a 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -1102,6 +1102,8 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) gpriv->gadget.name = "renesas_usbhs_udc"; gpriv->gadget.ops = &usbhsg_gadget_ops; gpriv->gadget.max_speed = USB_SPEED_HIGH; + gpriv->gadget.quirk_avoids_skb_reserve = usbhs_get_dparam(priv, + has_usb_dmac); INIT_LIST_HEAD(&gpriv->gadget.ep_list); From 4fbac5206afd01b717d4bdc58793d471f3391b4b Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Wed, 17 Aug 2016 12:36:57 +0200 Subject: [PATCH 206/343] usb: gadget: uvc: Add missing call for additional setup data Some UVC commands require additional data (non zero uvc->event_length). Add usb_ep_queue() call, so uvc_function_ep0_complete() can be called and send received data to the userspace. Signed-off-by: Petr Cvek Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uvc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 29b41b5dee04..27ed51b5082f 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -258,6 +258,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req)); v4l2_event_queue(&uvc->vdev, &v4l2_event); + /* Pass additional setup data to userspace */ + if (uvc->event_setup_out && uvc->event_length) { + uvc->control_req->length = uvc->event_length; + return usb_ep_queue(uvc->func.config->cdev->gadget->ep0, + uvc->control_req, GFP_ATOMIC); + } + return 0; } From da7b895d518cc1753ee5f4b7f2158087282d1a65 Mon Sep 17 00:00:00 2001 From: Romain Izard Date: Mon, 29 Aug 2016 12:22:29 +0300 Subject: [PATCH 207/343] usb: gadget: configfs: log function unbinding as debug Disabling USB gadget functions configured through configfs is something that can happen in normal use cases. Keep the existing log for this type of event, but only as debug, not as an error. Signed-off-by: Romain Izard Signed-off-by: Felipe Balbi --- drivers/usb/gadget/configfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index de844d44b998..3984787f8e97 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1211,7 +1211,7 @@ static void purge_configs_funcs(struct gadget_info *gi) list_move_tail(&f->list, &cfg->func_list); if (f->unbind) { - dev_info(&gi->cdev.gadget->dev, + dev_dbg(&gi->cdev.gadget->dev, "unbind function '%s'/%p\n", f->name, f); f->unbind(c, f); From ad674a15249e7d800162858e49272877a782ec40 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 29 Aug 2016 13:38:50 -0700 Subject: [PATCH 208/343] usb: dwc2: gadget: use ep->fifo_index in context of FIFO registers In context of FIFO registers we use ep->fifo_index instead of ep->index. Signed-off-by: Robert Baldyga Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 2ff03ae08e14..eae908951eab 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -388,7 +388,8 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, return -ENOSPC; } } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { - can_write = dwc2_readl(hsotg->regs + DTXFSTS(hs_ep->index)); + can_write = dwc2_readl(hsotg->regs + + DTXFSTS(hs_ep->fifo_index)); can_write &= 0xffff; can_write *= 4; @@ -2432,7 +2433,7 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, if (!hsotg->dedicated_fifos) return; - size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4; + size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->fifo_index)) & 0xffff) * 4; if (size < ep->fifo_size) dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index); } From aa381a7259c3f53727bcaa8c5f9359e940a0e3fd Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 29 Aug 2016 13:38:52 -0700 Subject: [PATCH 209/343] usb: dwc2: gadget: fix TX FIFO size and address initialization According to DWC2 documentation, DPTxFSize field of DPTXFSIZn register is read only, which means that software cannot change FIFO size. Register description says: "The value of this register is the Largest Device Mode Periodic Tx Data FIFO Depth (parameter OTG_TX_DPERIO_DFIFO_DEPTH_n), as specified during coreConsultant configuration." That means, that we have to setup only FIFO start addresses (DPTxFStAddr), taking into account reset values of DPTxFSize. Initialize FIFO start addresses properly and remove unneeded core related to incorrect FIFO size initialization. Signed-off-by: Robert Baldyga Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.h | 7 ------ drivers/usb/dwc2/gadget.c | 47 +++++++-------------------------------- 2 files changed, 8 insertions(+), 46 deletions(-) diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 9fae0291cd69..78526eedf519 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -259,13 +259,6 @@ enum dwc2_lx_state { DWC2_L3, /* Off state */ }; -/* - * Gadget periodic tx fifo sizes as used by legacy driver - * EP0 is not included - */ -#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \ - 768, 0, 0, 0, 0, 0, 0, 0} - /* Gadget ep0 states */ enum dwc2_ep0_state { DWC2_EP0_SETUP, diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index eae908951eab..7db763e2e975 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -189,6 +189,7 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) unsigned int ep; unsigned int addr; int timeout; + u32 dptxfsizn; u32 val; /* Reset fifo map if not correctly cleared during previous session */ @@ -217,13 +218,13 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) * given endpoint. */ for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { - if (!hsotg->g_tx_fifo_sz[ep]) - continue; - val = addr; - val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT; - WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem, - "insufficient fifo memory"); - addr += hsotg->g_tx_fifo_sz[ep]; + dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(ep)); + + val = (dptxfsizn & FIFOSIZE_DEPTH_MASK) | addr; + addr += dptxfsizn >> FIFOSIZE_DEPTH_SHIFT; + + if (addr > hsotg->fifo_mem) + break; dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep)); } @@ -3814,36 +3815,10 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) static void dwc2_hsotg_of_probe(struct dwc2_hsotg *hsotg) { struct device_node *np = hsotg->dev->of_node; - u32 len = 0; - u32 i = 0; /* Enable dma if requested in device tree */ hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma"); - /* - * Register TX periodic fifo size per endpoint. - * EP0 is excluded since it has no fifo configuration. - */ - if (!of_find_property(np, "g-tx-fifo-size", &len)) - goto rx_fifo; - - len /= sizeof(u32); - - /* Read tx fifo sizes other than ep0 */ - if (of_property_read_u32_array(np, "g-tx-fifo-size", - &hsotg->g_tx_fifo_sz[1], len)) - goto rx_fifo; - - /* Add ep0 */ - len++; - - /* Make remaining TX fifos unavailable */ - if (len < MAX_EPS_CHANNELS) { - for (i = len; i < MAX_EPS_CHANNELS; i++) - hsotg->g_tx_fifo_sz[i] = 0; - } - -rx_fifo: /* Register RX fifo size */ of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz); @@ -3865,13 +3840,10 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) struct device *dev = hsotg->dev; int epnum; int ret; - int i; - u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE; /* Initialize to legacy fifo configuration values */ hsotg->g_rx_fifo_sz = 2048; hsotg->g_np_g_tx_fifo_sz = 1024; - memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo)); /* Device tree specific probe */ dwc2_hsotg_of_probe(hsotg); @@ -3889,9 +3861,6 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n", hsotg->g_np_g_tx_fifo_sz); dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz); - for (i = 0; i < MAX_EPS_CHANNELS; i++) - dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i, - hsotg->g_tx_fifo_sz[i]); hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; From ba48eab8866ca71e7978380cf7564cf8240f28f8 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 29 Aug 2016 13:38:55 -0700 Subject: [PATCH 210/343] usb: dwc2: gadget: change variable name to more meaningful Since we handle FIFOs and endpoint separately, using variable named 'ep' in context of FIFO is misleading, hence we rename it to 'fifo'. Signed-off-by: Robert Baldyga Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 7db763e2e975..2aa41139d2d5 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -186,7 +186,7 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, */ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) { - unsigned int ep; + unsigned int fifo; unsigned int addr; int timeout; u32 dptxfsizn; @@ -217,8 +217,8 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) * them to endpoints dynamically according to maxpacket size value of * given endpoint. */ - for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) { - dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(ep)); + for (fifo = 1; fifo < MAX_EPS_CHANNELS; fifo++) { + dptxfsizn = dwc2_readl(hsotg->regs + DPTXFSIZN(fifo)); val = (dptxfsizn & FIFOSIZE_DEPTH_MASK) | addr; addr += dptxfsizn >> FIFOSIZE_DEPTH_SHIFT; @@ -226,7 +226,7 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) if (addr > hsotg->fifo_mem) break; - dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep)); + dwc2_writel(val, hsotg->regs + DPTXFSIZN(fifo)); } /* From 21f3bb52986c5f0ab74d350486de38fafff6ddef Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 29 Aug 2016 13:38:57 -0700 Subject: [PATCH 211/343] usb: dwc2: gadget: remove dead code from dwc2_hsotg_ep_enable() Since FIFO is always freed in dwc2_hsotg_ep_disable(), ep->fifo_index is always 0 in dwc2_hsotg_ep_enable(), hence code inside if() block is never executed. Signed-off-by: Robert Baldyga Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 2aa41139d2d5..94698298e829 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3043,22 +3043,11 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, break; } - /* If fifo is already allocated for this ep */ - if (hs_ep->fifo_index) { - size = hs_ep->ep.maxpacket * hs_ep->mc; - /* If bigger fifo is required deallocate current one */ - if (size > hs_ep->fifo_size) { - hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); - hs_ep->fifo_index = 0; - hs_ep->fifo_size = 0; - } - } - /* * if the hardware has dedicated fifos, we must give each IN EP * a unique tx-fifo even if it is non-periodic. */ - if (dir_in && hsotg->dedicated_fifos && !hs_ep->fifo_index) { + if (dir_in && hsotg->dedicated_fifos) { u32 fifo_index = 0; u32 fifo_size = UINT_MAX; size = hs_ep->ep.maxpacket*hs_ep->mc; From 1c07b20eaa0e001b3f7811cb3e1dafc4f00648c3 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 29 Aug 2016 13:39:00 -0700 Subject: [PATCH 212/343] usb: dwc2: gadget: free TX FIFO after killing requests As kill_all_requests() potentially flushes TX FIFO, we should should free FIFO after calling it. Otherwise FIFO could stay unflushed properly. Signed-off-by: Robert Baldyga Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 94698298e829..94bd19ad7f5c 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3120,10 +3120,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) spin_lock_irqsave(&hsotg->lock, flags); - hsotg->fifo_map &= ~(1<fifo_index); - hs_ep->fifo_index = 0; - hs_ep->fifo_size = 0; - ctrl = dwc2_readl(hsotg->regs + epctrl_reg); ctrl &= ~DXEPCTL_EPENA; ctrl &= ~DXEPCTL_USBACTEP; @@ -3138,6 +3134,10 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) /* terminate all requests with shutdown */ kill_all_requests(hsotg, hs_ep, -ESHUTDOWN); + hsotg->fifo_map &= ~(1 << hs_ep->fifo_index); + hs_ep->fifo_index = 0; + hs_ep->fifo_size = 0; + spin_unlock_irqrestore(&hsotg->lock, flags); return 0; } From f7b7f375491b0016004b2c50118160de57908278 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 18 Aug 2016 09:45:04 -0400 Subject: [PATCH 213/343] usb: core: use IS_ENABLED() instead of checking for built-in or module The IS_ENABLED() macro checks if a Kconfig symbol has been enabled either built-in or as a module, use that macro instead of open coding the same. Using the macro makes the code more readable by helping abstract away some of the Kconfig built-in and module enable details. Signed-off-by: Javier Martinez Canillas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/otg_whitelist.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index a0c87b617edd..746c47d86cf5 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -3031,7 +3031,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); /*-------------------------------------------------------------------------*/ -#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) +#if IS_ENABLED(CONFIG_USB_MON) const struct usb_mon_operations *mon_ops; diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index a95b0c989c21..085049d37d7a 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -38,7 +38,7 @@ static struct usb_device_id whitelist_table[] = { { USB_DEVICE(0x0525, 0xa4a2), }, #endif -#if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE) +#if IS_ENABLED(CONFIG_USB_TEST) /* gadget zero, for testing */ { USB_DEVICE(0x0525, 0xa4a0), }, #endif From 3112fdde68fa4a3b0b3a3a738f9f32b4d62fdf05 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 18 Aug 2016 09:45:05 -0400 Subject: [PATCH 214/343] usb: gadget: use IS_ENABLED() instead of checking for built-in or module The IS_ENABLED() macro checks if a Kconfig symbol has been enabled either built-in or as a module, use that macro instead of open coding the same. Using the macro makes the code more readable by helping abstract away some of the Kconfig built-in and module enable details. Signed-off-by: Javier Martinez Canillas Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/omap_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index 9b7d39484ed3..a8709f9e5648 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2875,7 +2875,7 @@ bad_on_1710: xceiv = NULL; /* "udc" is now valid */ pullup_disable(udc); -#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) +#if IS_ENABLED(CONFIG_USB_OHCI_HCD) udc->gadget.is_otg = (config->otg != 0); #endif From 65e1ff7f4b5b37d84c058a09d60ca2a0acff7cfd Mon Sep 17 00:00:00 2001 From: John Youn Date: Mon, 29 Aug 2016 13:39:03 -0700 Subject: [PATCH 215/343] Documentation: devicetree: dwc2: Deprecate g-tx-fifo-size This property is not needed because the periodic fifos are not configurable. So it was incorrect to add this property in the first place. Acked-by: Rob Herring Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc2.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt index 20a68bf2b4e7..7d16ebfaa5a1 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.txt +++ b/Documentation/devicetree/bindings/usb/dwc2.txt @@ -26,7 +26,10 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties - g-use-dma: enable dma usage in gadget driver. - g-rx-fifo-size: size of rx fifo size in gadget mode. - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. -- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode. + +Deprecated properties: +- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) + in gadget mode. Example: From 51b0ce387b43ba8ed532e6f9f215d891e1899e0a Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Tue, 16 Aug 2016 19:04:46 +0300 Subject: [PATCH 216/343] usb: ulpi: move setting of ulpi->dev parent up in ulpi_register() Once ulpi operations use the parent device directly, this will be needed during the operations used in ulpi_register() itself, so set the parent field before calling any ulpi operations. Acked-by: Heikki Krogerus Signed-off-by: Tal Shorer Signed-off-by: Felipe Balbi --- drivers/usb/common/ulpi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 01c0c0477a9e..d1f419c7cddb 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -156,6 +156,8 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi) { int ret; + ulpi->dev.parent = dev; /* needed early for ops */ + /* Test the interface */ ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa); if (ret < 0) @@ -174,7 +176,6 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi) ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW); ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8; - ulpi->dev.parent = dev; ulpi->dev.bus = &ulpi_bus; ulpi->dev.type = &ulpi_dev_type; dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev)); From 6691402313ddda232e6a401af8841b5fe676a62f Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Tue, 16 Aug 2016 19:04:47 +0300 Subject: [PATCH 217/343] usb: ulpi: add new api functions, {read|write}_dev() Add these two new api callbacks to struct ulpi_ops. These are different than read, write in that they pass the parent device directly instead of via the ops argument. They are intended to replace the old api functions. If the new api callbacks are missing, revert to calling the old ones as before. Acked-by: Heikki Krogerus Signed-off-by: Tal Shorer Signed-off-by: Felipe Balbi --- drivers/usb/common/ulpi.c | 8 ++++++-- include/linux/ulpi/interface.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index d1f419c7cddb..a877ddbbe826 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -21,13 +21,17 @@ int ulpi_read(struct ulpi *ulpi, u8 addr) { - return ulpi->ops->read(ulpi->ops, addr); + if (!ulpi->ops->read_dev) + return ulpi->ops->read(ulpi->ops, addr); + return ulpi->ops->read_dev(ulpi->dev.parent, addr); } EXPORT_SYMBOL_GPL(ulpi_read); int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val) { - return ulpi->ops->write(ulpi->ops, addr, val); + if (!ulpi->ops->write_dev) + return ulpi->ops->write(ulpi->ops, addr, val); + return ulpi->ops->write_dev(ulpi->dev.parent, addr, val); } EXPORT_SYMBOL_GPL(ulpi_write); diff --git a/include/linux/ulpi/interface.h b/include/linux/ulpi/interface.h index 4de8ab491038..d8189d08eddb 100644 --- a/include/linux/ulpi/interface.h +++ b/include/linux/ulpi/interface.h @@ -15,6 +15,8 @@ struct ulpi_ops { struct device *dev; int (*read)(struct ulpi_ops *ops, u8 addr); int (*write)(struct ulpi_ops *ops, u8 addr, u8 val); + int (*read_dev)(struct device *dev, u8 addr); + int (*write_dev)(struct device *dev, u8 addr, u8 val); }; struct ulpi *ulpi_register_interface(struct device *, struct ulpi_ops *); From b7cf1dc3414de59f178734466f6cfff5171a8ffb Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Tue, 16 Aug 2016 19:04:48 +0300 Subject: [PATCH 218/343] usb: dwc3: ulpi: use new api The old read, write callbacks in struct ulpi_ops have been deprecated in favor of new callbacks that pass the parent device directly. Replace the used callbacks in dwc3's ulpi component with the new api. Reviewed-by: Heikki Krogerus Signed-off-by: Tal Shorer Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ulpi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c index ec004c6d76f2..94eeb7a42dbd 100644 --- a/drivers/usb/dwc3/ulpi.c +++ b/drivers/usb/dwc3/ulpi.c @@ -35,9 +35,9 @@ static int dwc3_ulpi_busyloop(struct dwc3 *dwc) return -ETIMEDOUT; } -static int dwc3_ulpi_read(struct ulpi_ops *ops, u8 addr) +static int dwc3_ulpi_read(struct device *dev, u8 addr) { - struct dwc3 *dwc = dev_get_drvdata(ops->dev); + struct dwc3 *dwc = dev_get_drvdata(dev); u32 reg; int ret; @@ -53,9 +53,9 @@ static int dwc3_ulpi_read(struct ulpi_ops *ops, u8 addr) return DWC3_GUSB2PHYACC_DATA(reg); } -static int dwc3_ulpi_write(struct ulpi_ops *ops, u8 addr, u8 val) +static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val) { - struct dwc3 *dwc = dev_get_drvdata(ops->dev); + struct dwc3 *dwc = dev_get_drvdata(dev); u32 reg; reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); @@ -66,8 +66,8 @@ static int dwc3_ulpi_write(struct ulpi_ops *ops, u8 addr, u8 val) } static struct ulpi_ops dwc3_ulpi_ops = { - .read = dwc3_ulpi_read, - .write = dwc3_ulpi_write, + .read_dev = dwc3_ulpi_read, + .write_dev = dwc3_ulpi_write, }; int dwc3_ulpi_init(struct dwc3 *dwc) From 5c42f38795645834a7c23998bd74d35a37bff078 Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Tue, 16 Aug 2016 19:04:49 +0300 Subject: [PATCH 219/343] usb: ulpi: remove calls to old api callbacks Now that all users use the new api callbacks, remove the old api callbacks and force new interface drivers to use the new api. Acked-by: Heikki Krogerus Signed-off-by: Tal Shorer Signed-off-by: Felipe Balbi --- drivers/usb/common/ulpi.c | 4 ---- include/linux/ulpi/interface.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index a877ddbbe826..43142c3d94d7 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -21,16 +21,12 @@ int ulpi_read(struct ulpi *ulpi, u8 addr) { - if (!ulpi->ops->read_dev) - return ulpi->ops->read(ulpi->ops, addr); return ulpi->ops->read_dev(ulpi->dev.parent, addr); } EXPORT_SYMBOL_GPL(ulpi_read); int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val) { - if (!ulpi->ops->write_dev) - return ulpi->ops->write(ulpi->ops, addr, val); return ulpi->ops->write_dev(ulpi->dev.parent, addr, val); } EXPORT_SYMBOL_GPL(ulpi_write); diff --git a/include/linux/ulpi/interface.h b/include/linux/ulpi/interface.h index d8189d08eddb..71f3c99771aa 100644 --- a/include/linux/ulpi/interface.h +++ b/include/linux/ulpi/interface.h @@ -13,8 +13,6 @@ struct ulpi; */ struct ulpi_ops { struct device *dev; - int (*read)(struct ulpi_ops *ops, u8 addr); - int (*write)(struct ulpi_ops *ops, u8 addr, u8 val); int (*read_dev)(struct device *dev, u8 addr); int (*write_dev)(struct device *dev, u8 addr, u8 val); }; From e6f74849784ccf275226d5d3ddfb96c71fa90383 Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Tue, 16 Aug 2016 19:04:50 +0300 Subject: [PATCH 220/343] usb: ulpi: rename operations {read|write}_dev to simply {read|write} With the removal of the old {read|write} operations, we can now safely rename the new api operations {read|write}_dev to use the shorter and clearer names {read|write}, respectively. Acked-by: Heikki Krogerus Signed-off-by: Tal Shorer Signed-off-by: Felipe Balbi --- drivers/usb/common/ulpi.c | 4 ++-- drivers/usb/dwc3/ulpi.c | 4 ++-- include/linux/ulpi/interface.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 43142c3d94d7..fdaed7c26c12 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -21,13 +21,13 @@ int ulpi_read(struct ulpi *ulpi, u8 addr) { - return ulpi->ops->read_dev(ulpi->dev.parent, addr); + return ulpi->ops->read(ulpi->dev.parent, addr); } EXPORT_SYMBOL_GPL(ulpi_read); int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val) { - return ulpi->ops->write_dev(ulpi->dev.parent, addr, val); + return ulpi->ops->write(ulpi->dev.parent, addr, val); } EXPORT_SYMBOL_GPL(ulpi_write); diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c index 94eeb7a42dbd..51ac939b2dfc 100644 --- a/drivers/usb/dwc3/ulpi.c +++ b/drivers/usb/dwc3/ulpi.c @@ -66,8 +66,8 @@ static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val) } static struct ulpi_ops dwc3_ulpi_ops = { - .read_dev = dwc3_ulpi_read, - .write_dev = dwc3_ulpi_write, + .read = dwc3_ulpi_read, + .write = dwc3_ulpi_write, }; int dwc3_ulpi_init(struct dwc3 *dwc) diff --git a/include/linux/ulpi/interface.h b/include/linux/ulpi/interface.h index 71f3c99771aa..ac3cd8058d9c 100644 --- a/include/linux/ulpi/interface.h +++ b/include/linux/ulpi/interface.h @@ -13,8 +13,8 @@ struct ulpi; */ struct ulpi_ops { struct device *dev; - int (*read_dev)(struct device *dev, u8 addr); - int (*write_dev)(struct device *dev, u8 addr, u8 val); + int (*read)(struct device *dev, u8 addr); + int (*write)(struct device *dev, u8 addr, u8 val); }; struct ulpi *ulpi_register_interface(struct device *, struct ulpi_ops *); From 042b0f31b2a87799a9c832f71474c5be3517e139 Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Tue, 16 Aug 2016 19:04:51 +0300 Subject: [PATCH 221/343] usb: ulpi: remove "dev" field from struct ulpi_ops Operations now use ulpi->dev.parent directly instead of via the ulpi_ops struct, making this field unused. Remove it. Acked-by: Heikki Krogerus Signed-off-by: Tal Shorer Signed-off-by: Felipe Balbi --- drivers/usb/common/ulpi.c | 1 - include/linux/ulpi/interface.h | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index fdaed7c26c12..0439e9638813 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -212,7 +212,6 @@ struct ulpi *ulpi_register_interface(struct device *dev, struct ulpi_ops *ops) return ERR_PTR(-ENOMEM); ulpi->ops = ops; - ops->dev = dev; ret = ulpi_register(dev, ulpi); if (ret) { diff --git a/include/linux/ulpi/interface.h b/include/linux/ulpi/interface.h index ac3cd8058d9c..cdedac87ed48 100644 --- a/include/linux/ulpi/interface.h +++ b/include/linux/ulpi/interface.h @@ -4,15 +4,14 @@ #include struct ulpi; +struct device; /** * struct ulpi_ops - ULPI register access - * @dev: the interface provider * @read: read operation for ULPI register access * @write: write operation for ULPI register access */ struct ulpi_ops { - struct device *dev; int (*read)(struct device *dev, u8 addr); int (*write)(struct device *dev, u8 addr, u8 val); }; From b9454f90c9432e1a70389c26c34e972090efcec6 Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Tue, 16 Aug 2016 19:04:52 +0300 Subject: [PATCH 222/343] usb: ulpi: make ops struct constant None of the core ulpi functions perform any changes to the operations struct, and logically as a struct that contains function pointers there's no reason it shouldn't be constant. Acked-by: Heikki Krogerus Signed-off-by: Tal Shorer Signed-off-by: Felipe Balbi --- drivers/usb/common/ulpi.c | 3 ++- include/linux/ulpi/driver.h | 2 +- include/linux/ulpi/interface.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 0439e9638813..d4ff6df859eb 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -202,7 +202,8 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi) * Allocates and registers a ULPI device and an interface for it. Called from * the USB controller that provides the ULPI interface. */ -struct ulpi *ulpi_register_interface(struct device *dev, struct ulpi_ops *ops) +struct ulpi *ulpi_register_interface(struct device *dev, + const struct ulpi_ops *ops) { struct ulpi *ulpi; int ret; diff --git a/include/linux/ulpi/driver.h b/include/linux/ulpi/driver.h index 388f6e08b9d4..a44408f6d532 100644 --- a/include/linux/ulpi/driver.h +++ b/include/linux/ulpi/driver.h @@ -15,7 +15,7 @@ struct ulpi_ops; */ struct ulpi { struct ulpi_device_id id; - struct ulpi_ops *ops; + const struct ulpi_ops *ops; struct device dev; }; diff --git a/include/linux/ulpi/interface.h b/include/linux/ulpi/interface.h index cdedac87ed48..a2011a919eb6 100644 --- a/include/linux/ulpi/interface.h +++ b/include/linux/ulpi/interface.h @@ -16,7 +16,7 @@ struct ulpi_ops { int (*write)(struct device *dev, u8 addr, u8 val); }; -struct ulpi *ulpi_register_interface(struct device *, struct ulpi_ops *); +struct ulpi *ulpi_register_interface(struct device *, const struct ulpi_ops *); void ulpi_unregister_interface(struct ulpi *); #endif /* __LINUX_ULPI_INTERFACE_H */ From 073c47aca7b7ccc6dd3fb21a3ee8134e30d8b327 Mon Sep 17 00:00:00 2001 From: Tal Shorer Date: Tue, 16 Aug 2016 19:04:53 +0300 Subject: [PATCH 223/343] usb: dwc3: ulpi: make dwc3_ulpi_ops constant ulpi_register_interface() accepts a const struct ulpi_ops and dwc3 doesn't perform any changes to this struct at runtime, so there's no reason it shouldn't be constant. Reviewed-by: Heikki Krogerus Signed-off-by: Tal Shorer Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ulpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c index 51ac939b2dfc..bd86f84f3790 100644 --- a/drivers/usb/dwc3/ulpi.c +++ b/drivers/usb/dwc3/ulpi.c @@ -65,7 +65,7 @@ static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val) return dwc3_ulpi_busyloop(dwc); } -static struct ulpi_ops dwc3_ulpi_ops = { +static const struct ulpi_ops dwc3_ulpi_ops = { .read = dwc3_ulpi_read, .write = dwc3_ulpi_write, }; From 9d6173e125d92e38d4e39bc71f0c3c2cf95cba1a Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Tue, 6 Sep 2016 19:22:03 -0700 Subject: [PATCH 224/343] usb: dwc3: Fix dr_mode validation This patch follows the similar fix in dwc2. See commit 5268ed9d2e3b ("usb: dwc2: Fix dr_mode validation") Currently, the dr_mode is only checked against the module configuration. It also needs to be checked against the hardware capablities. The driver now checks if both the module configuration and hardware are capable of the dr_mode value. If not, then it will issue a warning and fall back to a supported value. If it is unable to fall back to a suitable value, then the probe will fail. Behavior summary: module : actual HW config dr_mode : dr_mode --------------------------------- host host any : host host dev any : INVALID host otg any : host dev host any : INVALID dev dev any : dev dev otg any : dev otg host any : host otg dev any : dev otg otg any : dr_mode Signed-off-by: Thinh Nguyen Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 65 ++++++++++++++++++++++++++++++++++------- drivers/usb/dwc3/core.h | 5 +++- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d6d3fa0fa528..dcacc7056271 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -49,6 +49,57 @@ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ +/** + * dwc3_get_dr_mode - Validates and sets dr_mode + * @dwc: pointer to our context structure + */ +static int dwc3_get_dr_mode(struct dwc3 *dwc) +{ + enum usb_dr_mode mode; + struct device *dev = dwc->dev; + unsigned int hw_mode; + + if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) + dwc->dr_mode = USB_DR_MODE_OTG; + + mode = dwc->dr_mode; + hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0); + + switch (hw_mode) { + case DWC3_GHWPARAMS0_MODE_GADGET: + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) { + dev_err(dev, + "Controller does not support host mode.\n"); + return -EINVAL; + } + mode = USB_DR_MODE_PERIPHERAL; + break; + case DWC3_GHWPARAMS0_MODE_HOST: + if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) { + dev_err(dev, + "Controller does not support device mode.\n"); + return -EINVAL; + } + mode = USB_DR_MODE_HOST; + break; + default: + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) + mode = USB_DR_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) + mode = USB_DR_MODE_PERIPHERAL; + } + + if (mode != dwc->dr_mode) { + dev_warn(dev, + "Configuration mismatch. dr_mode forced to %s\n", + mode == USB_DR_MODE_HOST ? "host" : "gadget"); + + dwc->dr_mode = mode; + } + + return 0; +} + void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; @@ -1023,17 +1074,9 @@ static int dwc3_probe(struct platform_device *pdev) goto err2; } - if (IS_ENABLED(CONFIG_USB_DWC3_HOST) && - (dwc->dr_mode == USB_DR_MODE_OTG || - dwc->dr_mode == USB_DR_MODE_UNKNOWN)) - dwc->dr_mode = USB_DR_MODE_HOST; - else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) && - (dwc->dr_mode == USB_DR_MODE_OTG || - dwc->dr_mode == USB_DR_MODE_UNKNOWN)) - dwc->dr_mode = USB_DR_MODE_PERIPHERAL; - - if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) - dwc->dr_mode = USB_DR_MODE_OTG; + ret = dwc3_get_dr_mode(dwc); + if (ret) + goto err3; ret = dwc3_alloc_scratch_buffers(dwc); if (ret) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index b2317e702f57..6b60e42626a2 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -245,7 +245,10 @@ #define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff) /* Global HWPARAMS0 Register */ -#define DWC3_GHWPARAMS0_USB3_MODE(n) ((n) & 0x3) +#define DWC3_GHWPARAMS0_MODE(n) ((n) & 0x3) +#define DWC3_GHWPARAMS0_MODE_GADGET 0 +#define DWC3_GHWPARAMS0_MODE_HOST 1 +#define DWC3_GHWPARAMS0_MODE_DRD 2 #define DWC3_GHWPARAMS0_MBUS_TYPE(n) (((n) >> 3) & 0x7) #define DWC3_GHWPARAMS0_SBUS_TYPE(n) (((n) >> 6) & 0x3) #define DWC3_GHWPARAMS0_MDWIDTH(n) (((n) >> 8) & 0xff) From 3262ad824307c275922161e82c2db1458822f28c Mon Sep 17 00:00:00 2001 From: Jim Baxter Date: Thu, 8 Sep 2016 11:18:16 +0200 Subject: [PATCH 225/343] usb: gadget: f_fs: Stop ffs_closed NULL pointer dereference The struct ffs_data::private_data has a pointer to ffs_dev stored in it during the ffs_fs_mount() function however it is not cleared when the ffs_dev is freed later which causes the ffs_closed function to crash with "Unable to handle kernel NULL pointer dereference" error when using the data in ffs_data::private_data. This clears this pointer during the ffs_free_dev clean up function. Signed-off-by: Jim Baxter Signed-off-by: Jiada Wang Signed-off-by: Harish Jenny K N Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 998697bd80ac..0aeed85bb5cb 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -3502,6 +3502,11 @@ static void _ffs_free_dev(struct ffs_dev *dev) list_del(&dev->entry); if (dev->name_allocated) kfree(dev->name); + + /* Clear the private_data pointer to stop incorrect dev access */ + if (dev->ffs_data) + dev->ffs_data->private_data = NULL; + kfree(dev); if (list_empty(&ffs_devices)) functionfs_cleanup(); From d0f0ac56b34b28e80223d7086b4decdf027c27ed Mon Sep 17 00:00:00 2001 From: John Youn Date: Wed, 7 Sep 2016 19:39:37 -0700 Subject: [PATCH 226/343] usb: dwc2: gadget: Only initialize device if in device mode In dwc2_hsotg_udc_start(), don't initialize the controller for device mode unless we are actually in device mode. Tested-by: Heiko Stuebner Tested-by: Stefan Wahren Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 94bd19ad7f5c..4cd6403a7566 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3466,8 +3466,11 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget); spin_lock_irqsave(&hsotg->lock, flags); - dwc2_hsotg_init(hsotg); - dwc2_hsotg_core_init_disconnected(hsotg, false); + if (dwc2_hw_is_device(hsotg)) { + dwc2_hsotg_init(hsotg); + dwc2_hsotg_core_init_disconnected(hsotg, false); + } + hsotg->enabled = 0; spin_unlock_irqrestore(&hsotg->lock, flags); From fef6bc37dbafe0d6d71c808c8867a8c5ab4b9816 Mon Sep 17 00:00:00 2001 From: John Youn Date: Wed, 7 Sep 2016 19:39:40 -0700 Subject: [PATCH 227/343] usb: dwc2: Add delay to core soft reset Add a delay to the core soft reset function to account for the IDDIG debounce filter. If the current mode is host, either due to the force mode bit being set (which persists after core reset) or the connector id pin, a core soft reset will temporarily reset the mode to device and a delay from the IDDIG debounce filter will occur before going back to host mode. Tested-by: Stefan Wahren Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.c | 95 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/dwc2/core.h | 1 + drivers/usb/dwc2/hw.h | 1 + 3 files changed, 97 insertions(+) diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 4135a5ff67ca..a3068e01c609 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -238,6 +238,77 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg) return ret; } +/** + * dwc2_wait_for_mode() - Waits for the controller mode. + * @hsotg: Programming view of the DWC_otg controller. + * @host_mode: If true, waits for host mode, otherwise device mode. + */ +static void dwc2_wait_for_mode(struct dwc2_hsotg *hsotg, + bool host_mode) +{ + ktime_t start; + ktime_t end; + unsigned int timeout = 110; + + dev_vdbg(hsotg->dev, "Waiting for %s mode\n", + host_mode ? "host" : "device"); + + start = ktime_get(); + + while (1) { + s64 ms; + + if (dwc2_is_host_mode(hsotg) == host_mode) { + dev_vdbg(hsotg->dev, "%s mode set\n", + host_mode ? "Host" : "Device"); + break; + } + + end = ktime_get(); + ms = ktime_to_ms(ktime_sub(end, start)); + + if (ms >= (s64)timeout) { + dev_warn(hsotg->dev, "%s: Couldn't set %s mode\n", + __func__, host_mode ? "host" : "device"); + break; + } + + usleep_range(1000, 2000); + } +} + +/** + * dwc2_iddig_filter_enabled() - Returns true if the IDDIG debounce + * filter is enabled. + */ +static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) +{ + u32 gsnpsid; + u32 ghwcfg4; + + if (!dwc2_hw_is_otg(hsotg)) + return false; + + /* Check if core configuration includes the IDDIG filter. */ + ghwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4); + if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN)) + return false; + + /* + * Check if the IDDIG debounce filter is bypassed. Available + * in core version >= 3.10a. + */ + gsnpsid = dwc2_readl(hsotg->regs + GSNPSID); + if (gsnpsid >= DWC2_CORE_REV_3_10a) { + u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); + + if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS) + return false; + } + + return true; +} + /* * Do core a soft reset of the core. Be careful with this because it * resets all the internal state machines of the core. @@ -246,9 +317,30 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg) { u32 greset; int count = 0; + bool wait_for_host_mode = false; dev_vdbg(hsotg->dev, "%s()\n", __func__); + /* + * If the current mode is host, either due to the force mode + * bit being set (which persists after core reset) or the + * connector id pin, a core soft reset will temporarily reset + * the mode to device. A delay from the IDDIG debounce filter + * will occur before going back to host mode. + * + * Determine whether we will go back into host mode after a + * reset and account for this delay after the reset. + */ + if (dwc2_iddig_filter_enabled(hsotg)) { + u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); + u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); + + if (!(gotgctl & GOTGCTL_CONID_B) || + (gusbcfg & GUSBCFG_FORCEHOSTMODE)) { + wait_for_host_mode = true; + } + } + /* Core Soft Reset */ greset = dwc2_readl(hsotg->regs + GRSTCTL); greset |= GRSTCTL_CSFTRST; @@ -277,6 +369,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg) } } while (!(greset & GRSTCTL_AHBIDLE)); + if (wait_for_host_mode) + dwc2_wait_for_mode(hsotg, true); + return 0; } diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 78526eedf519..466c220914d4 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -882,6 +882,7 @@ struct dwc2_hsotg { #define DWC2_CORE_REV_2_92a 0x4f54292a #define DWC2_CORE_REV_2_94a 0x4f54294a #define DWC2_CORE_REV_3_00a 0x4f54300a +#define DWC2_CORE_REV_3_10a 0x4f54310a #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) union dwc2_hcd_internal_flags { diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index efc3bcde2822..91058441e62a 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -48,6 +48,7 @@ #define GOTGCTL_ASESVLD (1 << 18) #define GOTGCTL_DBNC_SHORT (1 << 17) #define GOTGCTL_CONID_B (1 << 16) +#define GOTGCTL_DBNCE_FLTR_BYPASS (1 << 15) #define GOTGCTL_DEVHNPEN (1 << 11) #define GOTGCTL_HSTSETHNPEN (1 << 10) #define GOTGCTL_HNPREQ (1 << 9) From 2938fc63e0c26bf694436ac81bc776c8b7eced0c Mon Sep 17 00:00:00 2001 From: John Youn Date: Wed, 7 Sep 2016 19:39:43 -0700 Subject: [PATCH 228/343] usb: dwc2: Properly account for the force mode delays When a force mode bit is set and the IDDIG debounce filter is enabled, there is a delay for the forced mode to take effect. This delay is due to the IDDIG debounce filter and is variable depending on the platform's PHY clock speed. To account for this delay we can poll for the expected mode. On a clear force mode, since we don't know what mode to poll for, delay for a fixed 100 ms. This is the maximum delay based on the slowest PHY clock speed. Tested-by: Stefan Wahren Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/core.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index a3068e01c609..fa9b26b91507 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -395,9 +395,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg) * Checks are done in this function to determine whether doing a force * would be valid or not. * - * If a force is done, it requires a 25ms delay to take effect. - * - * Returns true if the mode was forced. + * If a force is done, it requires a IDDIG debounce filter delay if + * the filter is configured and enabled. We poll the current mode of + * the controller to account for this delay. */ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) { @@ -432,12 +432,18 @@ static bool dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host) gusbcfg |= set; dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); - msleep(25); + dwc2_wait_for_mode(hsotg, host); return true; } -/* - * Clears the force mode bits. +/** + * dwc2_clear_force_mode() - Clears the force mode bits. + * + * After clearing the bits, wait up to 100 ms to account for any + * potential IDDIG filter delay. We can't know if we expect this delay + * or not because the value of the connector ID status is affected by + * the force mode. We only need to call this once during probe if + * dr_mode == OTG. */ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) { @@ -448,11 +454,8 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) gusbcfg &= ~GUSBCFG_FORCEDEVMODE; dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); - /* - * NOTE: This long sleep is _very_ important, otherwise the core will - * not stay in host mode after a connector ID change! - */ - msleep(25); + if (dwc2_iddig_filter_enabled(hsotg)) + usleep_range(100000, 110000); } /* @@ -475,12 +478,6 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) __func__, hsotg->dr_mode); break; } - - /* - * NOTE: This is required for some rockchip soc based - * platforms. - */ - msleep(50); } /* From 5387c920372a3aaeb97b8b4721619ca9ff2a82ab Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 8 Sep 2016 21:09:30 +0100 Subject: [PATCH 229/343] usb: gadget: remove variable ret and remove unnecessary if statement the if statement in lb_modinit is unnecessary so we can totally remove the variable ret and just return the return value from the call to usb_function_register. Signed-off-by: Colin Ian King Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_loopback.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index ddb8c896eaa3..e70093835e14 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c @@ -591,13 +591,9 @@ DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc); int __init lb_modinit(void) { - int ret; - - ret = usb_function_register(&Loopbackusb_func); - if (ret) - return ret; - return ret; + return usb_function_register(&Loopbackusb_func); } + void __exit lb_modexit(void) { usb_function_unregister(&Loopbackusb_func); From 79775f441838403be856e06eaab893a3fe9dd7b2 Mon Sep 17 00:00:00 2001 From: Harish Jenny K N Date: Fri, 9 Sep 2016 11:30:41 +0200 Subject: [PATCH 230/343] usb: gadget: u_ether: fix another dereference after null check dev->port_usb is checked for null pointer previously, so dev->port_usb might be null during no zlp check, fix it by adding null pointer check. Acked-by: Jim Baxter Signed-off-by: Harish Jenny K N Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_ether.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 3be4b93fd415..9c8c9ed1dc9e 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -571,7 +571,8 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->complete = tx_complete; /* NCM requires no zlp if transfer is dwNtbInMaxSize */ - if (dev->port_usb->is_fixed && + if (dev->port_usb && + dev->port_usb->is_fixed && length == dev->port_usb->fixed_in_len && (length % in->maxpacket) == 0) req->zero = 0; From c9ffc78745f89e300fe704348dd8e6800acf4d18 Mon Sep 17 00:00:00 2001 From: Harish Jenny K N Date: Fri, 9 Sep 2016 11:30:42 +0200 Subject: [PATCH 231/343] usb: gadget: NCM: Protect dev->port_usb using dev->lock This commit incorporates findings from https://lkml.org/lkml/2016/4/25/594 The function has been modified to make sure we hold the dev lock when accessing the net device pointer. Acked-by: Jim Baxter Signed-off-by: Harish Jenny K N Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/u_ether.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 9c8c9ed1dc9e..8cb08033b7c1 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -553,14 +553,16 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) skb = dev->wrap(dev->port_usb, skb); - spin_unlock_irqrestore(&dev->lock, flags); if (!skb) { /* Multi frame CDC protocols may store the frame for * later which is not a dropped frame. */ if (dev->port_usb && - dev->port_usb->supports_multi_frame) + dev->port_usb->supports_multi_frame) { + spin_unlock_irqrestore(&dev->lock, flags); goto multiframe; + } + spin_unlock_irqrestore(&dev->lock, flags); goto drop; } } @@ -578,6 +580,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->zero = 0; else req->zero = 1; + spin_unlock_irqrestore(&dev->lock, flags); /* use zlp framing on tx for strict CDC-Ether conformance, * though any robust network rx path ignores extra padding. From d6e10bf2ba4783881670731faf8d3705cad488eb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Sep 2016 12:01:51 +0200 Subject: [PATCH 232/343] usb: dwc3: avoid -Wmaybe-uninitialized warning Cleaning up the loop in dwc3_cleanup_done_reqs() introduced a gcc warning if built with "-Wmaybe-uninitialized": drivers/usb/dwc3/gadget.c: In function 'dwc3_endpoint_transfer_complete': drivers/usb/dwc3/gadget.c:2015:9: 'trb' may be used uninitialized in this function [-Wmaybe-uninitialized] I believe it is a false positive and we always have a valid 'trb' pointer at the end of the function, but neither I nor the compiler are able to prove that. This works around the warning by computing a flag earlier in the function when it's guaranteed to be valid, which tells the compiler that it's safe and makes it easier to understand to me. Signed-off-by: Arnd Bergmann Fixes: 31162af447d7 ("usb: dwc3: gadget: avoid while (1) loop on completion") Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 37a86522fa88..a5d496dd53b2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1934,6 +1934,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, { struct dwc3_request *req, *n; struct dwc3_trb *trb; + bool ioc = false; int ret; list_for_each_entry_safe(req, n, &dep->started_list, list) { @@ -1981,8 +1982,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, dwc3_gadget_giveback(dep, req, status); - if (ret) + if (ret) { + if ((event->status & DEPEVT_STATUS_IOC) && + (trb->ctrl & DWC3_TRB_CTRL_IOC)) + ioc = true; break; + } } /* @@ -2010,10 +2015,9 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, return 1; } - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) - if ((event->status & DEPEVT_STATUS_IOC) && - (trb->ctrl & DWC3_TRB_CTRL_IOC)) - return 0; + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && ioc) + return 0; + return 1; } From ad764c49f65ac171e493e6baf39bc8ba296ef376 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 16 Aug 2016 17:33:25 +0800 Subject: [PATCH 233/343] usb: Kconfig: move ulpi bus support out of host The ULPI bus is not only for host, but for device mode too, so move it out from host's Kconfig. Signed-off-by: Peter Chen Acked-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 20 ++++++++++++++++++++ drivers/usb/core/Kconfig | 20 -------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 8689dcba5201..6dfa10af7185 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -160,4 +160,24 @@ config USB_LED_TRIG LEDs and you want to use them as activity indicators for USB host or gadget. +config USB_ULPI_BUS + tristate "USB ULPI PHY interface support" + help + UTMI+ Low Pin Interface (ULPI) is specification for a commonly used + USB 2.0 PHY interface. The ULPI specification defines a standard set + of registers that can be used to detect the vendor and product which + allows ULPI to be handled as a bus. This module is the driver for that + bus. + + The ULPI interfaces (the buses) are registered by the drivers for USB + controllers which support ULPI register access and have ULPI PHY + attached to them. The ULPI PHY drivers themselves are normal PHY + drivers. + + ULPI PHYs provide often functions such as ADP sensing/probing (OTG + protocol) and USB charger detection. + + To compile this driver as a module, choose M here: the module will + be called ulpi. + endif # USB_SUPPORT diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 253aac74cce1..d6e43ce96799 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -82,23 +82,3 @@ config USB_OTG_FSM help Implements OTG Finite State Machine as specified in On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification. - -config USB_ULPI_BUS - tristate "USB ULPI PHY interface support" - help - UTMI+ Low Pin Interface (ULPI) is specification for a commonly used - USB 2.0 PHY interface. The ULPI specification defines a standard set - of registers that can be used to detect the vendor and product which - allows ULPI to be handled as a bus. This module is the driver for that - bus. - - The ULPI interfaces (the buses) are registered by the drivers for USB - controllers which support ULPI register access and have ULPI PHY - attached to them. The ULPI PHY drivers themselves are normal PHY - drivers. - - ULPI PHYs provide often functions such as ADP sensing/probing (OTG - protocol) and USB charger detection. - - To compile this driver as a module, choose M here: the module will - be called ulpi. From ce8bb344dffb493fbc80027a28d4f03c029d775e Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 16 Aug 2016 15:12:22 +0200 Subject: [PATCH 234/343] cdc-wdm: add terminating newline Debug messages should be properly terminated. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index bf4bb58312fb..0a6369510f2d 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -171,15 +171,15 @@ static void wdm_in_callback(struct urb *urb) switch (status) { case -ENOENT: dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ENOENT"); + "nonzero urb status received: -ENOENT\n"); goto skip_error; case -ECONNRESET: dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ECONNRESET"); + "nonzero urb status received: -ECONNRESET\n"); goto skip_error; case -ESHUTDOWN: dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ESHUTDOWN"); + "nonzero urb status received: -ESHUTDOWN\n"); goto skip_error; case -EPIPE: dev_dbg(&desc->intf->dev, @@ -284,18 +284,18 @@ static void wdm_int_callback(struct urb *urb) switch (dr->bNotificationType) { case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: dev_dbg(&desc->intf->dev, - "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d", + "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d\n", le16_to_cpu(dr->wIndex), le16_to_cpu(dr->wLength)); break; case USB_CDC_NOTIFY_NETWORK_CONNECTION: dev_dbg(&desc->intf->dev, - "NOTIFY_NETWORK_CONNECTION %s network", + "NOTIFY_NETWORK_CONNECTION %s network\n", dr->wValue ? "connected to" : "disconnected from"); goto exit; case USB_CDC_NOTIFY_SPEED_CHANGE: - dev_dbg(&desc->intf->dev, "SPEED_CHANGE received (len %u)", + dev_dbg(&desc->intf->dev, "SPEED_CHANGE received (len %u)\n", urb->actual_length); goto exit; default: @@ -314,7 +314,7 @@ static void wdm_int_callback(struct urb *urb) && !test_bit(WDM_DISCONNECTING, &desc->flags) && !test_bit(WDM_SUSPENDING, &desc->flags)) { rv = usb_submit_urb(desc->response, GFP_ATOMIC); - dev_dbg(&desc->intf->dev, "submit response URB %d", rv); + dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv); } spin_unlock(&desc->iuspin); if (rv < 0) { @@ -456,7 +456,7 @@ static ssize_t wdm_write rv = usb_translate_errors(rv); goto out_free_mem_pm; } else { - dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", + dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d\n", le16_to_cpu(req->wIndex)); } @@ -573,7 +573,7 @@ retry: } if (!desc->reslength) { /* zero length read */ - dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ"); + dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ\n"); clear_bit(WDM_READ, &desc->flags); rv = service_outstanding_interrupt(desc); spin_unlock_irq(&desc->iuspin); @@ -723,7 +723,7 @@ static int wdm_release(struct inode *inode, struct file *file) if (!desc->count) { if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { - dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); + dev_dbg(&desc->intf->dev, "wdm_release: cleanup\n"); kill_urbs(desc); spin_lock_irq(&desc->iuspin); desc->resp_count = 0; From ab57f86198d6ff20371613d4a02fd4841972a5c0 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 7 Sep 2016 14:30:01 +0200 Subject: [PATCH 235/343] cdc-acm: delete obsolete debug messages Some debug messages merely provide a function trace without additional debug data. They predate ftrace and can be replaced by it. Drop them without replacement. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 0f3f62e81e5b..fef0d8fcd916 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -492,8 +492,6 @@ static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) struct acm *acm; int retval; - dev_dbg(tty->dev, "%s\n", __func__); - acm = acm_get_by_minor(tty->index); if (!acm) return -ENODEV; @@ -515,8 +513,6 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) { struct acm *acm = tty->driver_data; - dev_dbg(tty->dev, "%s\n", __func__); - return tty_port_open(&acm->port, tty, filp); } @@ -545,8 +541,6 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) int retval = -ENODEV; int i; - dev_dbg(&acm->control->dev, "%s\n", __func__); - mutex_lock(&acm->mutex); if (acm->disconnected) goto disconnected; @@ -607,8 +601,6 @@ static void acm_port_destruct(struct tty_port *port) { struct acm *acm = container_of(port, struct acm, port); - dev_dbg(&acm->control->dev, "%s\n", __func__); - acm_release_minor(acm); usb_put_intf(acm->control); kfree(acm->country_codes); @@ -622,8 +614,6 @@ static void acm_port_shutdown(struct tty_port *port) struct acm_wb *wb; int i; - dev_dbg(&acm->control->dev, "%s\n", __func__); - /* * Need to grab write_lock to prevent race with resume, but no need to * hold it due to the tty-port initialised flag. @@ -654,21 +644,21 @@ static void acm_port_shutdown(struct tty_port *port) static void acm_tty_cleanup(struct tty_struct *tty) { struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); + tty_port_put(&acm->port); } static void acm_tty_hangup(struct tty_struct *tty) { struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); + tty_port_hangup(&acm->port); } static void acm_tty_close(struct tty_struct *tty, struct file *filp) { struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); + tty_port_close(&acm->port, tty, filp); } @@ -1533,8 +1523,6 @@ static void stop_data_traffic(struct acm *acm) { int i; - dev_dbg(&acm->control->dev, "%s\n", __func__); - usb_kill_urb(acm->ctrlurb); for (i = 0; i < ACM_NW; i++) usb_kill_urb(acm->wb[i].urb); @@ -1551,8 +1539,6 @@ static void acm_disconnect(struct usb_interface *intf) struct tty_struct *tty; int i; - dev_dbg(&intf->dev, "%s\n", __func__); - /* sibling interface is already cleaning up */ if (!acm) return; From d223472505d4211b348a5931605858c85b395df5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 12 Aug 2016 17:27:38 +0800 Subject: [PATCH 236/343] phy: exynos5-usbdrd: Remove "static" from local variable The 'reg' local variable does not need to be static. Signed-off-by: Axel Lin Reviewed-by: Krzysztof Kozlowski Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-exynos5-usbdrd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index 20696f53303f..07ed608905ac 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -249,7 +249,7 @@ static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst, static unsigned int exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst) { - static u32 reg; + u32 reg; struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); /* restore any previous reference clock settings */ @@ -295,7 +295,7 @@ exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst) static unsigned int exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst) { - static u32 reg; + u32 reg; struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); /* restore any previous reference clock settings */ From 732e35da7b4ab054239b92ce10c8e7936724a2c8 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 12 Aug 2016 11:06:20 +0800 Subject: [PATCH 237/343] dt: bindings: add bindings for Allwinner A64 usb phy Update sun4i usb phy dt binding documentation to include support for Allwinner A64 usb phy. Signed-off-by: Icenowy Zheng Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 95736d77fbb7..287150db6db4 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -10,6 +10,7 @@ Required properties: * allwinner,sun8i-a23-usb-phy * allwinner,sun8i-a33-usb-phy * allwinner,sun8i-h3-usb-phy + * allwinner,sun50i-a64-usb-phy - reg : a list of offset + length pairs - reg-names : * "phy_ctrl" From b3e0d141ca9f7355fca8a12feb451c31f6b2ee18 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 12 Aug 2016 11:06:21 +0800 Subject: [PATCH 238/343] phy: sun4i: add support for A64 usb phy There's something unknown in the pmu part that shared with H3. It's renamed as PMU_UNK1 from PMU_UNK_H3. Signed-off-by: Icenowy Zheng Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 8c7eb335622e..fcf4d95ecc6d 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -50,7 +50,7 @@ #define REG_PHYCTL_A33 0x10 #define REG_PHY_UNK_H3 0x20 -#define REG_PMU_UNK_H3 0x10 +#define REG_PMU_UNK1 0x10 #define PHYCTL_DATA BIT(7) @@ -98,6 +98,7 @@ enum sun4i_usb_phy_type { sun6i_a31_phy, sun8i_a33_phy, sun8i_h3_phy, + sun50i_a64_phy, }; struct sun4i_usb_phy_cfg { @@ -106,6 +107,7 @@ struct sun4i_usb_phy_cfg { u32 disc_thresh; u8 phyctl_offset; bool dedicated_clocks; + bool enable_pmu_unk1; }; struct sun4i_usb_phy_data { @@ -183,8 +185,9 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, mutex_lock(&phy_data->mutex); - if (phy_data->cfg->type == sun8i_a33_phy) { - /* A33 needs us to set phyctl to 0 explicitly */ + if (phy_data->cfg->type == sun8i_a33_phy || + phy_data->cfg->type == sun50i_a64_phy) { + /* A33 or A64 needs us to set phyctl to 0 explicitly */ writel(0, phyctl); } @@ -258,14 +261,16 @@ static int sun4i_usb_phy_init(struct phy *_phy) return ret; } + if (data->cfg->enable_pmu_unk1) { + val = readl(phy->pmu + REG_PMU_UNK1); + writel(val & ~2, phy->pmu + REG_PMU_UNK1); + } + if (data->cfg->type == sun8i_h3_phy) { if (phy->index == 0) { val = readl(data->base + REG_PHY_UNK_H3); writel(val & ~1, data->base + REG_PHY_UNK_H3); } - - val = readl(phy->pmu + REG_PMU_UNK_H3); - writel(val & ~2, phy->pmu + REG_PMU_UNK_H3); } else { /* Enable USB 45 Ohm resistor calibration */ if (phy->index == 0) @@ -737,6 +742,7 @@ static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = { .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, + .enable_pmu_unk1 = false, }; static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = { @@ -745,6 +751,7 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = { .disc_thresh = 2, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, + .enable_pmu_unk1 = false, }; static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { @@ -753,6 +760,7 @@ static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = { .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, + .enable_pmu_unk1 = false, }; static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = { @@ -761,6 +769,7 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = { .disc_thresh = 2, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = false, + .enable_pmu_unk1 = false, }; static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { @@ -769,6 +778,7 @@ static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A10, .dedicated_clocks = true, + .enable_pmu_unk1 = false, }; static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { @@ -777,6 +787,7 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = { .disc_thresh = 3, .phyctl_offset = REG_PHYCTL_A33, .dedicated_clocks = true, + .enable_pmu_unk1 = false, }; static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { @@ -784,6 +795,16 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { .type = sun8i_h3_phy, .disc_thresh = 3, .dedicated_clocks = true, + .enable_pmu_unk1 = true, +}; + +static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { + .num_phys = 2, + .type = sun50i_a64_phy, + .disc_thresh = 3, + .phyctl_offset = REG_PHYCTL_A33, + .dedicated_clocks = true, + .enable_pmu_unk1 = true, }; static const struct of_device_id sun4i_usb_phy_of_match[] = { @@ -794,6 +815,8 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg }, { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg }, { .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg }, + { .compatible = "allwinner,sun50i-a64-usb-phy", + .data = &sun50i_a64_cfg}, { }, }; MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); From e5666281d9eadb98a802e5ec6e85f0b4640f30c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 12 Aug 2016 00:28:03 +0200 Subject: [PATCH 239/343] phy: bcm-ns-usb3: new driver for USB 3.0 PHY on Northstar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Northstar is a family of SoCs used in home routers. They have USB 2.0 and 3.0 controllers with PHYs that need to be properly initialized. This driver provides PHY init support in a generic way and can be bound with XHCI controller driver. There aren't any public datasheets from Broadcom so we can't have nice defines for all used bits. It means we just follow Broadcom's initialization procedure using their magic values. We were quite lucky actually that Broadcom put some comments in their SDK reference code explaining what given writes are responsible for. Signed-off-by: Rafał Miłecki Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/bcm-ns-usb3-phy.txt | 23 ++ drivers/phy/Kconfig | 9 + drivers/phy/Makefile | 1 + drivers/phy/phy-bcm-ns-usb3.c | 274 ++++++++++++++++++ 4 files changed, 307 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt create mode 100644 drivers/phy/phy-bcm-ns-usb3.c diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt new file mode 100644 index 000000000000..09aeba94538d --- /dev/null +++ b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt @@ -0,0 +1,23 @@ +Driver for Broadcom Northstar USB 3.0 PHY + +Required properties: + +- compatible: one of: "brcm,ns-ax-usb3-phy", "brcm,ns-bx-usb3-phy". +- reg: register mappings for DMP (Device Management Plugin) and ChipCommon B + MMI. +- reg-names: "dmp" and "ccb-mii" + +Initialization of USB 3.0 PHY depends on Northstar version. There are currently +three known series: Ax, Bx and Cx. +Known A0: BCM4707 rev 0 +Known B0: BCM4707 rev 4, BCM53573 rev 2 +Known B1: BCM4707 rev 6 +Known C0: BCM47094 rev 0 + +Example: + usb3-phy { + compatible = "brcm,ns-ax-usb3-phy"; + reg = <0x18105000 0x1000>, <0x18003000 0x1000>; + reg-names = "dmp", "ccb-mii"; + #phy-cells = <0>; + }; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 19bff3a10f69..afbdd6a9b964 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -24,6 +24,15 @@ config PHY_BCM_NS_USB2 Enable this to support Broadcom USB 2.0 PHY connected to the USB controller on Northstar family. +config PHY_BCM_NS_USB3 + tristate "Broadcom Northstar USB 3.0 PHY Driver" + depends on ARCH_BCM_IPROC || COMPILE_TEST + depends on HAS_IOMEM && OF + select GENERIC_PHY + help + Enable this to support Broadcom USB 3.0 PHY connected to the USB + controller on Northstar family. + config PHY_BERLIN_USB tristate "Marvell Berlin USB PHY Driver" depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 90ae19879b0a..b99370a14ed9 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_GENERIC_PHY) += phy-core.o obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o +obj-$(CONFIG_PHY_BCM_NS_USB3) += phy-bcm-ns-usb3.o obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o diff --git a/drivers/phy/phy-bcm-ns-usb3.c b/drivers/phy/phy-bcm-ns-usb3.c new file mode 100644 index 000000000000..f420fa4bebfc --- /dev/null +++ b/drivers/phy/phy-bcm-ns-usb3.c @@ -0,0 +1,274 @@ +/* + * Broadcom Northstar USB 3.0 PHY Driver + * + * Copyright (C) 2016 Rafał Miłecki + * + * All magic values used for initialization (and related comments) were obtained + * from Broadcom's SDK: + * Copyright (c) Broadcom Corp, 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BCM_NS_USB3_MII_MNG_TIMEOUT_US 1000 /* usecs */ + +enum bcm_ns_family { + BCM_NS_UNKNOWN, + BCM_NS_AX, + BCM_NS_BX, +}; + +struct bcm_ns_usb3 { + struct device *dev; + enum bcm_ns_family family; + void __iomem *dmp; + void __iomem *ccb_mii; + struct phy *phy; +}; + +static const struct of_device_id bcm_ns_usb3_id_table[] = { + { + .compatible = "brcm,ns-ax-usb3-phy", + .data = (int *)BCM_NS_AX, + }, + { + .compatible = "brcm,ns-bx-usb3-phy", + .data = (int *)BCM_NS_BX, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table); + +static int bcm_ns_usb3_wait_reg(struct bcm_ns_usb3 *usb3, void __iomem *addr, + u32 mask, u32 value, unsigned long timeout) +{ + unsigned long deadline = jiffies + timeout; + u32 val; + + do { + val = readl(addr); + if ((val & mask) == value) + return 0; + cpu_relax(); + udelay(10); + } while (!time_after_eq(jiffies, deadline)); + + dev_err(usb3->dev, "Timeout waiting for register %p\n", addr); + + return -EBUSY; +} + +static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3) +{ + return bcm_ns_usb3_wait_reg(usb3, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL, + 0x0100, 0x0000, + usecs_to_jiffies(BCM_NS_USB3_MII_MNG_TIMEOUT_US)); +} + +static int bcm_ns_usb3_mii_mng_write32(struct bcm_ns_usb3 *usb3, u32 value) +{ + int err; + + err = bcm_ns_usb3_mii_mng_wait_idle(usb3); + if (err < 0) { + dev_err(usb3->dev, "Couldn't write 0x%08x value\n", value); + return err; + } + + writel(value, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA); + + return 0; +} + +static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3) +{ + int err; + + /* Enable MDIO. Setting MDCDIV as 26 */ + writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL); + + /* Wait for MDIO? */ + udelay(2); + + /* USB3 PLL Block */ + err = bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000); + if (err < 0) + return err; + + /* Assert Ana_Pllseq start */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x58061000); + + /* Assert CML Divider ratio to 26 */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400); + + /* Asserting PLL Reset */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x582ec000); + + /* Deaaserting PLL Reset */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x582e8000); + + /* Waiting MII Mgt interface idle */ + bcm_ns_usb3_mii_mng_wait_idle(usb3); + + /* Deasserting USB3 system reset */ + writel(0, usb3->dmp + BCMA_RESET_CTL); + + /* PLL frequency monitor enable */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x58069000); + + /* PIPE Block */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8060); + + /* CMPMAX & CMPMINTH setting */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x580af30d); + + /* DEGLITCH MIN & MAX setting */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x580e6302); + + /* TXPMD block */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040); + + /* Enabling SSC */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003); + + /* Waiting MII Mgt interface idle */ + bcm_ns_usb3_mii_mng_wait_idle(usb3); + + return 0; +} + +static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3) +{ + int err; + + /* Enable MDIO. Setting MDCDIV as 26 */ + writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL); + + /* Wait for MDIO? */ + udelay(2); + + /* PLL30 block */ + err = bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000); + if (err < 0) + return err; + + bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400); + + bcm_ns_usb3_mii_mng_write32(usb3, 0x587e80e0); + + bcm_ns_usb3_mii_mng_write32(usb3, 0x580a009c); + + /* Enable SSC */ + bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040); + + bcm_ns_usb3_mii_mng_write32(usb3, 0x580a21d3); + + bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003); + + /* Waiting MII Mgt interface idle */ + bcm_ns_usb3_mii_mng_wait_idle(usb3); + + /* Deasserting USB3 system reset */ + writel(0, usb3->dmp + BCMA_RESET_CTL); + + return 0; +} + +static int bcm_ns_usb3_phy_init(struct phy *phy) +{ + struct bcm_ns_usb3 *usb3 = phy_get_drvdata(phy); + int err; + + /* Perform USB3 system soft reset */ + writel(BCMA_RESET_CTL_RESET, usb3->dmp + BCMA_RESET_CTL); + + switch (usb3->family) { + case BCM_NS_AX: + err = bcm_ns_usb3_phy_init_ns_ax(usb3); + break; + case BCM_NS_BX: + err = bcm_ns_usb3_phy_init_ns_bx(usb3); + break; + default: + WARN_ON(1); + err = -ENOTSUPP; + } + + return err; +} + +static const struct phy_ops ops = { + .init = bcm_ns_usb3_phy_init, + .owner = THIS_MODULE, +}; + +static int bcm_ns_usb3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id; + struct bcm_ns_usb3 *usb3; + struct resource *res; + struct phy_provider *phy_provider; + + usb3 = devm_kzalloc(dev, sizeof(*usb3), GFP_KERNEL); + if (!usb3) + return -ENOMEM; + + usb3->dev = dev; + + of_id = of_match_device(bcm_ns_usb3_id_table, dev); + if (!of_id) + return -EINVAL; + usb3->family = (enum bcm_ns_family)of_id->data; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmp"); + usb3->dmp = devm_ioremap_resource(dev, res); + if (IS_ERR(usb3->dmp)) { + dev_err(dev, "Failed to map DMP regs\n"); + return PTR_ERR(usb3->dmp); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ccb-mii"); + usb3->ccb_mii = devm_ioremap_resource(dev, res); + if (IS_ERR(usb3->ccb_mii)) { + dev_err(dev, "Failed to map ChipCommon B MII regs\n"); + return PTR_ERR(usb3->ccb_mii); + } + + usb3->phy = devm_phy_create(dev, NULL, &ops); + if (IS_ERR(usb3->phy)) { + dev_err(dev, "Failed to create PHY\n"); + return PTR_ERR(usb3->phy); + } + + phy_set_drvdata(usb3->phy, usb3); + platform_set_drvdata(pdev, usb3); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (!IS_ERR(phy_provider)) + dev_info(dev, "Registered Broadcom Northstar USB 3.0 PHY driver\n"); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static struct platform_driver bcm_ns_usb3_driver = { + .probe = bcm_ns_usb3_probe, + .driver = { + .name = "bcm_ns_usb3", + .of_match_table = bcm_ns_usb3_id_table, + }, +}; +module_platform_driver(bcm_ns_usb3_driver); + +MODULE_LICENSE("GPL v2"); From 3ea981ed816a69129d1153d1b683617496b126cb Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 5 Aug 2016 13:25:13 +0200 Subject: [PATCH 240/343] phy: qcom-ufs: use of_property_read_bool Use of_property_read_bool to check for the existence of a property. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression e1,e2,x; @@ - if (of_get_property(e1,e2,NULL)) - x = true; - else - x = false; + x = of_property_read_bool(e1,e2); // Signed-off-by: Julia Lawall Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-qcom-ufs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c index 107cb57c3513..18a5b495ad65 100644 --- a/drivers/phy/phy-qcom-ufs.c +++ b/drivers/phy/phy-qcom-ufs.c @@ -283,10 +283,8 @@ static int __ufs_qcom_phy_init_vreg(struct phy *phy, err = 0; } snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name); - if (of_get_property(dev->of_node, prop_name, NULL)) - vreg->is_always_on = true; - else - vreg->is_always_on = false; + vreg->is_always_on = of_property_read_bool(dev->of_node, + prop_name); } if (!strcmp(name, "vdda-pll")) { From 72580a49a837c2c7da83f698c00592eac41537d8 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Fri, 22 Jul 2016 15:00:43 +0800 Subject: [PATCH 241/343] Documentation: bindings: add DT documentation for Rockchip USB2PHY Signed-off-by: Frank Wang Acked-by: Rob Herring Reviewed-by: Heiko Stuebner Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/phy-rockchip-inno-usb2.txt | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new file mode 100644 index 000000000000..3c29c77a7018 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt @@ -0,0 +1,64 @@ +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK + +Required properties (phy (parent) node): + - compatible : should be one of the listed compatibles: + * "rockchip,rk3366-usb2phy" + * "rockchip,rk3399-usb2phy" + - reg : the address offset of grf for usb-phy configuration. + - #clock-cells : should be 0. + - clock-output-names : specify the 480m output clock name. + +Optional properties: + - clocks : phandle + phy specifier pair, for the input clock of phy. + - clock-names : input clock name of phy, must be "phyclk". + +Required nodes : a sub-node is required for each port the phy provides. + The sub-node name is used to identify host or otg port, + and shall be the following entries: + * "otg-port" : the name of otg port. + * "host-port" : the name of host port. + +Required properties (port (child) node): + - #phy-cells : must be 0. See ./phy-bindings.txt for details. + - interrupts : specify an interrupt for each entry in interrupt-names. + - interrupt-names : a list which shall be the following entries: + * "otg-id" : for the otg id interrupt. + * "otg-bvalid" : for the otg vbus interrupt. + * "linestate" : for the host/otg linestate interrupt. + +Optional properties: + - phy-supply : phandle to a regulator that provides power to VBUS. + See ./phy-bindings.txt for details. + +Example: + +grf: syscon@ff770000 { + compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + +... + + u2phy: usb2-phy@700 { + compatible = "rockchip,rk3366-usb2phy"; + reg = <0x700 0x2c>; + #clock-cells = <0>; + clock-output-names = "sclk_otgphy0_480m"; + + u2phy_otg: otg-port { + #phy-cells = <0>; + interrupts = , + , + ; + interrupt-names = "otg-id", "otg-bvalid", "linestate"; + status = "okay"; + }; + + u2phy_host: host-port { + #phy-cells = <0>; + interrupts = ; + interrupt-names = "linestate"; + status = "okay"; + }; + }; +}; From 0e08d2a727e68bbe426457dc61ec11a5c6a76ed6 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Fri, 22 Jul 2016 15:00:44 +0800 Subject: [PATCH 242/343] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy The newer SoCs (rk3366, rk3399) take a different usb-phy IP block than rk3288 and before, and most of phy-related registers are also different from the past, so a new phy driver is required necessarily. Signed-off-by: Frank Wang Suggested-by: Heiko Stuebner Suggested-by: Guenter Roeck Suggested-by: Doug Anderson Reviewed-by: Heiko Stuebner Reviewed-by: Guenter Roeck Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 7 + drivers/phy/Makefile | 1 + drivers/phy/phy-rockchip-inno-usb2.c | 707 +++++++++++++++++++++++++++ 3 files changed, 715 insertions(+) create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index afbdd6a9b964..f9bf9817e63f 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -367,6 +367,13 @@ config PHY_ROCKCHIP_USB help Enable this to support the Rockchip USB 2.0 PHY. +config PHY_ROCKCHIP_INNO_USB2 + tristate "Rockchip INNO USB2PHY Driver" + depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF + select GENERIC_PHY + help + Support for Rockchip USB2.0 PHY with Innosilicon IP block. + config PHY_ROCKCHIP_EMMC tristate "Rockchip EMMC PHY Driver" depends on ARCH_ROCKCHIP && OF diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index b99370a14ed9..74b44ef5f0a5 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -40,6 +40,7 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o +obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c new file mode 100644 index 000000000000..ac203107b071 --- /dev/null +++ b/drivers/phy/phy-rockchip-inno-usb2.c @@ -0,0 +1,707 @@ +/* + * Rockchip USB2.0 PHY with Innosilicon IP block driver + * + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BIT_WRITEABLE_SHIFT 16 +#define SCHEDULE_DELAY (60 * HZ) + +enum rockchip_usb2phy_port_id { + USB2PHY_PORT_OTG, + USB2PHY_PORT_HOST, + USB2PHY_NUM_PORTS, +}; + +enum rockchip_usb2phy_host_state { + PHY_STATE_HS_ONLINE = 0, + PHY_STATE_DISCONNECT = 1, + PHY_STATE_CONNECT = 2, + PHY_STATE_FS_LS_ONLINE = 4, +}; + +struct usb2phy_reg { + unsigned int offset; + unsigned int bitend; + unsigned int bitstart; + unsigned int disable; + unsigned int enable; +}; + +/** + * struct rockchip_usb2phy_port_cfg: usb-phy port configuration. + * @phy_sus: phy suspend register. + * @ls_det_en: linestate detection enable register. + * @ls_det_st: linestate detection state register. + * @ls_det_clr: linestate detection clear register. + * @utmi_ls: utmi linestate state register. + * @utmi_hstdet: utmi host disconnect register. + */ +struct rockchip_usb2phy_port_cfg { + struct usb2phy_reg phy_sus; + struct usb2phy_reg ls_det_en; + struct usb2phy_reg ls_det_st; + struct usb2phy_reg ls_det_clr; + struct usb2phy_reg utmi_ls; + struct usb2phy_reg utmi_hstdet; +}; + +/** + * struct rockchip_usb2phy_cfg: usb-phy configuration. + * @reg: the address offset of grf for usb-phy config. + * @num_ports: specify how many ports that the phy has. + * @clkout_ctl: keep on/turn off output clk of phy. + */ +struct rockchip_usb2phy_cfg { + unsigned int reg; + unsigned int num_ports; + struct usb2phy_reg clkout_ctl; + const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS]; +}; + +/** + * struct rockchip_usb2phy_port: usb-phy port data. + * @port_id: flag for otg port or host port. + * @suspended: phy suspended flag. + * @ls_irq: IRQ number assigned for linestate detection. + * @mutex: for register updating in sm_work. + * @sm_work: OTG state machine work. + * @phy_cfg: port register configuration, assigned by driver data. + */ +struct rockchip_usb2phy_port { + struct phy *phy; + unsigned int port_id; + bool suspended; + int ls_irq; + struct mutex mutex; + struct delayed_work sm_work; + const struct rockchip_usb2phy_port_cfg *port_cfg; +}; + +/** + * struct rockchip_usb2phy: usb2.0 phy driver data. + * @grf: General Register Files regmap. + * @clk: clock struct of phy input clk. + * @clk480m: clock struct of phy output clk. + * @clk_hw: clock struct of phy output clk management. + * @phy_cfg: phy register configuration, assigned by driver data. + * @ports: phy port instance. + */ +struct rockchip_usb2phy { + struct device *dev; + struct regmap *grf; + struct clk *clk; + struct clk *clk480m; + struct clk_hw clk480m_hw; + const struct rockchip_usb2phy_cfg *phy_cfg; + struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS]; +}; + +static inline int property_enable(struct rockchip_usb2phy *rphy, + const struct usb2phy_reg *reg, bool en) +{ + unsigned int val, mask, tmp; + + tmp = en ? reg->enable : reg->disable; + mask = GENMASK(reg->bitend, reg->bitstart); + val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); + + return regmap_write(rphy->grf, reg->offset, val); +} + +static inline bool property_enabled(struct rockchip_usb2phy *rphy, + const struct usb2phy_reg *reg) +{ + int ret; + unsigned int tmp, orig; + unsigned int mask = GENMASK(reg->bitend, reg->bitstart); + + ret = regmap_read(rphy->grf, reg->offset, &orig); + if (ret) + return false; + + tmp = (orig & mask) >> reg->bitstart; + return tmp == reg->enable; +} + +static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw) +{ + struct rockchip_usb2phy *rphy = + container_of(hw, struct rockchip_usb2phy, clk480m_hw); + int ret; + + /* turn on 480m clk output if it is off */ + if (!property_enabled(rphy, &rphy->phy_cfg->clkout_ctl)) { + ret = property_enable(rphy, &rphy->phy_cfg->clkout_ctl, true); + if (ret) + return ret; + + /* waitting for the clk become stable */ + mdelay(1); + } + + return 0; +} + +static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw) +{ + struct rockchip_usb2phy *rphy = + container_of(hw, struct rockchip_usb2phy, clk480m_hw); + + /* turn off 480m clk output */ + property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false); +} + +static int rockchip_usb2phy_clk480m_enabled(struct clk_hw *hw) +{ + struct rockchip_usb2phy *rphy = + container_of(hw, struct rockchip_usb2phy, clk480m_hw); + + return property_enabled(rphy, &rphy->phy_cfg->clkout_ctl); +} + +static unsigned long +rockchip_usb2phy_clk480m_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 480000000; +} + +static const struct clk_ops rockchip_usb2phy_clkout_ops = { + .enable = rockchip_usb2phy_clk480m_enable, + .disable = rockchip_usb2phy_clk480m_disable, + .is_enabled = rockchip_usb2phy_clk480m_enabled, + .recalc_rate = rockchip_usb2phy_clk480m_recalc_rate, +}; + +static void rockchip_usb2phy_clk480m_unregister(void *data) +{ + struct rockchip_usb2phy *rphy = data; + + of_clk_del_provider(rphy->dev->of_node); + clk_unregister(rphy->clk480m); +} + +static int +rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) +{ + struct device_node *node = rphy->dev->of_node; + struct clk_init_data init; + const char *clk_name; + int ret; + + init.flags = 0; + init.name = "clk_usbphy_480m"; + init.ops = &rockchip_usb2phy_clkout_ops; + + /* optional override of the clockname */ + of_property_read_string(node, "clock-output-names", &init.name); + + if (rphy->clk) { + clk_name = __clk_get_name(rphy->clk); + init.parent_names = &clk_name; + init.num_parents = 1; + } else { + init.parent_names = NULL; + init.num_parents = 0; + } + + rphy->clk480m_hw.init = &init; + + /* register the clock */ + rphy->clk480m = clk_register(rphy->dev, &rphy->clk480m_hw); + if (IS_ERR(rphy->clk480m)) { + ret = PTR_ERR(rphy->clk480m); + goto err_ret; + } + + ret = of_clk_add_provider(node, of_clk_src_simple_get, rphy->clk480m); + if (ret < 0) + goto err_clk_provider; + + ret = devm_add_action(rphy->dev, rockchip_usb2phy_clk480m_unregister, + rphy); + if (ret < 0) + goto err_unreg_action; + + return 0; + +err_unreg_action: + of_clk_del_provider(node); +err_clk_provider: + clk_unregister(rphy->clk480m); +err_ret: + return ret; +} + +static int rockchip_usb2phy_init(struct phy *phy) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); + int ret; + + if (rport->port_id == USB2PHY_PORT_HOST) { + /* clear linestate and enable linestate detect irq */ + mutex_lock(&rport->mutex); + + ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true); + if (ret) { + mutex_unlock(&rport->mutex); + return ret; + } + + ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true); + if (ret) { + mutex_unlock(&rport->mutex); + return ret; + } + + mutex_unlock(&rport->mutex); + schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY); + } + + return 0; +} + +static int rockchip_usb2phy_power_on(struct phy *phy) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); + int ret; + + dev_dbg(&rport->phy->dev, "port power on\n"); + + if (!rport->suspended) + return 0; + + ret = clk_prepare_enable(rphy->clk480m); + if (ret) + return ret; + + ret = property_enable(rphy, &rport->port_cfg->phy_sus, false); + if (ret) + return ret; + + rport->suspended = false; + return 0; +} + +static int rockchip_usb2phy_power_off(struct phy *phy) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); + int ret; + + dev_dbg(&rport->phy->dev, "port power off\n"); + + if (rport->suspended) + return 0; + + ret = property_enable(rphy, &rport->port_cfg->phy_sus, true); + if (ret) + return ret; + + rport->suspended = true; + clk_disable_unprepare(rphy->clk480m); + + return 0; +} + +static int rockchip_usb2phy_exit(struct phy *phy) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + + if (rport->port_id == USB2PHY_PORT_HOST) + cancel_delayed_work_sync(&rport->sm_work); + + return 0; +} + +static const struct phy_ops rockchip_usb2phy_ops = { + .init = rockchip_usb2phy_init, + .exit = rockchip_usb2phy_exit, + .power_on = rockchip_usb2phy_power_on, + .power_off = rockchip_usb2phy_power_off, + .owner = THIS_MODULE, +}; + +/* + * The function manage host-phy port state and suspend/resume phy port + * to save power. + * + * we rely on utmi_linestate and utmi_hostdisconnect to identify whether + * devices is disconnect or not. Besides, we do not need care it is FS/LS + * disconnected or HS disconnected, actually, we just only need get the + * device is disconnected at last through rearm the delayed work, + * to suspend the phy port in _PHY_STATE_DISCONNECT_ case. + * + * NOTE: It may invoke *phy_powr_off or *phy_power_on which will invoke + * some clk related APIs, so do not invoke it from interrupt context directly. + */ +static void rockchip_usb2phy_sm_work(struct work_struct *work) +{ + struct rockchip_usb2phy_port *rport = + container_of(work, struct rockchip_usb2phy_port, sm_work.work); + struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); + unsigned int sh = rport->port_cfg->utmi_hstdet.bitend - + rport->port_cfg->utmi_hstdet.bitstart + 1; + unsigned int ul, uhd, state; + unsigned int ul_mask, uhd_mask; + int ret; + + mutex_lock(&rport->mutex); + + ret = regmap_read(rphy->grf, rport->port_cfg->utmi_ls.offset, &ul); + if (ret < 0) + goto next_schedule; + + ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, + &uhd); + if (ret < 0) + goto next_schedule; + + uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend, + rport->port_cfg->utmi_hstdet.bitstart); + ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend, + rport->port_cfg->utmi_ls.bitstart); + + /* stitch on utmi_ls and utmi_hstdet as phy state */ + state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) | + (((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh); + + switch (state) { + case PHY_STATE_HS_ONLINE: + dev_dbg(&rport->phy->dev, "HS online\n"); + break; + case PHY_STATE_FS_LS_ONLINE: + /* + * For FS/LS device, the online state share with connect state + * from utmi_ls and utmi_hstdet register, so we distinguish + * them via suspended flag. + * + * Plus, there are two cases, one is D- Line pull-up, and D+ + * line pull-down, the state is 4; another is D+ line pull-up, + * and D- line pull-down, the state is 2. + */ + if (!rport->suspended) { + /* D- line pull-up, D+ line pull-down */ + dev_dbg(&rport->phy->dev, "FS/LS online\n"); + break; + } + /* fall through */ + case PHY_STATE_CONNECT: + if (rport->suspended) { + dev_dbg(&rport->phy->dev, "Connected\n"); + rockchip_usb2phy_power_on(rport->phy); + rport->suspended = false; + } else { + /* D+ line pull-up, D- line pull-down */ + dev_dbg(&rport->phy->dev, "FS/LS online\n"); + } + break; + case PHY_STATE_DISCONNECT: + if (!rport->suspended) { + dev_dbg(&rport->phy->dev, "Disconnected\n"); + rockchip_usb2phy_power_off(rport->phy); + rport->suspended = true; + } + + /* + * activate the linestate detection to get the next device + * plug-in irq. + */ + property_enable(rphy, &rport->port_cfg->ls_det_clr, true); + property_enable(rphy, &rport->port_cfg->ls_det_en, true); + + /* + * we don't need to rearm the delayed work when the phy port + * is suspended. + */ + mutex_unlock(&rport->mutex); + return; + default: + dev_dbg(&rport->phy->dev, "unknown phy state\n"); + break; + } + +next_schedule: + mutex_unlock(&rport->mutex); + schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY); +} + +static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data) +{ + struct rockchip_usb2phy_port *rport = data; + struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); + + if (!property_enabled(rphy, &rport->port_cfg->ls_det_st)) + return IRQ_NONE; + + mutex_lock(&rport->mutex); + + /* disable linestate detect irq and clear its status */ + property_enable(rphy, &rport->port_cfg->ls_det_en, false); + property_enable(rphy, &rport->port_cfg->ls_det_clr, true); + + mutex_unlock(&rport->mutex); + + /* + * In this case for host phy port, a new device is plugged in, + * meanwhile, if the phy port is suspended, we need rearm the work to + * resume it and mange its states; otherwise, we do nothing about that. + */ + if (rport->suspended && rport->port_id == USB2PHY_PORT_HOST) + rockchip_usb2phy_sm_work(&rport->sm_work.work); + + return IRQ_HANDLED; +} + +static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy, + struct rockchip_usb2phy_port *rport, + struct device_node *child_np) +{ + int ret; + + rport->port_id = USB2PHY_PORT_HOST; + rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST]; + rport->suspended = true; + + mutex_init(&rport->mutex); + INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work); + + rport->ls_irq = of_irq_get_byname(child_np, "linestate"); + if (rport->ls_irq < 0) { + dev_err(rphy->dev, "no linestate irq provided\n"); + return rport->ls_irq; + } + + ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL, + rockchip_usb2phy_linestate_irq, + IRQF_ONESHOT, + "rockchip_usb2phy", rport); + if (ret) { + dev_err(rphy->dev, "failed to request irq handle\n"); + return ret; + } + + return 0; +} + +static int rockchip_usb2phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child_np; + struct phy_provider *provider; + struct rockchip_usb2phy *rphy; + const struct rockchip_usb2phy_cfg *phy_cfgs; + const struct of_device_id *match; + unsigned int reg; + int index, ret; + + rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); + if (!rphy) + return -ENOMEM; + + match = of_match_device(dev->driver->of_match_table, dev); + if (!match || !match->data) { + dev_err(dev, "phy configs are not assigned!\n"); + return -EINVAL; + } + + if (!dev->parent || !dev->parent->of_node) + return -EINVAL; + + rphy->grf = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(rphy->grf)) + return PTR_ERR(rphy->grf); + + if (of_property_read_u32(np, "reg", ®)) { + dev_err(dev, "the reg property is not assigned in %s node\n", + np->name); + return -EINVAL; + } + + rphy->dev = dev; + phy_cfgs = match->data; + platform_set_drvdata(pdev, rphy); + + /* find out a proper config which can be matched with dt. */ + index = 0; + while (phy_cfgs[index].reg) { + if (phy_cfgs[index].reg == reg) { + rphy->phy_cfg = &phy_cfgs[index]; + break; + } + + ++index; + } + + if (!rphy->phy_cfg) { + dev_err(dev, "no phy-config can be matched with %s node\n", + np->name); + return -EINVAL; + } + + rphy->clk = of_clk_get_by_name(np, "phyclk"); + if (!IS_ERR(rphy->clk)) { + clk_prepare_enable(rphy->clk); + } else { + dev_info(&pdev->dev, "no phyclk specified\n"); + rphy->clk = NULL; + } + + ret = rockchip_usb2phy_clk480m_register(rphy); + if (ret) { + dev_err(dev, "failed to register 480m output clock\n"); + goto disable_clks; + } + + index = 0; + for_each_available_child_of_node(np, child_np) { + struct rockchip_usb2phy_port *rport = &rphy->ports[index]; + struct phy *phy; + + /* + * This driver aim to support both otg-port and host-port, + * but unfortunately, the otg part is not ready in current, + * so this comments and below codes are interim, which should + * be changed after otg-port is supplied soon. + */ + if (of_node_cmp(child_np->name, "host-port")) + goto next_child; + + phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy\n"); + ret = PTR_ERR(phy); + goto put_child; + } + + rport->phy = phy; + phy_set_drvdata(rport->phy, rport); + + ret = rockchip_usb2phy_host_port_init(rphy, rport, child_np); + if (ret) + goto put_child; + +next_child: + /* to prevent out of boundary */ + if (++index >= rphy->phy_cfg->num_ports) + break; + } + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(provider); + +put_child: + of_node_put(child_np); +disable_clks: + if (rphy->clk) { + clk_disable_unprepare(rphy->clk); + clk_put(rphy->clk); + } + return ret; +} + +static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = { + { + .reg = 0x700, + .num_ports = 2, + .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, + .ls_det_en = { 0x0680, 4, 4, 0, 1 }, + .ls_det_st = { 0x0690, 4, 4, 0, 1 }, + .ls_det_clr = { 0x06a0, 4, 4, 0, 1 }, + .utmi_ls = { 0x049c, 14, 13, 0, 1 }, + .utmi_hstdet = { 0x049c, 12, 12, 0, 1 } + } + }, + }, + { /* sentinel */ } +}; + +static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { + { + .reg = 0xe450, + .num_ports = 2, + .clkout_ctl = { 0xe450, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0xe458, 1, 0, 0x2, 0x1 }, + .ls_det_en = { 0xe3c0, 6, 6, 0, 1 }, + .ls_det_st = { 0xe3e0, 6, 6, 0, 1 }, + .ls_det_clr = { 0xe3d0, 6, 6, 0, 1 }, + .utmi_ls = { 0xe2ac, 22, 21, 0, 1 }, + .utmi_hstdet = { 0xe2ac, 23, 23, 0, 1 } + } + }, + }, + { + .reg = 0xe460, + .num_ports = 2, + .clkout_ctl = { 0xe460, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0xe468, 1, 0, 0x2, 0x1 }, + .ls_det_en = { 0xe3c0, 11, 11, 0, 1 }, + .ls_det_st = { 0xe3e0, 11, 11, 0, 1 }, + .ls_det_clr = { 0xe3d0, 11, 11, 0, 1 }, + .utmi_ls = { 0xe2ac, 26, 25, 0, 1 }, + .utmi_hstdet = { 0xe2ac, 27, 27, 0, 1 } + } + }, + }, + { /* sentinel */ } +}; + +static const struct of_device_id rockchip_usb2phy_dt_match[] = { + { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, + { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, + {} +}; +MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match); + +static struct platform_driver rockchip_usb2phy_driver = { + .probe = rockchip_usb2phy_probe, + .driver = { + .name = "rockchip-usb2phy", + .of_match_table = rockchip_usb2phy_dt_match, + }, +}; +module_platform_driver(rockchip_usb2phy_driver); + +MODULE_AUTHOR("Frank Wang "); +MODULE_DESCRIPTION("Rockchip USB2.0 PHY driver"); +MODULE_LICENSE("GPL v2"); From b11c821532b53976ff8af1b9c98d114facdfadcb Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 1 Sep 2016 15:44:53 +0800 Subject: [PATCH 243/343] Documentation: bindings: add dt documentation for Rockchip PCIe PHY This patch adds a binding that describes the Rockchip PCIe PHY found on Rockchip SoCs PCIe interface. Signed-off-by: Shawn Lin Acked-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/rockchip-pcie-phy.txt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt diff --git a/Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt b/Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt new file mode 100644 index 000000000000..0f6222a672ce --- /dev/null +++ b/Documentation/devicetree/bindings/phy/rockchip-pcie-phy.txt @@ -0,0 +1,31 @@ +Rockchip PCIE PHY +----------------------- + +Required properties: + - compatible: rockchip,rk3399-pcie-phy + - #phy-cells: must be 0 + - clocks: Must contain an entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must be "refclk" + - resets: Must contain an entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must be "phy" + +Example: + +grf: syscon@ff770000 { + compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + ... + + pcie_phy: pcie-phy { + compatible = "rockchip,rk3399-pcie-phy"; + #phy-cells = <0>; + clocks = <&cru SCLK_PCIEPHY_REF>; + clock-names = "refclk"; + resets = <&cru SRST_PCIEPHY>; + reset-names = "phy"; + }; +}; From fcffee3d54fcadcfa82b183c3fcdbd43e573339e Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 1 Sep 2016 15:44:54 +0800 Subject: [PATCH 244/343] phy: add a driver for the Rockchip SoC internal PCIe PHY This patch to add a generic PHY driver for rockchip PCIe PHY. Access the PHY via registers provided by GRF (general register files) module. Signed-off-by: Shawn Lin Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 8 + drivers/phy/Makefile | 1 + drivers/phy/phy-rockchip-pcie.c | 357 ++++++++++++++++++++++++++++++++ 3 files changed, 366 insertions(+) create mode 100644 drivers/phy/phy-rockchip-pcie.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index f9bf9817e63f..46e5536c453e 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -388,6 +388,14 @@ config PHY_ROCKCHIP_DP help Enable this to support the Rockchip Display Port PHY. +config PHY_ROCKCHIP_PCIE + tristate "Rockchip PCIe PHY Driver" + depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support the Rockchip PCIe PHY. + config PHY_ST_SPEAR1310_MIPHY tristate "ST SPEAR1310-MIPHY driver" select GENERIC_PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 74b44ef5f0a5..ce0e526059dd 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o +obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o diff --git a/drivers/phy/phy-rockchip-pcie.c b/drivers/phy/phy-rockchip-pcie.c new file mode 100644 index 000000000000..a2b4c6b58aea --- /dev/null +++ b/drivers/phy/phy-rockchip-pcie.c @@ -0,0 +1,357 @@ +/* + * Rockchip PCIe PHY driver + * + * Copyright (C) 2016 Shawn Lin + * Copyright (C) 2016 ROCKCHIP, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The higher 16-bit of this register is used for write protection + * only if BIT(x + 16) set to 1 the BIT(x) can be written. + */ +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + +#define PHY_MAX_LANE_NUM 4 +#define PHY_CFG_DATA_SHIFT 7 +#define PHY_CFG_ADDR_SHIFT 1 +#define PHY_CFG_DATA_MASK 0xf +#define PHY_CFG_ADDR_MASK 0x3f +#define PHY_CFG_RD_MASK 0x3ff +#define PHY_CFG_WR_ENABLE 1 +#define PHY_CFG_WR_DISABLE 1 +#define PHY_CFG_WR_SHIFT 0 +#define PHY_CFG_WR_MASK 1 +#define PHY_CFG_PLL_LOCK 0x10 +#define PHY_CFG_CLK_TEST 0x10 +#define PHY_CFG_CLK_SCC 0x12 +#define PHY_CFG_SEPE_RATE BIT(3) +#define PHY_CFG_PLL_100M BIT(3) +#define PHY_PLL_LOCKED BIT(9) +#define PHY_PLL_OUTPUT BIT(10) +#define PHY_LANE_A_STATUS 0x30 +#define PHY_LANE_B_STATUS 0x31 +#define PHY_LANE_C_STATUS 0x32 +#define PHY_LANE_D_STATUS 0x33 +#define PHY_LANE_RX_DET_SHIFT 11 +#define PHY_LANE_RX_DET_TH 0x1 +#define PHY_LANE_IDLE_OFF 0x1 +#define PHY_LANE_IDLE_MASK 0x1 +#define PHY_LANE_IDLE_A_SHIFT 3 +#define PHY_LANE_IDLE_B_SHIFT 4 +#define PHY_LANE_IDLE_C_SHIFT 5 +#define PHY_LANE_IDLE_D_SHIFT 6 + +struct rockchip_pcie_data { + unsigned int pcie_conf; + unsigned int pcie_status; + unsigned int pcie_laneoff; +}; + +struct rockchip_pcie_phy { + struct rockchip_pcie_data *phy_data; + struct regmap *reg_base; + struct reset_control *phy_rst; + struct clk *clk_pciephy_ref; +}; + +static inline void phy_wr_cfg(struct rockchip_pcie_phy *rk_phy, + u32 addr, u32 data) +{ + regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf, + HIWORD_UPDATE(data, + PHY_CFG_DATA_MASK, + PHY_CFG_DATA_SHIFT) | + HIWORD_UPDATE(addr, + PHY_CFG_ADDR_MASK, + PHY_CFG_ADDR_SHIFT)); + udelay(1); + regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf, + HIWORD_UPDATE(PHY_CFG_WR_ENABLE, + PHY_CFG_WR_MASK, + PHY_CFG_WR_SHIFT)); + udelay(1); + regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf, + HIWORD_UPDATE(PHY_CFG_WR_DISABLE, + PHY_CFG_WR_MASK, + PHY_CFG_WR_SHIFT)); +} + +static inline u32 phy_rd_cfg(struct rockchip_pcie_phy *rk_phy, + u32 addr) +{ + u32 val; + + regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf, + HIWORD_UPDATE(addr, + PHY_CFG_RD_MASK, + PHY_CFG_ADDR_SHIFT)); + regmap_read(rk_phy->reg_base, + rk_phy->phy_data->pcie_status, + &val); + return val; +} + +static int rockchip_pcie_phy_power_off(struct phy *phy) +{ + struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy); + int err = 0; + + err = reset_control_assert(rk_phy->phy_rst); + if (err) { + dev_err(&phy->dev, "assert phy_rst err %d\n", err); + return err; + } + + return 0; +} + +static int rockchip_pcie_phy_power_on(struct phy *phy) +{ + struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy); + int err = 0; + u32 status; + unsigned long timeout; + + err = reset_control_deassert(rk_phy->phy_rst); + if (err) { + dev_err(&phy->dev, "deassert phy_rst err %d\n", err); + return err; + } + + regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf, + HIWORD_UPDATE(PHY_CFG_PLL_LOCK, + PHY_CFG_ADDR_MASK, + PHY_CFG_ADDR_SHIFT)); + + /* + * No documented timeout value for phy operation below, + * so we make it large enough here. And we use loop-break + * method which should not be harmful. + */ + timeout = jiffies + msecs_to_jiffies(1000); + + err = -EINVAL; + while (time_before(jiffies, timeout)) { + regmap_read(rk_phy->reg_base, + rk_phy->phy_data->pcie_status, + &status); + if (status & PHY_PLL_LOCKED) { + dev_dbg(&phy->dev, "pll locked!\n"); + err = 0; + break; + } + msleep(20); + } + + if (err) { + dev_err(&phy->dev, "pll lock timeout!\n"); + goto err_pll_lock; + } + + phy_wr_cfg(rk_phy, PHY_CFG_CLK_TEST, PHY_CFG_SEPE_RATE); + phy_wr_cfg(rk_phy, PHY_CFG_CLK_SCC, PHY_CFG_PLL_100M); + + err = -ETIMEDOUT; + while (time_before(jiffies, timeout)) { + regmap_read(rk_phy->reg_base, + rk_phy->phy_data->pcie_status, + &status); + if (!(status & PHY_PLL_OUTPUT)) { + dev_dbg(&phy->dev, "pll output enable done!\n"); + err = 0; + break; + } + msleep(20); + } + + if (err) { + dev_err(&phy->dev, "pll output enable timeout!\n"); + goto err_pll_lock; + } + + regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf, + HIWORD_UPDATE(PHY_CFG_PLL_LOCK, + PHY_CFG_ADDR_MASK, + PHY_CFG_ADDR_SHIFT)); + err = -EINVAL; + while (time_before(jiffies, timeout)) { + regmap_read(rk_phy->reg_base, + rk_phy->phy_data->pcie_status, + &status); + if (status & PHY_PLL_LOCKED) { + dev_dbg(&phy->dev, "pll relocked!\n"); + err = 0; + break; + } + msleep(20); + } + + if (err) { + dev_err(&phy->dev, "pll relock timeout!\n"); + goto err_pll_lock; + } + + return 0; + +err_pll_lock: + reset_control_assert(rk_phy->phy_rst); + return err; +} + +static int rockchip_pcie_phy_init(struct phy *phy) +{ + struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy); + int err = 0; + + err = clk_prepare_enable(rk_phy->clk_pciephy_ref); + if (err) { + dev_err(&phy->dev, "Fail to enable pcie ref clock.\n"); + goto err_refclk; + } + + err = reset_control_assert(rk_phy->phy_rst); + if (err) { + dev_err(&phy->dev, "assert phy_rst err %d\n", err); + goto err_reset; + } + + return err; + +err_reset: + clk_disable_unprepare(rk_phy->clk_pciephy_ref); +err_refclk: + return err; +} + +static int rockchip_pcie_phy_exit(struct phy *phy) +{ + struct rockchip_pcie_phy *rk_phy = phy_get_drvdata(phy); + int err = 0; + + clk_disable_unprepare(rk_phy->clk_pciephy_ref); + + err = reset_control_deassert(rk_phy->phy_rst); + if (err) { + dev_err(&phy->dev, "deassert phy_rst err %d\n", err); + goto err_reset; + } + + return err; + +err_reset: + clk_prepare_enable(rk_phy->clk_pciephy_ref); + return err; +} + +static const struct phy_ops ops = { + .init = rockchip_pcie_phy_init, + .exit = rockchip_pcie_phy_exit, + .power_on = rockchip_pcie_phy_power_on, + .power_off = rockchip_pcie_phy_power_off, + .owner = THIS_MODULE, +}; + +static const struct rockchip_pcie_data rk3399_pcie_data = { + .pcie_conf = 0xe220, + .pcie_status = 0xe2a4, + .pcie_laneoff = 0xe214, +}; + +static const struct of_device_id rockchip_pcie_phy_dt_ids[] = { + { + .compatible = "rockchip,rk3399-pcie-phy", + .data = &rk3399_pcie_data, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, rockchip_pcie_phy_dt_ids); + +static int rockchip_pcie_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rockchip_pcie_phy *rk_phy; + struct phy *generic_phy; + struct phy_provider *phy_provider; + struct regmap *grf; + const struct of_device_id *of_id; + + grf = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(grf)) { + dev_err(dev, "Cannot find GRF syscon\n"); + return PTR_ERR(grf); + } + + rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL); + if (!rk_phy) + return -ENOMEM; + + of_id = of_match_device(rockchip_pcie_phy_dt_ids, &pdev->dev); + if (!of_id) + return -EINVAL; + + rk_phy->phy_data = (struct rockchip_pcie_data *)of_id->data; + rk_phy->reg_base = grf; + + rk_phy->phy_rst = devm_reset_control_get(dev, "phy"); + if (IS_ERR(rk_phy->phy_rst)) { + if (PTR_ERR(rk_phy->phy_rst) != -EPROBE_DEFER) + dev_err(dev, + "missing phy property for reset controller\n"); + return PTR_ERR(rk_phy->phy_rst); + } + + rk_phy->clk_pciephy_ref = devm_clk_get(dev, "refclk"); + if (IS_ERR(rk_phy->clk_pciephy_ref)) { + dev_err(dev, "refclk not found.\n"); + return PTR_ERR(rk_phy->clk_pciephy_ref); + } + + generic_phy = devm_phy_create(dev, dev->of_node, &ops); + if (IS_ERR(generic_phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(generic_phy); + } + + phy_set_drvdata(generic_phy, rk_phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static struct platform_driver rockchip_pcie_driver = { + .probe = rockchip_pcie_phy_probe, + .driver = { + .name = "rockchip-pcie-phy", + .of_match_table = rockchip_pcie_phy_dt_ids, + }, +}; + +module_platform_driver(rockchip_pcie_driver); + +MODULE_AUTHOR("Shawn Lin "); +MODULE_DESCRIPTION("Rockchip PCIe PHY driver"); +MODULE_LICENSE("GPL v2"); From 0674b440b8c98a0fa353960c814076a32d39b472 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Wed, 31 Aug 2016 16:56:49 +0800 Subject: [PATCH 245/343] phy: tegra: add missing header dependencies We get 5 warnings when building kernel with W=1: drivers/phy/tegra/xusb.c:948:27: warning: no previous prototype for 'tegra_xusb_padctl_get' [-Wmissing-prototypes] drivers/phy/tegra/xusb.c:981:6: warning: no previous prototype for 'tegra_xusb_padctl_put' [-Wmissing-prototypes] drivers/phy/tegra/xusb.c:988:5: warning: no previous prototype for 'tegra_xusb_padctl_usb3_save_context' [-Wmissing-prototypes] drivers/phy/tegra/xusb.c:998:5: warning: no previous prototype for 'tegra_xusb_padctl_hsic_set_idle' [-Wmissing-prototypes] drivers/phy/tegra/xusb.c:1008:5: warning: no previous prototype for 'tegra_xusb_padctl_usb3_set_lfps_detect' [-Wmissing-prototypes] In fact, these functions are declared in linux/phy/tegra/xusb.h, so this patch adds missing header dependencies. Signed-off-by: Baoyou Xie Acked-by: Arnd Bergmann Acked-by: Thierry Reding Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/tegra/xusb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index ec83dfdbc206..dbd2a4db1078 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include From 713b3ce9a3afba269590b8630db8abd8e139f873 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Wed, 31 Aug 2016 17:05:19 +0800 Subject: [PATCH 246/343] phy: tegra: mark tegra_xusb_lane_lookup_function() static We get 1 warning when building kernel with W=1: drivers/phy/tegra/xusb.c:104:5: warning: no previous prototype for 'tegra_xusb_lane_lookup_function' [-Wmissing-prototypes] In fact, this function is only used in the file in which it is declared and don't need a declaration, but can be made static. So this patch marks it 'static'. Signed-off-by: Baoyou Xie Acked-by: Arnd Bergmann Acked-by: Thierry Reding Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/tegra/xusb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index dbd2a4db1078..873424ab0e32 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -102,7 +102,8 @@ tegra_xusb_pad_find_phy_node(struct tegra_xusb_pad *pad, unsigned int index) return of_find_node_by_name(np, pad->soc->lanes[index].name); } -int tegra_xusb_lane_lookup_function(struct tegra_xusb_lane *lane, +static int +tegra_xusb_lane_lookup_function(struct tegra_xusb_lane *lane, const char *function) { unsigned int i; From b9d0397fefb3487ed121d45c9ecf4a21d4ecd54c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 30 Aug 2016 21:53:59 +0800 Subject: [PATCH 247/343] phy: bcm-ns2-pcie: Get rid of struct ns2_pci_phy By setting phy_set_drvdata(phy, mdiodev), struct ns2_pci_phy can be removed. Signed-off-by: Axel Lin Reviewed-and-tested-by: Jon Mason Reviewed-by: Pramod Kumar Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-bcm-ns2-pcie.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/drivers/phy/phy-bcm-ns2-pcie.c b/drivers/phy/phy-bcm-ns2-pcie.c index 9513f7ab1eaa..ee6177296ac2 100644 --- a/drivers/phy/phy-bcm-ns2-pcie.c +++ b/drivers/phy/phy-bcm-ns2-pcie.c @@ -18,11 +18,6 @@ #include #include -struct ns2_pci_phy { - struct mdio_device *mdiodev; - struct phy *phy; -}; - #define BLK_ADDR_REG_OFFSET 0x1f #define PLL_AFE1_100MHZ_BLK 0x2100 #define PLL_CLK_AMP_OFFSET 0x03 @@ -30,17 +25,17 @@ struct ns2_pci_phy { static int ns2_pci_phy_init(struct phy *p) { - struct ns2_pci_phy *phy = phy_get_drvdata(p); + struct mdio_device *mdiodev = phy_get_drvdata(p); int rc; /* select the AFE 100MHz block page */ - rc = mdiobus_write(phy->mdiodev->bus, phy->mdiodev->addr, + rc = mdiobus_write(mdiodev->bus, mdiodev->addr, BLK_ADDR_REG_OFFSET, PLL_AFE1_100MHZ_BLK); if (rc) goto err; /* set the 100 MHz reference clock amplitude to 2.05 v */ - rc = mdiobus_write(phy->mdiodev->bus, phy->mdiodev->addr, + rc = mdiobus_write(mdiodev->bus, mdiodev->addr, PLL_CLK_AMP_OFFSET, PLL_CLK_AMP_2P05V); if (rc) goto err; @@ -48,7 +43,7 @@ static int ns2_pci_phy_init(struct phy *p) return 0; err: - dev_err(&phy->mdiodev->dev, "Error %d writing to phy\n", rc); + dev_err(&mdiodev->dev, "Error %d writing to phy\n", rc); return rc; } @@ -60,7 +55,6 @@ static int ns2_pci_phy_probe(struct mdio_device *mdiodev) { struct device *dev = &mdiodev->dev; struct phy_provider *provider; - struct ns2_pci_phy *p; struct phy *phy; phy = devm_phy_create(dev, dev->of_node, &ns2_pci_phy_ops); @@ -69,16 +63,7 @@ static int ns2_pci_phy_probe(struct mdio_device *mdiodev) return PTR_ERR(phy); } - p = devm_kmalloc(dev, sizeof(struct ns2_pci_phy), - GFP_KERNEL); - if (!p) - return -ENOMEM; - - p->mdiodev = mdiodev; - dev_set_drvdata(dev, p); - - p->phy = phy; - phy_set_drvdata(phy, p); + phy_set_drvdata(phy, mdiodev); provider = devm_of_phy_provider_register(&phy->dev, of_phy_simple_xlate); From 5ed0e7410451f1148d7655461cae7ed23aafd244 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 30 Aug 2016 21:54:00 +0800 Subject: [PATCH 248/343] phy: bcm-ns2-pcie: Set missing .owner field in ns2_pci_phy_ops Add missing .owner field in ns2_pci_phy_ops, which is used for refcounting. While at it, also makes ns2_pci_phy_ops const as it's never get modified. Signed-off-by: Axel Lin Reviewed-and-tested-by: Jon Mason Reviewed-by: Pramod Kumar Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-bcm-ns2-pcie.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/phy-bcm-ns2-pcie.c b/drivers/phy/phy-bcm-ns2-pcie.c index ee6177296ac2..4c7d11d2b378 100644 --- a/drivers/phy/phy-bcm-ns2-pcie.c +++ b/drivers/phy/phy-bcm-ns2-pcie.c @@ -47,8 +47,9 @@ err: return rc; } -static struct phy_ops ns2_pci_phy_ops = { +static const struct phy_ops ns2_pci_phy_ops = { .init = ns2_pci_phy_init, + .owner = THIS_MODULE, }; static int ns2_pci_phy_probe(struct mdio_device *mdiodev) From 8cf1ffe985ef81c983092838332a639cbf86d74c Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 24 Aug 2016 15:49:21 +0900 Subject: [PATCH 249/343] phy: rcar-gen3-usb2: revise the example of device tree doc The clocks property should be set to &cpg, not &mstpX_clks. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index 2281d6cdecb1..b54fb36dcafc 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -30,11 +30,11 @@ Example (R-Car H3): compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy"; reg = <0 0xee080200 0 0x700>; interrupts = ; - clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; + clocks = <&cpg CPG_MOD 703>; }; usb-phy@ee0a0200 { compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy"; reg = <0 0xee0a0200 0 0x700>; - clocks = <&mstp7_clks R8A7795_CLK_EHCI0>; + clocks = <&cpg CPG_MOD 702>; }; From 800dcc307dfeea7c3d7ff46f3d7d592a8dac3ea1 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 24 Aug 2016 15:49:22 +0900 Subject: [PATCH 250/343] phy: rcar-gen3-usb2: Add a compatible string for r8a7796 This driver can support for r8a7796 SoC. So, this patch adds it. Signed-off-by: Yoshihiro Shimoda Acked-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | 2 ++ drivers/phy/phy-rcar-gen3-usb2.c | 1 + 2 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index b54fb36dcafc..ace9cce2704a 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt @@ -5,6 +5,8 @@ This file provides information on what the device node for the R-Car generation Required properties: - compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 + SoC. + "renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796 SoC. "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device. diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index 31156c9c4707..3d97eadd247d 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -280,6 +280,7 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { { .compatible = "renesas,usb2-phy-r8a7795" }, + { .compatible = "renesas,usb2-phy-r8a7796" }, { .compatible = "renesas,rcar-gen3-usb2-phy" }, { } }; From 80fc6660caa64ebc7df7c78d886d2023fd652904 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 23 Aug 2016 11:57:39 +0300 Subject: [PATCH 251/343] phy: omap-usb2: support suspend/resume Relying on PM-ops for shutting down PHY clocks was a bad idea since the users (e.g. USB DWC3) might not have been suspended by then. Get rid of all PM-ops. It is the sole responsibility of the PHY user to properly turn OFF and de-initialize the PHY as part of its suspend routine. Enable/disable PHY clock as part of ->init()/->exit() call respectively. With this phy_init() and phy_exit() can be called by PHY user during suspend/resume. This is similar to what is done for ti-pipe3 driver. See 31c8954efb1b ("phy: ti-pipe3: fix suspend") The pm_runtime_enable() call in omap_usb2_probe() is still required because without it, phy_create() will not enable runtime PM on the phy device it creates and phy_init() will not call pm_runtime_get_sync(). Without pm_runtime_get_sync(), ocp2scp hwmod will _not_ enable the IP and, thus, we will have abort exceptions. Signed-off-by: Sekhar Nori Signed-off-by: Roger Quadros Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-omap-usb2.c | 100 +++++++++++++++++------------------- 1 file changed, 46 insertions(+), 54 deletions(-) diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index c134989052f5..fe909fd8144f 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -133,11 +133,49 @@ static int omap_usb_power_on(struct phy *x) return omap_usb_phy_power(phy, true); } +static int omap_usb2_disable_clocks(struct omap_usb *phy) +{ + clk_disable(phy->wkupclk); + if (!IS_ERR(phy->optclk)) + clk_disable(phy->optclk); + + return 0; +} + +static int omap_usb2_enable_clocks(struct omap_usb *phy) +{ + int ret; + + ret = clk_enable(phy->wkupclk); + if (ret < 0) { + dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); + goto err0; + } + + if (!IS_ERR(phy->optclk)) { + ret = clk_enable(phy->optclk); + if (ret < 0) { + dev_err(phy->dev, "Failed to enable optclk %d\n", ret); + goto err1; + } + } + + return 0; + +err1: + clk_disable(phy->wkupclk); + +err0: + return ret; +} + static int omap_usb_init(struct phy *x) { struct omap_usb *phy = phy_get_drvdata(x); u32 val; + omap_usb2_enable_clocks(phy); + if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { /* * @@ -155,8 +193,16 @@ static int omap_usb_init(struct phy *x) return 0; } +static int omap_usb_exit(struct phy *x) +{ + struct omap_usb *phy = phy_get_drvdata(x); + + return omap_usb2_disable_clocks(phy); +} + static const struct phy_ops ops = { .init = omap_usb_init, + .exit = omap_usb_exit, .power_on = omap_usb_power_on, .power_off = omap_usb_power_off, .owner = THIS_MODULE, @@ -376,65 +422,11 @@ static int omap_usb2_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM - -static int omap_usb2_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct omap_usb *phy = platform_get_drvdata(pdev); - - clk_disable(phy->wkupclk); - if (!IS_ERR(phy->optclk)) - clk_disable(phy->optclk); - - return 0; -} - -static int omap_usb2_runtime_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct omap_usb *phy = platform_get_drvdata(pdev); - int ret; - - ret = clk_enable(phy->wkupclk); - if (ret < 0) { - dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); - goto err0; - } - - if (!IS_ERR(phy->optclk)) { - ret = clk_enable(phy->optclk); - if (ret < 0) { - dev_err(phy->dev, "Failed to enable optclk %d\n", ret); - goto err1; - } - } - - return 0; - -err1: - clk_disable(phy->wkupclk); - -err0: - return ret; -} - -static const struct dev_pm_ops omap_usb2_pm_ops = { - SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume, - NULL) -}; - -#define DEV_PM_OPS (&omap_usb2_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - static struct platform_driver omap_usb2_driver = { .probe = omap_usb2_probe, .remove = omap_usb2_remove, .driver = { .name = "omap-usb2", - .pm = DEV_PM_OPS, .of_match_table = omap_usb2_id_table, }, }; From a0ceee5893d7915ab533391bea2ed245c9223175 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 23 Aug 2016 11:57:40 +0300 Subject: [PATCH 252/343] dt-bindings: phy: ti: add documentation for ti,dra7x-usb2 Commit 7e472402ca30 ("phy: omap-usb2: Provide workaround for USB2PHY false disconnect") added a new binding for USB2 PHYs on DRA7x. But it has remained undocumented so far. Add documentation for the binding. Signed-off-by: Sekhar Nori Signed-off-by: Roger Quadros Acked-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/ti-phy.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/ti-phy.txt b/Documentation/devicetree/bindings/phy/ti-phy.txt index a3b394587874..cd13e6157088 100644 --- a/Documentation/devicetree/bindings/phy/ti-phy.txt +++ b/Documentation/devicetree/bindings/phy/ti-phy.txt @@ -31,6 +31,8 @@ OMAP USB2 PHY Required properties: - compatible: Should be "ti,omap-usb2" + Should be "ti,dra7x-usb2" for the 1st instance of USB2 PHY on + DRA7x Should be "ti,dra7x-usb2-phy2" for the 2nd instance of USB2 PHY in DRA7x - reg : Address and length of the register set for the device. From 3fa295667a70e8f2e7e0251dbaa615b01ca82b23 Mon Sep 17 00:00:00 2001 From: Frank Wang Date: Tue, 16 Aug 2016 14:13:42 +0800 Subject: [PATCH 253/343] phy: rockchip-inno-usb2: add COMMON_CLK dependency On kernel builds without COMMON_CLK, the newly added rockchip-inno-usb2 driver fails to build: drivers/phy/phy-rockchip-inno-usb2.c:124:16: error: field 'clk480m_hw' has incomplete type struct clk_hw clk480m_hw; In file included from include/linux/clk.h:16:0 from drivers/phy/phy-rockchip-inno-usb2.c:17: include/linux/kernel.h:831:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types] const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ... ... Signed-off-by: Frank Wang Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Guenter Roeck Reviewed-by: Heiko Stuebner --- drivers/phy/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 46e5536c453e..8cf6c3d0f71a 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -370,6 +370,7 @@ config PHY_ROCKCHIP_USB config PHY_ROCKCHIP_INNO_USB2 tristate "Rockchip INNO USB2PHY Driver" depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF + depends on COMMON_CLK select GENERIC_PHY help Support for Rockchip USB2.0 PHY with Innosilicon IP block. From 44d6106808a841d89dd7c96740917538ea47a29c Mon Sep 17 00:00:00 2001 From: Venkat Reddy Talla Date: Tue, 5 Jul 2016 19:26:21 +0530 Subject: [PATCH 254/343] extcon: adc-jack: update cable state during boot Update cable state during boot to avoid any missing external cable events occurred before driver initialisation. Signed-off-by: Venkat Reddy Talla Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 44e48aa78a84..48dec94b487b 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -158,6 +158,7 @@ static int adc_jack_probe(struct platform_device *pdev) if (data->wakeup_source) device_init_wakeup(&pdev->dev, 1); + adc_jack_handler(&data->handler.work); return 0; } From 97536d1d27e583daa8c3235ea9936065a1ae01fc Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 5 Jul 2016 11:57:05 -0700 Subject: [PATCH 255/343] extcon: Move extcon_get_edev_by_phandle() errors to dbg level Sometimes drivers may call this API and expect it to fail because the extcon they're looking for is optional. Let's move these prints to debug level so it doesn't look like there's a problem when there isn't one. Signed-off-by: Stephen Boyd Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 8682efc0f57b..319659c6af28 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -846,13 +846,13 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) return ERR_PTR(-EINVAL); if (!dev->of_node) { - dev_err(dev, "device does not have a device node entry\n"); + dev_dbg(dev, "device does not have a device node entry\n"); return ERR_PTR(-EINVAL); } node = of_parse_phandle(dev->of_node, "extcon", index); if (!node) { - dev_err(dev, "failed to get phandle in %s node\n", + dev_dbg(dev, "failed to get phandle in %s node\n", dev->of_node->full_name); return ERR_PTR(-ENODEV); } From 32daff5d77eb8053c75ce35731ec89d1f7f8eab8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 19 Jul 2016 13:23:56 +0100 Subject: [PATCH 256/343] extcon: arizona: Remove unneeded semi-colon There is no need for a semi-colon at the end of a switch statement so remove it. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 1d8e0a57bd51..be4d93d4c546 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -183,7 +183,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, if (clamp) val = ARIZONA_RMV_SHRT_HP1L; break; - }; + } snd_soc_dapm_mutex_lock(arizona->dapm); From cdc058320209d69a5eb7692658279e16aceb2d69 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 1 Jul 2016 02:36:49 +0900 Subject: [PATCH 257/343] extcon: arizona: Remove the usage of extcon_update_state() This patch remvoes the usage of extcon_update_state() because the extcon_update_state() use directly the bit masking calculation to change the state of external connector without the unique id of external connector. It makes the code diffcult to read it. So, this patch uses the extcon_set_cable_state_() instead. Signed-off-by: Chanwoo Choi Acked-by: Charles Keepax --- drivers/extcon/extcon-arizona.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index be4d93d4c546..493bd9fe5f67 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1149,10 +1149,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data) info->micd_ranges[i].key, 0); input_sync(info->input); - ret = extcon_update_state(info->edev, 0xffffffff, 0); - if (ret != 0) - dev_err(arizona->dev, "Removal report failed: %d\n", - ret); + for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) { + ret = extcon_set_cable_state_(info->edev, + arizona_cable[i], false); + if (ret != 0) + dev_err(arizona->dev, + "Removal report failed: %d\n", ret); + } regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE, From cc60211237086d718e463bcee74004b5bd38a78c Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 18 Jul 2016 16:16:29 +0900 Subject: [PATCH 258/343] extcon: adc-jack: Remove the usage of extcon_set_state() This patch removes the usage of extcon_set_state() because it uses the bit masking to change the state of external connectors. The extcon framework should handle the state by extcon_set/get_cable_state_() with extcon id. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-adc-jack.c | 26 ++++++++++++++------------ include/linux/extcon/extcon-adc-jack.h | 4 ++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 48dec94b487b..e62e6cd7e00a 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -3,6 +3,9 @@ * * Analog Jack extcon driver with ADC-based detection capability. * + * Copyright (C) 2016 Samsung Electronics + * Chanwoo Choi + * * Copyright (C) 2012 Samsung Electronics * MyungJoo Ham * @@ -58,7 +61,7 @@ static void adc_jack_handler(struct work_struct *work) struct adc_jack_data *data = container_of(to_delayed_work(work), struct adc_jack_data, handler); - u32 state = 0; + struct adc_jack_cond *def; int ret, adc_val; int i; @@ -70,17 +73,18 @@ static void adc_jack_handler(struct work_struct *work) /* Get state from adc value with adc_conditions */ for (i = 0; i < data->num_conditions; i++) { - struct adc_jack_cond *def = &data->adc_conditions[i]; - if (!def->state) - break; + def = &data->adc_conditions[i]; if (def->min_adc <= adc_val && def->max_adc >= adc_val) { - state = def->state; - break; + extcon_set_cable_state_(data->edev, def->id, true); + return; } } - /* if no def has met, it means state = 0 (no cables attached) */ - extcon_set_state(data->edev, state); + /* Set the detached state if adc value is not included in the range */ + for (i = 0; i < data->num_conditions; i++) { + def = &data->adc_conditions[i]; + extcon_set_cable_state_(data->edev, def->id, false); + } } static irqreturn_t adc_jack_irq_thread(int irq, void *_data) @@ -114,16 +118,14 @@ static int adc_jack_probe(struct platform_device *pdev) return -ENOMEM; } - if (!pdata->adc_conditions || - !pdata->adc_conditions[0].state) { + if (!pdata->adc_conditions) { dev_err(&pdev->dev, "error: adc_conditions not defined.\n"); return -EINVAL; } data->adc_conditions = pdata->adc_conditions; /* Check the length of array and set num_conditions */ - for (i = 0; data->adc_conditions[i].state; i++) - ; + for (i = 0; data->adc_conditions[i].id != EXTCON_NONE; i++); data->num_conditions = i; data->chan = iio_channel_get(&pdev->dev, pdata->consumer_channel); diff --git a/include/linux/extcon/extcon-adc-jack.h b/include/linux/extcon/extcon-adc-jack.h index ac85f2061351..a0e03b13b449 100644 --- a/include/linux/extcon/extcon-adc-jack.h +++ b/include/linux/extcon/extcon-adc-jack.h @@ -20,8 +20,8 @@ /** * struct adc_jack_cond - condition to use an extcon state - * @state: the corresponding extcon state (if 0, this struct * denotes the last adc_jack_cond element among the array) + * @id: the unique id of each external connector * @min_adc: min adc value for this condition * @max_adc: max adc value for this condition * @@ -33,7 +33,7 @@ * because when no adc_jack_cond is met, state = 0 is automatically chosen. */ struct adc_jack_cond { - u32 state; /* extcon state value. 0 if invalid */ + unsigned int id; u32 min_adc; u32 max_adc; }; From 1662622fe595919ef004ef24364a68061052a12f Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 21 Jul 2016 20:00:29 +0900 Subject: [PATCH 259/343] extcon: gpio: Remove the usage of extcon_set_state() This patch removes the usage of extcon_set_state() because it uses the bit masking to change the state of external connectors. The extcon framework should handle the state by extcon_set_cable_state_() with extcon id. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index d023789f0fda..b1b0264eb12d 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -49,7 +49,7 @@ static void gpio_extcon_work(struct work_struct *work) state = gpiod_get_value_cansleep(data->id_gpiod); if (data->pdata->gpio_active_low) state = !state; - extcon_set_state(data->edev, state); + extcon_set_cable_state_(data->edev, data->pdata->extcon_id, state); } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) From 0143f59de50eee70485be9b658e42495d72698dd Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 18 Jul 2016 15:39:28 +0900 Subject: [PATCH 260/343] extcon: Remove the state_store() to prevent the wrong access This patch removes the state_store() which change the state of external connectors with bit masking on user-space. It is wrong access to modify the change the state of external connectors. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 319659c6af28..ad5e4546f82c 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -174,26 +174,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, return count; } - -static ssize_t state_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - u32 state; - ssize_t ret = 0; - struct extcon_dev *edev = dev_get_drvdata(dev); - - ret = sscanf(buf, "0x%x", &state); - if (ret == 0) - ret = -EINVAL; - else - ret = extcon_set_state(edev, state); - - if (ret < 0) - return ret; - - return count; -} -static DEVICE_ATTR_RW(state); +static DEVICE_ATTR_RO(state); static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) From 84c48dc55945b4edfb63388832ebcca82d003ee7 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 1 Jul 2016 02:41:18 +0900 Subject: [PATCH 261/343] extcon: Block the bit masking operation for cable state except for extcon core This patch restrict the usage of extcon_update_state() in the extcon core because the extcon_update_state() use the bit masking to change the state of external connector. When this function is used in device drivers, it may occur the probelm with the handling mistake of bit masking. Also, this patch removes the extcon_get/set_state() functions because these functions use the bit masking which is reluctant way. Instead, extcon provides the extcon_set/get_cable_state_() functions. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 20 +------------------- include/linux/extcon.h | 30 ------------------------------ 2 files changed, 1 insertion(+), 49 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index ad5e4546f82c..5b61000cde26 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -224,7 +224,7 @@ static ssize_t cable_state_show(struct device *dev, * Note that the notifier provides which bits are changed in the state * variable with the val parameter (second) to the callback. */ -int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) +static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) { char name_buf[120]; char state_buf[120]; @@ -300,24 +300,6 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) return 0; } -EXPORT_SYMBOL_GPL(extcon_update_state); - -/** - * extcon_set_state() - Set the cable attach states of the extcon device. - * @edev: the extcon device - * @state: new cable attach status for @edev - * - * Note that notifier provides which bits are changed in the state - * variable with the val parameter (second) to the callback. - */ -int extcon_set_state(struct extcon_dev *edev, u32 state) -{ - if (!edev) - return -EINVAL; - - return extcon_update_state(edev, 0xffffffff, state); -} -EXPORT_SYMBOL_GPL(extcon_set_state); /** * extcon_get_cable_state_() - Get the status of a specific cable. diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 61004413dc64..667b1d35af12 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -149,20 +149,6 @@ extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, const unsigned int *cable); extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); -/* - * get/set/update_state access the 32b encoded state value, which represents - * states of all possible cables of the multistate port. For example, if one - * calls extcon_set_state(edev, 0x7), it may mean that all the three cables - * are attached to the port. - */ -static inline u32 extcon_get_state(struct extcon_dev *edev) -{ - return edev->state; -} - -extern int extcon_set_state(struct extcon_dev *edev, u32 state); -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 id. @@ -232,22 +218,6 @@ static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, static inline void devm_extcon_dev_free(struct extcon_dev *edev) { } -static inline u32 extcon_get_state(struct extcon_dev *edev) -{ - return 0; -} - -static inline int extcon_set_state(struct extcon_dev *edev, u32 state) -{ - return 0; -} - -static inline int extcon_update_state(struct extcon_dev *edev, u32 mask, - u32 state) -{ - return 0; -} - static inline int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id) { From 6e25baab5a0b2af2ebeb1d817ef94b11fc465fbd Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Mon, 1 Aug 2016 14:51:30 +0530 Subject: [PATCH 262/343] extcon: Fix compile time warning This patch fixes below compilation warning:- drivers/extcon/extcon.c: In function extcon_register_notifier: drivers/extcon/extcon.c:455:6: warning: idx may be used uninitialized in this function [-Wmaybe-uninitialized] if (idx >= 0) { Signed-off-by: Vaneet Narang Signed-off-by: Maninder Singh [cw00.choi : Modify the patch title using the a captical letter for first char] Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 5b61000cde26..9a266e5c7e10 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -391,7 +391,7 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, struct notifier_block *nb) { unsigned long flags; - int ret, idx; + int ret, idx = -EINVAL; if (!nb) return -EINVAL; From 505cf01f984bdcf088c9ec1e96f987f1ff47dc21 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 11 Jul 2016 16:34:52 +0900 Subject: [PATCH 263/343] extcon: Add the extcon_type to gather each connector into five category This patch adds the new extcon type to group the each connecotr into following five category. This type would be used to handle the connectors as a group unit instead of a connector unit. - EXTCON_TYPE_USB : USB connector - EXTCON_TYPE_CHG : Charger connector - EXTCON_TYPE_JACK : Jack connector - EXTCON_TYPE_DISP : Display connector - EXTCON_TYPE_MISC : Miscellaneous connector Also, each external connector is possible to belong to one more extcon type. In caes of EXTCON_CHG_USB_SDP, it have the EXTCON_TYPE_CHG and EXTCON_TYPE_USB. Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Signed-off-by: MyungJoo Ham Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 157 +++++++++++++++++++++++++++++++++------- include/linux/extcon.h | 9 +++ 2 files changed, 138 insertions(+), 28 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 9a266e5c7e10..f209a6959fed 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -38,43 +38,144 @@ #define SUPPORTED_CABLE_MAX 32 #define CABLE_NAME_MAX 30 -static const char *extcon_name[] = { - [EXTCON_NONE] = "NONE", +struct __extcon_info { + unsigned int type; + unsigned int id; + const char *name; + +} extcon_info[] = { + [EXTCON_NONE] = { + .type = EXTCON_TYPE_MISC, + .id = EXTCON_NONE, + .name = "NONE", + }, /* USB external connector */ - [EXTCON_USB] = "USB", - [EXTCON_USB_HOST] = "USB-HOST", + [EXTCON_USB] = { + .type = EXTCON_TYPE_USB, + .id = EXTCON_USB, + .name = "USB", + }, + [EXTCON_USB_HOST] = { + .type = EXTCON_TYPE_USB, + .id = EXTCON_USB_HOST, + .name = "USB_HOST", + }, /* Charging external connector */ - [EXTCON_CHG_USB_SDP] = "SDP", - [EXTCON_CHG_USB_DCP] = "DCP", - [EXTCON_CHG_USB_CDP] = "CDP", - [EXTCON_CHG_USB_ACA] = "ACA", - [EXTCON_CHG_USB_FAST] = "FAST-CHARGER", - [EXTCON_CHG_USB_SLOW] = "SLOW-CHARGER", + [EXTCON_CHG_USB_SDP] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_SDP, + .name = "SDP", + }, + [EXTCON_CHG_USB_DCP] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_DCP, + .name = "DCP", + }, + [EXTCON_CHG_USB_CDP] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_CDP, + .name = "CDP", + }, + [EXTCON_CHG_USB_ACA] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_ACA, + .name = "ACA", + }, + [EXTCON_CHG_USB_FAST] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_FAST, + .name = "FAST-CHARGER", + }, + [EXTCON_CHG_USB_SLOW] = { + .type = EXTCON_TYPE_CHG | EXTCON_TYPE_USB, + .id = EXTCON_CHG_USB_SLOW, + .name = "SLOW-CHARGER", + }, /* Jack external connector */ - [EXTCON_JACK_MICROPHONE] = "MICROPHONE", - [EXTCON_JACK_HEADPHONE] = "HEADPHONE", - [EXTCON_JACK_LINE_IN] = "LINE-IN", - [EXTCON_JACK_LINE_OUT] = "LINE-OUT", - [EXTCON_JACK_VIDEO_IN] = "VIDEO-IN", - [EXTCON_JACK_VIDEO_OUT] = "VIDEO-OUT", - [EXTCON_JACK_SPDIF_IN] = "SPDIF-IN", - [EXTCON_JACK_SPDIF_OUT] = "SPDIF-OUT", + [EXTCON_JACK_MICROPHONE] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_MICROPHONE, + .name = "MICROPHONE", + }, + [EXTCON_JACK_HEADPHONE] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_HEADPHONE, + .name = "HEADPHONE", + }, + [EXTCON_JACK_LINE_IN] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_LINE_IN, + .name = "LINE-IN", + }, + [EXTCON_JACK_LINE_OUT] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_LINE_OUT, + .name = "LINE-OUT", + }, + [EXTCON_JACK_VIDEO_IN] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_VIDEO_IN, + .name = "VIDEO-IN", + }, + [EXTCON_JACK_VIDEO_OUT] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_VIDEO_OUT, + .name = "VIDEO-OUT", + }, + [EXTCON_JACK_SPDIF_IN] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_SPDIF_IN, + .name = "SPDIF-IN", + }, + [EXTCON_JACK_SPDIF_OUT] = { + .type = EXTCON_TYPE_JACK, + .id = EXTCON_JACK_SPDIF_OUT, + .name = "SPDIF-OUT", + }, /* Display external connector */ - [EXTCON_DISP_HDMI] = "HDMI", - [EXTCON_DISP_MHL] = "MHL", - [EXTCON_DISP_DVI] = "DVI", - [EXTCON_DISP_VGA] = "VGA", + [EXTCON_DISP_HDMI] = { + .type = EXTCON_TYPE_DISP, + .id = EXTCON_DISP_HDMI, + .name = "HDMI", + }, + [EXTCON_DISP_MHL] = { + .type = EXTCON_TYPE_DISP, + .id = EXTCON_DISP_MHL, + .name = "MHL", + }, + [EXTCON_DISP_DVI] = { + .type = EXTCON_TYPE_DISP, + .id = EXTCON_DISP_DVI, + .name = "DVI", + }, + [EXTCON_DISP_VGA] = { + .type = EXTCON_TYPE_DISP, + .id = EXTCON_DISP_VGA, + .name = "VGA", + }, /* Miscellaneous external connector */ - [EXTCON_DOCK] = "DOCK", - [EXTCON_JIG] = "JIG", - [EXTCON_MECHANICAL] = "MECHANICAL", + [EXTCON_DOCK] = { + .type = EXTCON_TYPE_MISC, + .id = EXTCON_DOCK, + .name = "DOCK", + }, + [EXTCON_JIG] = { + .type = EXTCON_TYPE_MISC, + .id = EXTCON_JIG, + .name = "JIG", + }, + [EXTCON_MECHANICAL] = { + .type = EXTCON_TYPE_MISC, + .id = EXTCON_MECHANICAL, + .name = "MECHANICAL", + }, - NULL, + { /* sentinel */ } }; /** @@ -168,7 +269,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, for (i = 0; i < edev->max_supported; i++) { count += sprintf(buf + count, "%s=%d\n", - extcon_name[edev->supported_cable[i]], + extcon_info[edev->supported_cable[i]].name, !!(edev->state & (1 << i))); } @@ -193,7 +294,7 @@ static ssize_t cable_name_show(struct device *dev, int i = cable->cable_index; return sprintf(buf, "%s\n", - extcon_name[cable->edev->supported_cable[i]]); + extcon_info[cable->edev->supported_cable[i]].name); } static ssize_t cable_state_show(struct device *dev, diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 667b1d35af12..46d802892c82 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -28,6 +28,15 @@ #include +/* + * Define the type of supported external connectors + */ +#define EXTCON_TYPE_USB BIT(0) /* USB connector */ +#define EXTCON_TYPE_CHG BIT(1) /* Charger connector */ +#define EXTCON_TYPE_JACK BIT(2) /* Jack connector */ +#define EXTCON_TYPE_DISP BIT(3) /* Display connector */ +#define EXTCON_TYPE_MISC BIT(4) /* Miscellaneous connector */ + /* * Define the unique id of supported external connectors */ From 067c1652e7a7d50d951eee1d34a414ea931cee6c Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 11 Jul 2016 19:30:43 +0900 Subject: [PATCH 264/343] extcon: Add the support for extcon property according to extcon type This patch support the extcon property for the external connector because each external connector might have the property according to the H/W design and the specific characteristics. - EXTCON_PROP_USB_[property name] - EXTCON_PROP_CHG_[property name] - EXTCON_PROP_JACK_[property name] - EXTCON_PROP_DISP_[property name] Add the new extcon APIs to get/set the property value as following: - int extcon_get_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value *prop_val) - int extcon_set_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val) Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 201 +++++++++++++++++++++++++++++++++++++++- include/linux/extcon.h | 81 ++++++++++++++++ 2 files changed, 281 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index f209a6959fed..37fa4b51c5a1 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -196,6 +196,11 @@ struct extcon_cable { struct device_attribute attr_state; struct attribute *attrs[3]; /* to be fed to attr_g.attrs */ + + union extcon_property_value usb_propval[EXTCON_PROP_USB_CNT]; + union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT]; + union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; + union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; }; static struct class *extcon_class; @@ -248,6 +253,27 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id return -EINVAL; } +static int get_extcon_type(unsigned int prop) +{ + switch (prop) { + case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: + return EXTCON_TYPE_USB; + case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: + return EXTCON_TYPE_CHG; + case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: + return EXTCON_TYPE_JACK; + case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: + return EXTCON_TYPE_DISP; + default: + return -EINVAL; + } +} + +static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index) +{ + return !!(edev->state & BIT(index)); +} + static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) { if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) { @@ -258,6 +284,34 @@ static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) return false; } +static bool is_extcon_property_supported(unsigned int id, unsigned int prop) +{ + int type; + + /* Check whether the property is supported or not. */ + type = get_extcon_type(prop); + if (type < 0) + return false; + + /* Check whether a specific extcon id supports the property or not. */ + return !!(extcon_info[id].type & type); +} + +static void init_property(struct extcon_dev *edev, unsigned int id, int index) +{ + unsigned int type = extcon_info[id].type; + struct extcon_cable *cable = &edev->cables[index]; + + if (EXTCON_TYPE_USB & type) + memset(cable->usb_propval, 0, sizeof(cable->usb_propval)); + if (EXTCON_TYPE_CHG & type) + memset(cable->chg_propval, 0, sizeof(cable->chg_propval)); + if (EXTCON_TYPE_JACK & type) + memset(cable->jack_propval, 0, sizeof(cable->jack_propval)); + if (EXTCON_TYPE_DISP & type) + memset(cable->disp_propval, 0, sizeof(cable->disp_propval)); +} + static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -421,7 +475,7 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) if (edev->max_supported && edev->max_supported <= index) return -EINVAL; - return !!(edev->state & (1 << index)); + return is_extcon_attached(edev, index); } EXPORT_SYMBOL_GPL(extcon_get_cable_state_); @@ -449,11 +503,156 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, if (edev->max_supported && edev->max_supported <= index) return -EINVAL; + /* + * Initialize the value of extcon property before setting + * the detached state for an external connector. + */ + if (!cable_state) + init_property(edev, id, index); + state = cable_state ? (1 << index) : 0; return extcon_update_state(edev, 1 << index, state); } EXPORT_SYMBOL_GPL(extcon_set_cable_state_); +/** + * extcon_get_property() - Get the property value of a specific cable. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @prop: the property id among enum extcon_property. + * @prop_val: the pointer which store the value of property. + * + * When getting the property value of external connector, the external connector + * should be attached. If detached state, function just return 0 without + * property value. Also, the each property should be included in the list of + * supported properties according to the type of external connectors. + * + * Returns 0 if success or error number if fail + */ +int extcon_get_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value *prop_val) +{ + struct extcon_cable *cable; + unsigned long flags; + int index, ret = 0; + + *prop_val = (union extcon_property_value)(0); + + if (!edev) + return -EINVAL; + + /* Check whether the property is supported or not */ + if (!is_extcon_property_supported(id, prop)) + return -EINVAL; + + /* Find the cable index of external connector by using id */ + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + spin_lock_irqsave(&edev->lock, flags); + + /* + * Check whether the external connector is attached. + * If external connector is detached, the user can not + * get the property value. + */ + if (!is_extcon_attached(edev, index)) { + spin_unlock_irqrestore(&edev->lock, flags); + return 0; + } + + cable = &edev->cables[index]; + + /* Get the property value according to extcon type */ + switch (prop) { + case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: + *prop_val = cable->usb_propval[prop - EXTCON_PROP_USB_MIN]; + break; + case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: + *prop_val = cable->chg_propval[prop - EXTCON_PROP_CHG_MIN]; + break; + case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: + *prop_val = cable->jack_propval[prop - EXTCON_PROP_JACK_MIN]; + break; + case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: + *prop_val = cable->disp_propval[prop - EXTCON_PROP_DISP_MIN]; + break; + default: + ret = -EINVAL; + break; + } + + spin_unlock_irqrestore(&edev->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(extcon_get_property); + +/** + * extcon_set_property() - Set the property value of a specific cable. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @prop: the property id among enum extcon_property. + * @prop_val: the pointer including the new value of property. + * + * The each property should be included in the list of supported properties + * according to the type of external connectors. + * + * Returns 0 if success or error number if fail + */ +int extcon_set_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val) +{ + struct extcon_cable *cable; + unsigned long flags; + int index, ret = 0; + + if (!edev) + return -EINVAL; + + /* Check whether the property is supported or not */ + if (!is_extcon_property_supported(id, prop)) + return -EINVAL; + + /* Find the cable index of external connector by using id */ + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + spin_lock_irqsave(&edev->lock, flags); + + cable = &edev->cables[index]; + + /* Set the property value according to extcon type */ + switch (prop) { + case EXTCON_PROP_USB_MIN ... EXTCON_PROP_USB_MAX: + cable->usb_propval[prop - EXTCON_PROP_USB_MIN] = prop_val; + break; + case EXTCON_PROP_CHG_MIN ... EXTCON_PROP_CHG_MAX: + cable->chg_propval[prop - EXTCON_PROP_CHG_MIN] = prop_val; + break; + case EXTCON_PROP_JACK_MIN ... EXTCON_PROP_JACK_MAX: + cable->jack_propval[prop - EXTCON_PROP_JACK_MIN] = prop_val; + break; + case EXTCON_PROP_DISP_MIN ... EXTCON_PROP_DISP_MAX: + cable->disp_propval[prop - EXTCON_PROP_DISP_MIN] = prop_val; + break; + default: + ret = -EINVAL; + break; + } + + spin_unlock_irqrestore(&edev->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(extcon_set_property); + /** * extcon_get_extcon_dev() - Get the extcon device instance from the name * @extcon_name: The extcon name provided with extcon_dev_register() diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 46d802892c82..f9d4a44e86d3 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -77,6 +77,63 @@ #define EXTCON_NUM 63 +/* + * Define the property of supported external connectors. + * + * When adding the new extcon property, they *must* have + * the type/value/default information. Also, you *have to* + * modify the EXTCON_PROP_[type]_START/END definitions + * which mean the range of the supported properties + * for each extcon type. + * + * The naming style of property + * : EXTCON_PROP_[type]_[property name] + * + * EXTCON_PROP_USB_[property name] : USB property + * EXTCON_PROP_CHG_[property name] : Charger property + * EXTCON_PROP_JACK_[property name] : Jack property + * EXTCON_PROP_DISP_[property name] : Display property + */ + +/* + * Properties of EXTCON_TYPE_USB. + * + * - EXTCON_PROP_USB_VBUS + * @type: integer (intval) + * @value: 0 (low) or 1 (high) + * @default: 0 (low) + */ +#define EXTCON_PROP_USB_VBUS 0 + +#define EXTCON_PROP_USB_MIN 0 +#define EXTCON_PROP_USB_MAX 0 +#define EXTCON_PROP_USB_CNT (EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1) + +/* Properties of EXTCON_TYPE_CHG. */ +#define EXTCON_PROP_CHG_MIN 50 +#define EXTCON_PROP_CHG_MAX 50 +#define EXTCON_PROP_CHG_CNT (EXTCON_PROP_CHG_MAX - EXTCON_PROP_CHG_MIN + 1) + +/* Properties of EXTCON_TYPE_JACK. */ +#define EXTCON_PROP_JACK_MIN 100 +#define EXTCON_PROP_JACK_MAX 100 +#define EXTCON_PROP_JACK_CNT (EXTCON_PROP_JACK_MAX - EXTCON_PROP_JACK_MIN + 1) + +/* Properties of EXTCON_TYPE_DISP. */ +#define EXTCON_PROP_DISP_MIN 150 +#define EXTCON_PROP_DISP_MAX 150 +#define EXTCON_PROP_DISP_CNT (EXTCON_PROP_DISP_MAX - EXTCON_PROP_DISP_MIN + 1) + +/* + * Define the type of property's value. + * + * Define the property's value as union type. Because each property + * would need the different data type to store it. + */ +union extcon_property_value { + int intval; /* type : integer (intval) */ +}; + struct extcon_cable; /** @@ -166,6 +223,17 @@ 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); +/* + * get/set_property access the property value of each external connector. + * They are used to access the property of each cable based on the property id. + */ +extern int extcon_get_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value *prop_val); +extern int extcon_set_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val); + /* * Following APIs are to monitor every action of a notifier. * Registrar gets notified for every external port of a connection device. @@ -239,6 +307,19 @@ static inline int extcon_set_cable_state_(struct extcon_dev *edev, return 0; } +static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value *prop_val) +{ + return 0; +} +static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val) +{ + return 0; +} + static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { return NULL; From ceaa98f442cf09dc73946c6402489344367905ae Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Mon, 25 Jul 2016 21:15:19 +0900 Subject: [PATCH 265/343] extcon: Add the support for the capability of each property This patch adds the support of the property capability setting. This function decides the supported properties of each external connector on extcon provider driver. Ths list of new extcon APIs to get/set the capability of property as following: - int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop); - int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop); Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 140 ++++++++++++++++++++++++++++++++++++++++ include/linux/extcon.h | 22 +++++++ 2 files changed, 162 insertions(+) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 37fa4b51c5a1..599fc377a965 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -201,6 +201,11 @@ struct extcon_cable { union extcon_property_value chg_propval[EXTCON_PROP_CHG_CNT]; union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; + + unsigned long usb_bits[BITS_TO_LONGS(EXTCON_PROP_USB_CNT)]; + unsigned long chg_bits[BITS_TO_LONGS(EXTCON_PROP_CHG_CNT)]; + unsigned long jack_bits[BITS_TO_LONGS(EXTCON_PROP_JACK_CNT)]; + unsigned long disp_bits[BITS_TO_LONGS(EXTCON_PROP_DISP_CNT)]; }; static struct class *extcon_class; @@ -297,6 +302,39 @@ static bool is_extcon_property_supported(unsigned int id, unsigned int prop) return !!(extcon_info[id].type & type); } +static int is_extcon_property_capability(struct extcon_dev *edev, + unsigned int id, int index,unsigned int prop) +{ + struct extcon_cable *cable; + int type, ret; + + /* Check whether the property is supported or not. */ + type = get_extcon_type(prop); + if (type < 0) + return type; + + cable = &edev->cables[index]; + + switch (type) { + case EXTCON_TYPE_USB: + ret = test_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits); + break; + case EXTCON_TYPE_CHG: + ret = test_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits); + break; + case EXTCON_TYPE_JACK: + ret = test_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits); + break; + case EXTCON_TYPE_DISP: + ret = test_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits); + break; + default: + ret = -EINVAL; + } + + return ret; +} + static void init_property(struct extcon_dev *edev, unsigned int id, int index) { unsigned int type = extcon_info[id].type; @@ -554,6 +592,12 @@ int extcon_get_property(struct extcon_dev *edev, unsigned int id, spin_lock_irqsave(&edev->lock, flags); + /* Check whether the property is available or not. */ + if (!is_extcon_property_capability(edev, id, index, prop)) { + spin_unlock_irqrestore(&edev->lock, flags); + return -EPERM; + } + /* * Check whether the external connector is attached. * If external connector is detached, the user can not @@ -626,6 +670,12 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id, spin_lock_irqsave(&edev->lock, flags); + /* Check whether the property is available or not. */ + if (!is_extcon_property_capability(edev, id, index, prop)) { + spin_unlock_irqrestore(&edev->lock, flags); + return -EPERM; + } + cable = &edev->cables[index]; /* Set the property value according to extcon type */ @@ -653,6 +703,96 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id, } EXPORT_SYMBOL_GPL(extcon_set_property); +/** + * extcon_get_property_capability() - Get the capability of property + * of an external connector. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @prop: the property id among enum extcon_property. + * + * Returns 1 if the property is available or 0 if not available. + */ +int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, + unsigned int prop) +{ + int index; + + if (!edev) + return -EINVAL; + + /* Check whether the property is supported or not */ + if (!is_extcon_property_supported(id, prop)) + return -EINVAL; + + /* Find the cable index of external connector by using id */ + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + return is_extcon_property_capability(edev, id, index, prop); +} +EXPORT_SYMBOL_GPL(extcon_get_property_capability); + +/** + * extcon_set_property_capability() - Set the capability of a property + * of an external connector. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @prop: the property id among enum extcon_property. + * + * This function set the capability of a property for an external connector + * to mark the bit in capability bitmap which mean the available state of + * a property. + * + * Returns 0 if success or error number if fail + */ +int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, + unsigned int prop) +{ + struct extcon_cable *cable; + int index, type, ret = 0; + + if (!edev) + return -EINVAL; + + /* Check whether the property is supported or not. */ + if (!is_extcon_property_supported(id, prop)) + return -EINVAL; + + /* Find the cable index of external connector by using id. */ + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + type = get_extcon_type(prop); + if (type < 0) + return type; + + cable = &edev->cables[index]; + + switch (type) { + case EXTCON_TYPE_USB: + __set_bit(prop - EXTCON_PROP_USB_MIN, cable->usb_bits); + break; + case EXTCON_TYPE_CHG: + __set_bit(prop - EXTCON_PROP_CHG_MIN, cable->chg_bits); + break; + case EXTCON_TYPE_JACK: + __set_bit(prop - EXTCON_PROP_JACK_MIN, cable->jack_bits); + break; + case EXTCON_TYPE_DISP: + __set_bit(prop - EXTCON_PROP_DISP_MIN, cable->disp_bits); + break; + default: + ret = -EINVAL; + } + + return ret; +} +EXPORT_SYMBOL_GPL(extcon_set_property_capability); + /** * extcon_get_extcon_dev() - Get the extcon device instance from the name * @extcon_name: The extcon name provided with extcon_dev_register() diff --git a/include/linux/extcon.h b/include/linux/extcon.h index f9d4a44e86d3..f08469089f74 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -234,6 +234,16 @@ extern int extcon_set_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val); +/* + * get/set_property_capability set the capability of the property for each + * external connector. They are used to set the capability of the property + * of each external connector based on the id and property. + */ +extern int extcon_get_property_capability(struct extcon_dev *edev, + unsigned int id, unsigned int prop); +extern int extcon_set_property_capability(struct extcon_dev *edev, + unsigned int id, unsigned int prop); + /* * Following APIs are to monitor every action of a notifier. * Registrar gets notified for every external port of a connection device. @@ -320,6 +330,18 @@ static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, return 0; } +static inline int extcon_get_property_capability(struct extcon_dev *edev, + unsigned int id, unsigned int prop) +{ + return 0; +} + +static inline int extcon_set_property_capability(struct extcon_dev *edev, + unsigned int id, unsigned int prop) +{ + return 0; +} + static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { return NULL; From 35872fdcbf5c109dab03fb36ddec35b7bad7d762 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 22 Jul 2016 13:03:17 +0900 Subject: [PATCH 266/343] extcon: Rename the extcon_set/get_state() to maintain the function naming pattern This patch just renames the existing extcon_get/set_cable_state_() as following because of maintaining the function naming pattern like as extcon APIs for property. - extcon_set_cable_state_() -> extcon_set_state() - extcon_get_cable_state_() -> extcon_get_state() But, this patch remains the old extcon_set/get_cable_state_() functions to prevent the build break. After altering new APIs, remove the old APIs. Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 28 +++++++++++++--------------- include/linux/extcon.h | 25 ++++++++++++++++++------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 599fc377a965..d66adfd21159 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -398,8 +398,7 @@ static ssize_t cable_state_show(struct device *dev, int i = cable->cable_index; return sprintf(buf, "%d\n", - extcon_get_cable_state_(cable->edev, - cable->edev->supported_cable[i])); + extcon_get_state(cable->edev, cable->edev->supported_cable[i])); } /** @@ -495,13 +494,14 @@ static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) } /** - * extcon_get_cable_state_() - Get the status of a specific cable. + * extcon_get_state() - Get the state of a external connector. * @edev: the extcon device that has the cable. * @id: the unique id of each external connector in extcon enumeration. */ -int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) +int extcon_get_state(struct extcon_dev *edev, const unsigned int id) { - int index; + int index, state; + unsigned long flags; if (!edev) return -EINVAL; @@ -510,22 +510,23 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) if (index < 0) return index; - if (edev->max_supported && edev->max_supported <= index) - return -EINVAL; + spin_lock_irqsave(&edev->lock, flags); + state = is_extcon_attached(edev, index); + spin_unlock_irqrestore(&edev->lock, flags); - return is_extcon_attached(edev, index); + return state; } -EXPORT_SYMBOL_GPL(extcon_get_cable_state_); +EXPORT_SYMBOL_GPL(extcon_get_state); /** - * extcon_set_cable_state_() - Set the status of a specific cable. + * extcon_set_state() - Set the state of a external connector. * @edev: the extcon device that has the cable. * @id: the unique id of each external connector * in extcon enumeration. * @state: the new cable status. The default semantics is * true: attached / false: detached. */ -int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, +int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool cable_state) { u32 state; @@ -538,9 +539,6 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, if (index < 0) return index; - if (edev->max_supported && edev->max_supported <= index) - return -EINVAL; - /* * Initialize the value of extcon property before setting * the detached state for an external connector. @@ -551,7 +549,7 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, state = cable_state ? (1 << index) : 0; return extcon_update_state(edev, 1 << index, state); } -EXPORT_SYMBOL_GPL(extcon_set_cable_state_); +EXPORT_SYMBOL_GPL(extcon_set_state); /** * extcon_get_property() - Get the property value of a specific cable. diff --git a/include/linux/extcon.h b/include/linux/extcon.h index f08469089f74..4fa37385c97a 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -216,11 +216,11 @@ extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); /* - * get/set_cable_state access each bit of the 32b encoded state value. + * get/set_state access each bit of the 32b encoded state value. * 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, +extern int extcon_get_state(struct extcon_dev *edev, unsigned int id); +extern int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool cable_state); /* @@ -305,14 +305,14 @@ static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, static inline void devm_extcon_dev_free(struct extcon_dev *edev) { } -static inline int extcon_get_cable_state_(struct extcon_dev *edev, - unsigned int id) + +static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id) { return 0; } -static inline int extcon_set_cable_state_(struct extcon_dev *edev, - unsigned int id, bool cable_state) +static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id, + bool cable_state) { return 0; } @@ -402,4 +402,15 @@ static inline int extcon_unregister_interest(struct extcon_specific_cable_nb { return -EINVAL; } + +static inline int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id) +{ + return extcon_get_state(edev, id); +} + +static inline int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, + bool cable_state) +{ + return extcon_set_state(edev, id, cable_state); +} #endif /* __LINUX_EXTCON_H__ */ From a580982f0836e079171f65f22d82768a12f85570 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 22 Jul 2016 13:16:34 +0900 Subject: [PATCH 267/343] extcon: Add the synchronization extcon APIs to support the notification This patch adds the synchronization extcon APIs to support the notifications for both state and property. When extcon_*_sync() functions is called, the extcon informs the information from extcon provider to extcon client. The extcon driver may need to change the both state and multiple properties at the same time. After setting the data of a external connector, the extcon send the notification to client driver with the extcon_*_sync(). The list of new extcon APIs as following: - extcon_sync() : Send the notification for each external connector to synchronize the information between extcon provider driver and extcon client driver. - extcon_set_state_sync() : Set the state of external connector with noti. - extcon_set_property_sync() : Set the property of external connector with noti. For example, case 1, change the state of external connector and synchronized the data. extcon_set_state_sync(edev, EXTCON_USB, 1); case 2, change both the state and property of external connector and synchronized the data. extcon_set_state(edev, EXTCON_USB, 1); extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS 1); extcon_sync(edev, EXTCON_USB); case 3, change the property of external connector and synchronized the data. extcon_set_property(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS, 0); extcon_sync(edev, EXTCON_USB); case 4, change the property of external connector and synchronized the data. extcon_set_property_sync(edev, EXTCON_USB, EXTCON_PROP_USB_VBUS, 0); Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 216 +++++++++++++++++++++++++--------------- include/linux/extcon.h | 30 +++++- 2 files changed, 167 insertions(+), 79 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index d66adfd21159..8fde4befaa51 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -279,14 +279,11 @@ static bool is_extcon_attached(struct extcon_dev *edev, unsigned int index) return !!(edev->state & BIT(index)); } -static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached) +static bool is_extcon_changed(struct extcon_dev *edev, int index, + bool new_state) { - if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) { - *attached = ((new >> idx) & 0x1) ? true : false; - return true; - } - - return false; + int state = !!(edev->state & BIT(index)); + return (state != new_state); } static bool is_extcon_property_supported(unsigned int id, unsigned int prop) @@ -402,21 +399,13 @@ static ssize_t cable_state_show(struct device *dev, } /** - * extcon_update_state() - Update the cable attach states of the extcon device - * only for the masked bits. - * @edev: the extcon device - * @mask: the bit mask to designate updated bits. - * @state: new cable attach status for @edev + * extcon_sync() - Synchronize the states for both the attached/detached + * @edev: the extcon device that has the cable. * - * Changing the state sends uevent with environment variable containing - * the name of extcon device (envp[0]) and the state output (envp[1]). - * Tizen uses this format for extcon device to get events from ports. - * Android uses this format as well. - * - * Note that the notifier provides which bits are changed in the state - * variable with the val parameter (second) to the callback. + * This function send a notification to synchronize the all states of a + * specific external connector */ -static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) +int extcon_sync(struct extcon_dev *edev, unsigned int id) { char name_buf[120]; char state_buf[120]; @@ -425,73 +414,58 @@ static int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) int env_offset = 0; int length; int index; + int state; unsigned long flags; - bool attached; if (!edev) return -EINVAL; + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + spin_lock_irqsave(&edev->lock, flags); - if (edev->state != ((edev->state & ~mask) | (state & mask))) { - u32 old_state; + state = !!(edev->state & BIT(index)); + raw_notifier_call_chain(&edev->nh[index], state, edev); - if (check_mutually_exclusive(edev, (edev->state & ~mask) | - (state & mask))) { - spin_unlock_irqrestore(&edev->lock, flags); - return -EPERM; - } - - old_state = edev->state; - edev->state &= ~mask; - edev->state |= state & mask; - - for (index = 0; index < edev->max_supported; index++) { - if (is_extcon_changed(old_state, edev->state, index, - &attached)) - raw_notifier_call_chain(&edev->nh[index], - attached, edev); - } - - /* This could be in interrupt handler */ - prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); - if (prop_buf) { - length = name_show(&edev->dev, NULL, prop_buf); - if (length > 0) { - if (prop_buf[length - 1] == '\n') - prop_buf[length - 1] = 0; - snprintf(name_buf, sizeof(name_buf), - "NAME=%s", prop_buf); - envp[env_offset++] = name_buf; - } - length = state_show(&edev->dev, NULL, prop_buf); - if (length > 0) { - if (prop_buf[length - 1] == '\n') - prop_buf[length - 1] = 0; - snprintf(state_buf, sizeof(state_buf), - "STATE=%s", prop_buf); - envp[env_offset++] = state_buf; - } - envp[env_offset] = NULL; - /* Unlock early before uevent */ - spin_unlock_irqrestore(&edev->lock, flags); - - kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp); - free_page((unsigned long)prop_buf); - } else { - /* Unlock early before uevent */ - spin_unlock_irqrestore(&edev->lock, flags); - - dev_err(&edev->dev, "out of memory in extcon_set_state\n"); - kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE); - } - } else { - /* No changes */ + /* This could be in interrupt handler */ + prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); + if (!prop_buf) { + /* Unlock early before uevent */ spin_unlock_irqrestore(&edev->lock, flags); + + dev_err(&edev->dev, "out of memory in extcon_set_state\n"); + kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE); + + return 0; } + length = name_show(&edev->dev, NULL, prop_buf); + if (length > 0) { + if (prop_buf[length - 1] == '\n') + prop_buf[length - 1] = 0; + snprintf(name_buf, sizeof(name_buf), "NAME=%s", prop_buf); + envp[env_offset++] = name_buf; + } + + length = state_show(&edev->dev, NULL, prop_buf); + if (length > 0) { + if (prop_buf[length - 1] == '\n') + prop_buf[length - 1] = 0; + snprintf(state_buf, sizeof(state_buf), "STATE=%s", prop_buf); + envp[env_offset++] = state_buf; + } + envp[env_offset] = NULL; + + /* Unlock early before uevent */ + spin_unlock_irqrestore(&edev->lock, flags); + kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp); + free_page((unsigned long)prop_buf); + return 0; } +EXPORT_SYMBOL_GPL(extcon_sync); /** * extcon_get_state() - Get the state of a external connector. @@ -520,17 +494,22 @@ EXPORT_SYMBOL_GPL(extcon_get_state); /** * extcon_set_state() - Set the state of a external connector. + * without a notification. * @edev: the extcon device that has the cable. * @id: the unique id of each external connector * in extcon enumeration. * @state: the new cable status. The default semantics is * true: attached / false: detached. + * + * This function only set the state of a external connector without + * a notification. To synchronize the data of a external connector, + * use extcon_set_state_sync() and extcon_sync(). */ int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool cable_state) { - u32 state; - int index; + unsigned long flags; + int index, ret = 0; if (!edev) return -EINVAL; @@ -539,6 +518,18 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id, if (index < 0) return index; + spin_lock_irqsave(&edev->lock, flags); + + /* Check whether the external connector's state is changed. */ + if (!is_extcon_changed(edev, index, cable_state)) + goto out; + + if (check_mutually_exclusive(edev, + (edev->state & ~BIT(index)) | (cable_state & BIT(index)))) { + ret = -EPERM; + goto out; + } + /* * Initialize the value of extcon property before setting * the detached state for an external connector. @@ -546,11 +537,55 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id, if (!cable_state) init_property(edev, id, index); - state = cable_state ? (1 << index) : 0; - return extcon_update_state(edev, 1 << index, state); + /* Update the state for a external connector. */ + if (cable_state) + edev->state |= BIT(index); + else + edev->state &= ~(BIT(index)); +out: + spin_unlock_irqrestore(&edev->lock, flags); + + return ret; } EXPORT_SYMBOL_GPL(extcon_set_state); +/** + * extcon_set_state_sync() - Set the state of a external connector + * with a notification. + * @edev: the extcon device that has the cable. + * @id: the unique id of each external connector + * in extcon enumeration. + * @state: the new cable status. The default semantics is + * true: attached / false: detached. + * + * This function set the state of external connector and synchronize the data + * by usning a notification. + */ +int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, + bool cable_state) +{ + int ret, index; + unsigned long flags; + + index = find_cable_index_by_id(edev, id); + if (index < 0) + return index; + + /* Check whether the external connector's state is changed. */ + spin_lock_irqsave(&edev->lock, flags); + ret = is_extcon_changed(edev, index, cable_state); + spin_unlock_irqrestore(&edev->lock, flags); + if (!ret) + return 0; + + ret = extcon_set_state(edev, id, cable_state); + if (ret < 0) + return ret; + + return extcon_sync(edev, id); +} +EXPORT_SYMBOL_GPL(extcon_set_state_sync); + /** * extcon_get_property() - Get the property value of a specific cable. * @edev: the extcon device that has the cable. @@ -701,6 +736,31 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id, } EXPORT_SYMBOL_GPL(extcon_set_property); +/** + * extcon_set_property_sync() - Set the property value of a specific cable + with a notification. + * @prop_val: the pointer including the new value of property. + * + * When setting the property value of external connector, the external connector + * should be attached. The each property should be included in the list of + * supported properties according to the type of external connectors. + * + * Returns 0 if success or error number if fail + */ +int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val) +{ + int ret; + + ret = extcon_set_property(edev, id, prop, prop_val); + if (ret < 0) + return ret; + + return extcon_sync(edev, id); +} +EXPORT_SYMBOL_GPL(extcon_set_property_sync); + /** * extcon_get_property_capability() - Get the capability of property * of an external connector. diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 4fa37385c97a..162c46a42bac 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -222,6 +222,13 @@ extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); extern int extcon_get_state(struct extcon_dev *edev, unsigned int id); extern int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool cable_state); +extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, + bool cable_state); + +/* + * Synchronize the state and property data for a specific external connector. + */ +extern int extcon_sync(struct extcon_dev *edev, unsigned int id); /* * get/set_property access the property value of each external connector. @@ -233,6 +240,9 @@ extern int extcon_get_property(struct extcon_dev *edev, unsigned int id, extern int extcon_set_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val); +extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, + unsigned int prop, + union extcon_property_value prop_val); /* * get/set_property_capability set the capability of the property for each @@ -317,6 +327,17 @@ static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id, return 0; } +static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, + bool cable_state) +{ + return 0; +} + +static inline int extcon_sync(struct extcon_dev *edev, unsigned int id) +{ + return 0; +} + static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value *prop_val) @@ -330,6 +351,13 @@ static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, return 0; } +static inline int extcon_set_property_sync(struct extcon_dev *edev, + unsigned int id, unsigned int prop, + union extcon_property_value prop_val) +{ + return 0; +} + static inline int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop) { @@ -411,6 +439,6 @@ static inline int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int static inline int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, bool cable_state) { - return extcon_set_state(edev, id, cable_state); + return extcon_set_state_sync(edev, id, cable_state); } #endif /* __LINUX_EXTCON_H__ */ From 2f25140601115cd1b278e208099c9ebc627b9481 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Fri, 22 Jul 2016 01:13:02 +0900 Subject: [PATCH 268/343] extcon: Add EXTCON_DISP_DP and the property for USB Type-C Add EXTCON_DISP_DP for the Display external connector. For Type-C connector the DisplayPort can work as an Alternate Mode(VESA DisplayPort Alt Mode on USB Type-C Standard). The Type-C support both normal and flipped orientation, so add a property to extcon. Signed-off-by: Chris Zhong Signed-off-by: Chanwoo Choi Tested-by: Chris Zhong Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- drivers/extcon/extcon.c | 5 +++++ include/linux/extcon.h | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 8fde4befaa51..a0a1eea18727 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -157,6 +157,11 @@ struct __extcon_info { .id = EXTCON_DISP_VGA, .name = "VGA", }, + [EXTCON_DISP_DP] = { + .type = EXTCON_TYPE_DISP | EXTCON_TYPE_USB, + .id = EXTCON_DISP_DP, + .name = "DP", + }, /* Miscellaneous external connector */ [EXTCON_DOCK] = { diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 162c46a42bac..ad7a1606a7f3 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -69,6 +69,7 @@ #define EXTCON_DISP_MHL 41 /* Mobile High-Definition Link */ #define EXTCON_DISP_DVI 42 /* Digital Visual Interface */ #define EXTCON_DISP_VGA 43 /* Video Graphics Array */ +#define EXTCON_DISP_DP 44 /* Display Port */ /* Miscellaneous external connector */ #define EXTCON_DOCK 60 @@ -102,11 +103,16 @@ * @type: integer (intval) * @value: 0 (low) or 1 (high) * @default: 0 (low) + * - EXTCON_PROP_USB_TYPEC_POLARITY + * @type: integer (intval) + * @value: 0 (normal) or 1 (flip) + * @default: 0 (normal) */ #define EXTCON_PROP_USB_VBUS 0 +#define EXTCON_PROP_USB_TYPEC_POLARITY 1 #define EXTCON_PROP_USB_MIN 0 -#define EXTCON_PROP_USB_MAX 0 +#define EXTCON_PROP_USB_MAX 1 #define EXTCON_PROP_USB_CNT (EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1) /* Properties of EXTCON_TYPE_CHG. */ From 736d25b115e8f7b6728f39a993d784aac1c6118b Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 5 Aug 2016 17:49:23 +0900 Subject: [PATCH 269/343] extcon: Add new EXTCON_DISP_HMD for Head-mounted Display device This patch adds the new EXTCON_DISP_HMD id for Head-mounted Display[1] device. The HMD device is usually for USB connector type So, the HMD connector has the two extcon types of both EXTCON_TYPE_DISP and EXTCON_TYPE_USB. [1] https://en.wikipedia.org/wiki/Head-mounted_display Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 5 +++++ include/linux/extcon.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index a0a1eea18727..10ba876ea77a 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -162,6 +162,11 @@ struct __extcon_info { .id = EXTCON_DISP_DP, .name = "DP", }, + [EXTCON_DISP_HMD] = { + .type = EXTCON_TYPE_DISP | EXTCON_TYPE_USB, + .id = EXTCON_DISP_HMD, + .name = "HMD", + }, /* Miscellaneous external connector */ [EXTCON_DOCK] = { diff --git a/include/linux/extcon.h b/include/linux/extcon.h index ad7a1606a7f3..e79b644f41a7 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -70,6 +70,7 @@ #define EXTCON_DISP_DVI 42 /* Digital Visual Interface */ #define EXTCON_DISP_VGA 43 /* Video Graphics Array */ #define EXTCON_DISP_DP 44 /* Display Port */ +#define EXTCON_DISP_HMD 45 /* Head-Mounted Display */ /* Miscellaneous external connector */ #define EXTCON_DOCK 60 From af9b9285f2e9b5a625284f92fa508141b26ec381 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 5 Aug 2016 18:15:46 +0900 Subject: [PATCH 270/343] extcon: Add new EXTCON_CHG_WPT for Wireless Power Transfer device This patchs add the new EXTCON_CHG_WPT for Wireless Power Transfer[1]. The Wireless Power Transfer is the transmission of electronical energy from a power source. The EXTCON_CHG_WPT has the EXTCON_TYPE_CHG. [1] https://en.wikipedia.org/wiki/Wireless_power_transfer Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 5 +++++ include/linux/extcon.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 10ba876ea77a..78298460d168 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -93,6 +93,11 @@ struct __extcon_info { .id = EXTCON_CHG_USB_SLOW, .name = "SLOW-CHARGER", }, + [EXTCON_CHG_WPT] = { + .type = EXTCON_TYPE_CHG, + .id = EXTCON_CHG_WPT, + .name = "WPT", + }, /* Jack external connector */ [EXTCON_JACK_MICROPHONE] = { diff --git a/include/linux/extcon.h b/include/linux/extcon.h index e79b644f41a7..461abee969b7 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -53,6 +53,7 @@ #define EXTCON_CHG_USB_ACA 8 /* Accessory Charger Adapter */ #define EXTCON_CHG_USB_FAST 9 #define EXTCON_CHG_USB_SLOW 10 +#define EXTCON_CHG_WPT 11 /* Wireless Power Transfer */ /* Jack external connector */ #define EXTCON_JACK_MICROPHONE 20 From 8df0cfe6c6c4a9355989baa8de9f166b2bc51f76 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 15 Aug 2016 06:15:35 -0700 Subject: [PATCH 271/343] extcon: Introduce EXTCON_PROP_USB_SS property for SuperSpeed mode EXTCON_PROP_USB_SS (SuperSpeed)[1] is necessary to distinguish between USB/USB2 and USB3 connections on USB Type-C cables. [1] https://en.wikipedia.org/wiki/USB#Overview Cc: Chris Zhong Signed-off-by: Guenter Roeck Signed-off-by: Chanwoo Choi --- include/linux/extcon.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 461abee969b7..b34d1ae9011f 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -109,12 +109,18 @@ * @type: integer (intval) * @value: 0 (normal) or 1 (flip) * @default: 0 (normal) + * - EXTCON_PROP_USB_SS (SuperSpeed) + * @type: integer (intval) + * @value: 0 (USB/USB2) or 1 (USB3) + * @default: 0 (USB/USB2) + * */ #define EXTCON_PROP_USB_VBUS 0 #define EXTCON_PROP_USB_TYPEC_POLARITY 1 +#define EXTCON_PROP_USB_SS 2 #define EXTCON_PROP_USB_MIN 0 -#define EXTCON_PROP_USB_MAX 1 +#define EXTCON_PROP_USB_MAX 2 #define EXTCON_PROP_USB_CNT (EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1) /* Properties of EXTCON_TYPE_CHG. */ From 4033d95218489375f598e89e99fcc6e4b4321732 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 5 Sep 2016 14:45:46 -0500 Subject: [PATCH 272/343] phy: da8xx-usb: Fix syscon device name The syscon device in board config/device tree has been renamed. Signed-off-by: David Lechner Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-da8xx-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/phy-da8xx-usb.c b/drivers/phy/phy-da8xx-usb.c index b2e59b6170ac..32ae78c8ca17 100644 --- a/drivers/phy/phy-da8xx-usb.c +++ b/drivers/phy/phy-da8xx-usb.c @@ -154,7 +154,7 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) d_phy->regmap = syscon_regmap_lookup_by_compatible( "ti,da830-cfgchip"); else - d_phy->regmap = syscon_regmap_lookup_by_pdevname("syscon.0"); + d_phy->regmap = syscon_regmap_lookup_by_pdevname("syscon"); if (IS_ERR(d_phy->regmap)) { dev_err(dev, "Failed to get syscon\n"); return PTR_ERR(d_phy->regmap); From e96be45cb84e29e58f35ed460a859b61e8bf28c5 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Tue, 23 Aug 2016 22:17:02 -0700 Subject: [PATCH 273/343] phy: Add USB Type-C PHY driver for rk3399 Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB Type-C PHY is designed to support the USB3 and DP applications. The USB3 operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2 data rates. This driver create 2 PHY devices separately for USB3 and DisplyPort, and registers them under the child node. Signed-off-by: Chris Zhong Signed-off-by: Kever Yang Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 9 + drivers/phy/Makefile | 1 + drivers/phy/phy-rockchip-typec.c | 1013 ++++++++++++++++++++++++++++++ 3 files changed, 1023 insertions(+) create mode 100644 drivers/phy/phy-rockchip-typec.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 8cf6c3d0f71a..1f3e1fbef529 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -397,6 +397,15 @@ config PHY_ROCKCHIP_PCIE help Enable this to support the Rockchip PCIe PHY. +config PHY_ROCKCHIP_TYPEC + tristate "Rockchip TYPEC PHY Driver" + depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) + select EXTCON + select GENERIC_PHY + select RESET_CONTROLLER + help + Enable this to support the Rockchip USB TYPEC PHY. + config PHY_ST_SPEAR1310_MIPHY tristate "ST SPEAR1310-MIPHY driver" select GENERIC_PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index ce0e526059dd..a534cf5be07d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o +obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o diff --git a/drivers/phy/phy-rockchip-typec.c b/drivers/phy/phy-rockchip-typec.c new file mode 100644 index 000000000000..fb58a2775a49 --- /dev/null +++ b/drivers/phy/phy-rockchip-typec.c @@ -0,0 +1,1013 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Chris Zhong + * Kever Yang + * + * 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. + * + * The ROCKCHIP Type-C PHY has two PLL clocks. The first PLL clock + * is used for USB3, the second PLL clock is used for DP. This Type-C PHY has + * 3 working modes: USB3 only mode, DP only mode, and USB3+DP mode. + * At USB3 only mode, both PLL clocks need to be initialized, this allows the + * PHY to switch mode between USB3 and USB3+DP, without disconnecting the USB + * device. + * In The DP only mode, only the DP PLL needs to be powered on, and the 4 lanes + * are all used for DP. + * + * This driver gets extcon cable state and property, then decides which mode to + * select: + * + * 1. USB3 only mode: + * EXTCON_USB or EXTCON_USB_HOST state is true, and + * EXTCON_PROP_USB_SS property is true. + * EXTCON_DISP_DP state is false. + * + * 2. DP only mode: + * EXTCON_DISP_DP state is true, and + * EXTCON_PROP_USB_SS property is false. + * If EXTCON_USB_HOST state is true, it is DP + USB2 mode, since the USB2 phy + * is a separate phy, so this case is still DP only mode. + * + * 3. USB3+DP mode: + * EXTCON_USB_HOST and EXTCON_DISP_DP are both true, and + * EXTCON_PROP_USB_SS property is true. + * + * This Type-C PHY driver supports normal and flip orientation. The orientation + * is reported by the EXTCON_PROP_USB_TYPEC_POLARITY property: true is flip + * orientation, false is normal orientation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CMN_SSM_BANDGAP (0x21 << 2) +#define CMN_SSM_BIAS (0x22 << 2) +#define CMN_PLLSM0_PLLEN (0x29 << 2) +#define CMN_PLLSM0_PLLPRE (0x2a << 2) +#define CMN_PLLSM0_PLLVREF (0x2b << 2) +#define CMN_PLLSM0_PLLLOCK (0x2c << 2) +#define CMN_PLLSM1_PLLEN (0x31 << 2) +#define CMN_PLLSM1_PLLPRE (0x32 << 2) +#define CMN_PLLSM1_PLLVREF (0x33 << 2) +#define CMN_PLLSM1_PLLLOCK (0x34 << 2) +#define CMN_PLLSM1_USER_DEF_CTRL (0x37 << 2) +#define CMN_ICAL_OVRD (0xc1 << 2) +#define CMN_PLL0_VCOCAL_OVRD (0x83 << 2) +#define CMN_PLL0_VCOCAL_INIT (0x84 << 2) +#define CMN_PLL0_VCOCAL_ITER (0x85 << 2) +#define CMN_PLL0_LOCK_REFCNT_START (0x90 << 2) +#define CMN_PLL0_LOCK_PLLCNT_START (0x92 << 2) +#define CMN_PLL0_LOCK_PLLCNT_THR (0x93 << 2) +#define CMN_PLL0_INTDIV (0x94 << 2) +#define CMN_PLL0_FRACDIV (0x95 << 2) +#define CMN_PLL0_HIGH_THR (0x96 << 2) +#define CMN_PLL0_DSM_DIAG (0x97 << 2) +#define CMN_PLL0_SS_CTRL1 (0x98 << 2) +#define CMN_PLL0_SS_CTRL2 (0x99 << 2) +#define CMN_PLL1_VCOCAL_START (0xa1 << 2) +#define CMN_PLL1_VCOCAL_OVRD (0xa3 << 2) +#define CMN_PLL1_VCOCAL_INIT (0xa4 << 2) +#define CMN_PLL1_VCOCAL_ITER (0xa5 << 2) +#define CMN_PLL1_LOCK_REFCNT_START (0xb0 << 2) +#define CMN_PLL1_LOCK_PLLCNT_START (0xb2 << 2) +#define CMN_PLL1_LOCK_PLLCNT_THR (0xb3 << 2) +#define CMN_PLL1_INTDIV (0xb4 << 2) +#define CMN_PLL1_FRACDIV (0xb5 << 2) +#define CMN_PLL1_HIGH_THR (0xb6 << 2) +#define CMN_PLL1_DSM_DIAG (0xb7 << 2) +#define CMN_PLL1_SS_CTRL1 (0xb8 << 2) +#define CMN_PLL1_SS_CTRL2 (0xb9 << 2) +#define CMN_RXCAL_OVRD (0xd1 << 2) +#define CMN_TXPUCAL_CTRL (0xe0 << 2) +#define CMN_TXPUCAL_OVRD (0xe1 << 2) +#define CMN_TXPDCAL_OVRD (0xf1 << 2) +#define CMN_DIAG_PLL0_FBH_OVRD (0x1c0 << 2) +#define CMN_DIAG_PLL0_FBL_OVRD (0x1c1 << 2) +#define CMN_DIAG_PLL0_OVRD (0x1c2 << 2) +#define CMN_DIAG_PLL0_V2I_TUNE (0x1c5 << 2) +#define CMN_DIAG_PLL0_CP_TUNE (0x1c6 << 2) +#define CMN_DIAG_PLL0_LF_PROG (0x1c7 << 2) +#define CMN_DIAG_PLL1_FBH_OVRD (0x1d0 << 2) +#define CMN_DIAG_PLL1_FBL_OVRD (0x1d1 << 2) +#define CMN_DIAG_PLL1_OVRD (0x1d2 << 2) +#define CMN_DIAG_PLL1_V2I_TUNE (0x1d5 << 2) +#define CMN_DIAG_PLL1_CP_TUNE (0x1d6 << 2) +#define CMN_DIAG_PLL1_LF_PROG (0x1d7 << 2) +#define CMN_DIAG_PLL1_PTATIS_TUNE1 (0x1d8 << 2) +#define CMN_DIAG_PLL1_PTATIS_TUNE2 (0x1d9 << 2) +#define CMN_DIAG_PLL1_INCLK_CTRL (0x1da << 2) +#define CMN_DIAG_HSCLK_SEL (0x1e0 << 2) + +#define XCVR_PSM_RCTRL(n) ((0x4001 | ((n) << 9)) << 2) +#define XCVR_PSM_CAL_TMR(n) ((0x4002 | ((n) << 9)) << 2) +#define XCVR_PSM_A0IN_TMR(n) ((0x4003 | ((n) << 9)) << 2) +#define TX_TXCC_CAL_SCLR_MULT(n) ((0x4047 | ((n) << 9)) << 2) +#define TX_TXCC_CPOST_MULT_00(n) ((0x404c | ((n) << 9)) << 2) +#define TX_TXCC_CPOST_MULT_01(n) ((0x404d | ((n) << 9)) << 2) +#define TX_TXCC_CPOST_MULT_10(n) ((0x404e | ((n) << 9)) << 2) +#define TX_TXCC_CPOST_MULT_11(n) ((0x404f | ((n) << 9)) << 2) +#define TX_TXCC_MGNFS_MULT_000(n) ((0x4050 | ((n) << 9)) << 2) +#define TX_TXCC_MGNFS_MULT_001(n) ((0x4051 | ((n) << 9)) << 2) +#define TX_TXCC_MGNFS_MULT_010(n) ((0x4052 | ((n) << 9)) << 2) +#define TX_TXCC_MGNFS_MULT_011(n) ((0x4053 | ((n) << 9)) << 2) +#define TX_TXCC_MGNFS_MULT_100(n) ((0x4054 | ((n) << 9)) << 2) +#define TX_TXCC_MGNFS_MULT_101(n) ((0x4055 | ((n) << 9)) << 2) +#define TX_TXCC_MGNFS_MULT_110(n) ((0x4056 | ((n) << 9)) << 2) +#define TX_TXCC_MGNFS_MULT_111(n) ((0x4057 | ((n) << 9)) << 2) +#define XCVR_DIAG_PLLDRC_CTRL(n) ((0x40e0 | ((n) << 9)) << 2) +#define XCVR_DIAG_BIDI_CTRL(n) ((0x40e8 | ((n) << 9)) << 2) +#define XCVR_DIAG_LANE_FCM_EN_MGN(n) ((0x40f2 | ((n) << 9)) << 2) +#define TX_PSC_A0(n) ((0x4100 | ((n) << 9)) << 2) +#define TX_PSC_A1(n) ((0x4101 | ((n) << 9)) << 2) +#define TX_PSC_A2(n) ((0x4102 | ((n) << 9)) << 2) +#define TX_PSC_A3(n) ((0x4103 | ((n) << 9)) << 2) +#define TX_RCVDET_CTRL(n) ((0x4120 | ((n) << 9)) << 2) +#define TX_RCVDET_EN_TMR(n) ((0x4122 | ((n) << 9)) << 2) +#define TX_RCVDET_ST_TMR(n) ((0x4123 | ((n) << 9)) << 2) +#define TX_DIAG_TX_DRV(n) ((0x41e1 | ((n) << 9)) << 2) +#define TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 << 2) +#define TX_ANA_CTRL_REG_1 (0x5020 << 2) +#define TX_ANA_CTRL_REG_2 (0x5021 << 2) +#define TXDA_COEFF_CALC_CTRL (0x5022 << 2) +#define TX_DIG_CTRL_REG_2 (0x5024 << 2) +#define TXDA_CYA_AUXDA_CYA (0x5025 << 2) +#define TX_ANA_CTRL_REG_3 (0x5026 << 2) +#define TX_ANA_CTRL_REG_4 (0x5027 << 2) +#define TX_ANA_CTRL_REG_5 (0x5029 << 2) + +#define RX_PSC_A0(n) ((0x8000 | ((n) << 9)) << 2) +#define RX_PSC_A1(n) ((0x8001 | ((n) << 9)) << 2) +#define RX_PSC_A2(n) ((0x8002 | ((n) << 9)) << 2) +#define RX_PSC_A3(n) ((0x8003 | ((n) << 9)) << 2) +#define RX_PSC_CAL(n) ((0x8006 | ((n) << 9)) << 2) +#define RX_PSC_RDY(n) ((0x8007 | ((n) << 9)) << 2) +#define RX_IQPI_ILL_CAL_OVRD (0x8023 << 2) +#define RX_EPI_ILL_CAL_OVRD (0x8033 << 2) +#define RX_SDCAL0_OVRD (0x8041 << 2) +#define RX_SDCAL1_OVRD (0x8049 << 2) +#define RX_SLC_INIT (0x806d << 2) +#define RX_SLC_RUN (0x806e << 2) +#define RX_CDRLF_CNFG2 (0x8081 << 2) +#define RX_SIGDET_HL_FILT_TMR(n) ((0x8090 | ((n) << 9)) << 2) +#define RX_SLC_IOP0_OVRD (0x8101 << 2) +#define RX_SLC_IOP1_OVRD (0x8105 << 2) +#define RX_SLC_QOP0_OVRD (0x8109 << 2) +#define RX_SLC_QOP1_OVRD (0x810d << 2) +#define RX_SLC_EOP0_OVRD (0x8111 << 2) +#define RX_SLC_EOP1_OVRD (0x8115 << 2) +#define RX_SLC_ION0_OVRD (0x8119 << 2) +#define RX_SLC_ION1_OVRD (0x811d << 2) +#define RX_SLC_QON0_OVRD (0x8121 << 2) +#define RX_SLC_QON1_OVRD (0x8125 << 2) +#define RX_SLC_EON0_OVRD (0x8129 << 2) +#define RX_SLC_EON1_OVRD (0x812d << 2) +#define RX_SLC_IEP0_OVRD (0x8131 << 2) +#define RX_SLC_IEP1_OVRD (0x8135 << 2) +#define RX_SLC_QEP0_OVRD (0x8139 << 2) +#define RX_SLC_QEP1_OVRD (0x813d << 2) +#define RX_SLC_EEP0_OVRD (0x8141 << 2) +#define RX_SLC_EEP1_OVRD (0x8145 << 2) +#define RX_SLC_IEN0_OVRD (0x8149 << 2) +#define RX_SLC_IEN1_OVRD (0x814d << 2) +#define RX_SLC_QEN0_OVRD (0x8151 << 2) +#define RX_SLC_QEN1_OVRD (0x8155 << 2) +#define RX_SLC_EEN0_OVRD (0x8159 << 2) +#define RX_SLC_EEN1_OVRD (0x815d << 2) +#define RX_REE_CTRL_DATA_MASK(n) ((0x81bb | ((n) << 9)) << 2) +#define RX_DIAG_SIGDET_TUNE(n) ((0x81dc | ((n) << 9)) << 2) +#define RX_DIAG_SC2C_DELAY (0x81e1 << 2) + +#define PMA_LANE_CFG (0xc000 << 2) +#define PIPE_CMN_CTRL1 (0xc001 << 2) +#define PIPE_CMN_CTRL2 (0xc002 << 2) +#define PIPE_COM_LOCK_CFG1 (0xc003 << 2) +#define PIPE_COM_LOCK_CFG2 (0xc004 << 2) +#define PIPE_RCV_DET_INH (0xc005 << 2) +#define DP_MODE_CTL (0xc008 << 2) +#define DP_CLK_CTL (0xc009 << 2) +#define STS (0xc00F << 2) +#define PHY_ISO_CMN_CTRL (0xc010 << 2) +#define PHY_DP_TX_CTL (0xc408 << 2) +#define PMA_CMN_CTRL1 (0xc800 << 2) +#define PHY_PMA_ISO_CMN_CTRL (0xc810 << 2) +#define PHY_ISOLATION_CTRL (0xc81f << 2) +#define PHY_PMA_ISO_XCVR_CTRL(n) ((0xcc11 | ((n) << 6)) << 2) +#define PHY_PMA_ISO_LINK_MODE(n) ((0xcc12 | ((n) << 6)) << 2) +#define PHY_PMA_ISO_PWRST_CTRL(n) ((0xcc13 | ((n) << 6)) << 2) +#define PHY_PMA_ISO_TX_DATA_LO(n) ((0xcc14 | ((n) << 6)) << 2) +#define PHY_PMA_ISO_TX_DATA_HI(n) ((0xcc15 | ((n) << 6)) << 2) +#define PHY_PMA_ISO_RX_DATA_LO(n) ((0xcc16 | ((n) << 6)) << 2) +#define PHY_PMA_ISO_RX_DATA_HI(n) ((0xcc17 | ((n) << 6)) << 2) +#define TX_BIST_CTRL(n) ((0x4140 | ((n) << 9)) << 2) +#define TX_BIST_UDDWR(n) ((0x4141 | ((n) << 9)) << 2) + +/* + * Selects which PLL clock will be driven on the analog high speed + * clock 0: PLL 0 div 1 + * clock 1: PLL 1 div 2 + */ +#define CLK_PLL_CONFIG 0X30 +#define CLK_PLL_MASK 0x33 + +#define CMN_READY BIT(0) + +#define DP_PLL_CLOCK_ENABLE BIT(2) +#define DP_PLL_ENABLE BIT(0) +#define DP_PLL_DATA_RATE_RBR ((2 << 12) | (4 << 8)) +#define DP_PLL_DATA_RATE_HBR ((2 << 12) | (4 << 8)) +#define DP_PLL_DATA_RATE_HBR2 ((1 << 12) | (2 << 8)) + +#define DP_MODE_A0 BIT(4) +#define DP_MODE_A2 BIT(6) +#define DP_MODE_ENTER_A0 0xc101 +#define DP_MODE_ENTER_A2 0xc104 + +#define PHY_MODE_SET_TIMEOUT 100000 + +#define PIN_ASSIGN_C_E 0x51d9 +#define PIN_ASSIGN_D_F 0x5100 + +#define MODE_DISCONNECT 0 +#define MODE_UFP_USB BIT(0) +#define MODE_DFP_USB BIT(1) +#define MODE_DFP_DP BIT(2) + +struct usb3phy_reg { + u32 offset; + u32 enable_bit; + u32 write_enable; +}; + +struct rockchip_usb3phy_port_cfg { + struct usb3phy_reg typec_conn_dir; + struct usb3phy_reg usb3tousb2_en; + struct usb3phy_reg external_psm; + struct usb3phy_reg pipe_status; +}; + +struct rockchip_typec_phy { + struct device *dev; + void __iomem *base; + struct extcon_dev *extcon; + struct regmap *grf_regs; + struct clk *clk_core; + struct clk *clk_ref; + struct reset_control *uphy_rst; + struct reset_control *pipe_rst; + struct reset_control *tcphy_rst; + struct rockchip_usb3phy_port_cfg port_cfgs; + /* mutex to protect access to individual PHYs */ + struct mutex lock; + + bool flip; + u8 mode; +}; + +struct phy_reg { + u16 value; + u32 addr; +}; + +struct phy_reg usb3_pll_cfg[] = { + { 0xf0, CMN_PLL0_VCOCAL_INIT }, + { 0x18, CMN_PLL0_VCOCAL_ITER }, + { 0xd0, CMN_PLL0_INTDIV }, + { 0x4a4a, CMN_PLL0_FRACDIV }, + { 0x34, CMN_PLL0_HIGH_THR }, + { 0x1ee, CMN_PLL0_SS_CTRL1 }, + { 0x7f03, CMN_PLL0_SS_CTRL2 }, + { 0x20, CMN_PLL0_DSM_DIAG }, + { 0, CMN_DIAG_PLL0_OVRD }, + { 0, CMN_DIAG_PLL0_FBH_OVRD }, + { 0, CMN_DIAG_PLL0_FBL_OVRD }, + { 0x7, CMN_DIAG_PLL0_V2I_TUNE }, + { 0x45, CMN_DIAG_PLL0_CP_TUNE }, + { 0x8, CMN_DIAG_PLL0_LF_PROG }, +}; + +struct phy_reg dp_pll_cfg[] = { + { 0xf0, CMN_PLL1_VCOCAL_INIT }, + { 0x18, CMN_PLL1_VCOCAL_ITER }, + { 0x30b9, CMN_PLL1_VCOCAL_START }, + { 0x21c, CMN_PLL1_INTDIV }, + { 0, CMN_PLL1_FRACDIV }, + { 0x5, CMN_PLL1_HIGH_THR }, + { 0x35, CMN_PLL1_SS_CTRL1 }, + { 0x7f1e, CMN_PLL1_SS_CTRL2 }, + { 0x20, CMN_PLL1_DSM_DIAG }, + { 0, CMN_PLLSM1_USER_DEF_CTRL }, + { 0, CMN_DIAG_PLL1_OVRD }, + { 0, CMN_DIAG_PLL1_FBH_OVRD }, + { 0, CMN_DIAG_PLL1_FBL_OVRD }, + { 0x6, CMN_DIAG_PLL1_V2I_TUNE }, + { 0x45, CMN_DIAG_PLL1_CP_TUNE }, + { 0x8, CMN_DIAG_PLL1_LF_PROG }, + { 0x100, CMN_DIAG_PLL1_PTATIS_TUNE1 }, + { 0x7, CMN_DIAG_PLL1_PTATIS_TUNE2 }, + { 0x4, CMN_DIAG_PLL1_INCLK_CTRL }, +}; + +static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy) +{ + u32 i, rdata; + + /* + * cmn_ref_clk_sel = 3, select the 24Mhz for clk parent + * cmn_psm_clk_dig_div = 2, set the clk division to 2 + */ + writel(0x830, tcphy->base + PMA_CMN_CTRL1); + for (i = 0; i < 4; i++) { + /* + * The following PHY configuration assumes a 24 MHz reference + * clock. + */ + writel(0x90, tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i)); + writel(0x960, tcphy->base + TX_RCVDET_EN_TMR(i)); + writel(0x30, tcphy->base + TX_RCVDET_ST_TMR(i)); + } + + rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL); + rdata &= ~CLK_PLL_MASK; + rdata |= CLK_PLL_CONFIG; + writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL); +} + +static void tcphy_cfg_usb3_pll(struct rockchip_typec_phy *tcphy) +{ + u32 i; + + /* load the configuration of PLL0 */ + for (i = 0; i < ARRAY_SIZE(usb3_pll_cfg); i++) + writel(usb3_pll_cfg[i].value, + tcphy->base + usb3_pll_cfg[i].addr); +} + +static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy) +{ + u32 i; + + /* set the default mode to RBR */ + writel(DP_PLL_CLOCK_ENABLE | DP_PLL_ENABLE | DP_PLL_DATA_RATE_RBR, + tcphy->base + DP_CLK_CTL); + + /* load the configuration of PLL1 */ + for (i = 0; i < ARRAY_SIZE(dp_pll_cfg); i++) + writel(dp_pll_cfg[i].value, tcphy->base + dp_pll_cfg[i].addr); +} + +static void tcphy_tx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) +{ + writel(0x7799, tcphy->base + TX_PSC_A0(lane)); + writel(0x7798, tcphy->base + TX_PSC_A1(lane)); + writel(0x5098, tcphy->base + TX_PSC_A2(lane)); + writel(0x5098, tcphy->base + TX_PSC_A3(lane)); + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); + writel(0xbf, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane)); +} + +static void tcphy_rx_usb3_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) +{ + writel(0xa6fd, tcphy->base + RX_PSC_A0(lane)); + writel(0xa6fd, tcphy->base + RX_PSC_A1(lane)); + writel(0xa410, tcphy->base + RX_PSC_A2(lane)); + writel(0x2410, tcphy->base + RX_PSC_A3(lane)); + writel(0x23ff, tcphy->base + RX_PSC_CAL(lane)); + writel(0x13, tcphy->base + RX_SIGDET_HL_FILT_TMR(lane)); + writel(0x03e7, tcphy->base + RX_REE_CTRL_DATA_MASK(lane)); + writel(0x1004, tcphy->base + RX_DIAG_SIGDET_TUNE(lane)); + writel(0x2010, tcphy->base + RX_PSC_RDY(lane)); + writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane)); +} + +static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy, u32 lane) +{ + u16 rdata; + + writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane)); + writel(0x6799, tcphy->base + TX_PSC_A0(lane)); + writel(0x6798, tcphy->base + TX_PSC_A1(lane)); + writel(0x98, tcphy->base + TX_PSC_A2(lane)); + writel(0x98, tcphy->base + TX_PSC_A3(lane)); + + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane)); + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane)); + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane)); + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane)); + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane)); + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane)); + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane)); + writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane)); + writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane)); + writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane)); + writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane)); + writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane)); + + writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane)); + writel(0x400, tcphy->base + TX_DIAG_TX_DRV(lane)); + + rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); + rdata = (rdata & 0x8fff) | 0x6000; + writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane)); +} + +static inline int property_enable(struct rockchip_typec_phy *tcphy, + const struct usb3phy_reg *reg, bool en) +{ + u32 mask = 1 << reg->write_enable; + u32 val = en << reg->enable_bit; + + return regmap_write(tcphy->grf_regs, reg->offset, val | mask); +} + +static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy) +{ + u16 rdata, rdata2, val; + + /* disable txda_cal_latch_en for rewrite the calibration values */ + rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1); + val = rdata & 0xdfff; + writel(val, tcphy->base + TX_ANA_CTRL_REG_1); + + /* + * read a resistor calibration code from CMN_TXPUCAL_CTRL[6:0] and + * write it to TX_DIG_CTRL_REG_2[6:0], and delay 1ms to make sure it + * works. + */ + rdata = readl(tcphy->base + TX_DIG_CTRL_REG_2); + rdata = rdata & 0xffc0; + + rdata2 = readl(tcphy->base + CMN_TXPUCAL_CTRL); + rdata2 = rdata2 & 0x3f; + + val = rdata | rdata2; + writel(val, tcphy->base + TX_DIG_CTRL_REG_2); + usleep_range(1000, 1050); + + /* + * Enable signal for latch that sample and holds calibration values. + * Activate this signal for 1 clock cycle to sample new calibration + * values. + */ + rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1); + val = rdata | 0x2000; + writel(val, tcphy->base + TX_ANA_CTRL_REG_1); + usleep_range(150, 200); + + /* set TX Voltage Level and TX Deemphasis to 0 */ + writel(0, tcphy->base + PHY_DP_TX_CTL); + /* re-enable decap */ + writel(0x100, tcphy->base + TX_ANA_CTRL_REG_2); + writel(0x300, tcphy->base + TX_ANA_CTRL_REG_2); + writel(0x2008, tcphy->base + TX_ANA_CTRL_REG_1); + writel(0x2018, tcphy->base + TX_ANA_CTRL_REG_1); + + writel(0, tcphy->base + TX_ANA_CTRL_REG_5); + + /* + * Programs txda_drv_ldo_prog[15:0], Sets driver LDO + * voltage 16'h1001 for DP-AUX-TX and RX + */ + writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4); + + /* re-enables Bandgap reference for LDO */ + writel(0x2098, tcphy->base + TX_ANA_CTRL_REG_1); + writel(0x2198, tcphy->base + TX_ANA_CTRL_REG_1); + + /* + * re-enables the transmitter pre-driver, driver data selection MUX, + * and receiver detect circuits. + */ + writel(0x301, tcphy->base + TX_ANA_CTRL_REG_2); + writel(0x303, tcphy->base + TX_ANA_CTRL_REG_2); + + /* + * BIT 12: Controls auxda_polarity, which selects the polarity of the + * xcvr: + * 1, Reverses the polarity (If TYPEC, Pulls ups aux_p and pull + * down aux_m) + * 0, Normal polarity (if TYPE_C, pulls up aux_m and pulls down + * aux_p) + */ + val = 0xa078; + if (!tcphy->flip) + val |= BIT(12); + writel(val, tcphy->base + TX_ANA_CTRL_REG_1); + + writel(0, tcphy->base + TX_ANA_CTRL_REG_3); + writel(0, tcphy->base + TX_ANA_CTRL_REG_4); + writel(0, tcphy->base + TX_ANA_CTRL_REG_5); + + /* + * Controls low_power_swing_en, set the voltage swing of the driver + * to 400mv. The values below are peak to peak (differential) values. + */ + writel(4, tcphy->base + TXDA_COEFF_CALC_CTRL); + writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA); + + /* Controls tx_high_z_tm_en */ + val = readl(tcphy->base + TX_DIG_CTRL_REG_2); + val |= BIT(15); + writel(val, tcphy->base + TX_DIG_CTRL_REG_2); +} + +static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode) +{ + struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs; + int ret, i; + u32 val; + + ret = clk_prepare_enable(tcphy->clk_core); + if (ret) { + dev_err(tcphy->dev, "Failed to prepare_enable core clock\n"); + return ret; + } + + ret = clk_prepare_enable(tcphy->clk_ref); + if (ret) { + dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n"); + goto err_clk_core; + } + + reset_control_deassert(tcphy->tcphy_rst); + + property_enable(tcphy, &cfg->typec_conn_dir, tcphy->flip); + + tcphy_cfg_24m(tcphy); + + if (mode == MODE_DFP_DP) { + tcphy_cfg_dp_pll(tcphy); + for (i = 0; i < 4; i++) + tcphy_dp_cfg_lane(tcphy, i); + + writel(PIN_ASSIGN_C_E, tcphy->base + PMA_LANE_CFG); + } else { + tcphy_cfg_usb3_pll(tcphy); + tcphy_cfg_dp_pll(tcphy); + if (tcphy->flip) { + tcphy_tx_usb3_cfg_lane(tcphy, 3); + tcphy_rx_usb3_cfg_lane(tcphy, 2); + tcphy_dp_cfg_lane(tcphy, 0); + tcphy_dp_cfg_lane(tcphy, 1); + } else { + tcphy_tx_usb3_cfg_lane(tcphy, 0); + tcphy_rx_usb3_cfg_lane(tcphy, 1); + tcphy_dp_cfg_lane(tcphy, 2); + tcphy_dp_cfg_lane(tcphy, 3); + } + + writel(PIN_ASSIGN_D_F, tcphy->base + PMA_LANE_CFG); + } + + writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL); + + reset_control_deassert(tcphy->uphy_rst); + + ret = readx_poll_timeout(readl, tcphy->base + PMA_CMN_CTRL1, + val, val & CMN_READY, 10, + PHY_MODE_SET_TIMEOUT); + if (ret < 0) { + dev_err(tcphy->dev, "wait pma ready timeout\n"); + ret = -ETIMEDOUT; + goto err_wait_pma; + } + + reset_control_deassert(tcphy->pipe_rst); + + return 0; + +err_wait_pma: + reset_control_assert(tcphy->uphy_rst); + reset_control_assert(tcphy->tcphy_rst); + clk_disable_unprepare(tcphy->clk_ref); +err_clk_core: + clk_disable_unprepare(tcphy->clk_core); + return ret; +} + +static void tcphy_phy_deinit(struct rockchip_typec_phy *tcphy) +{ + reset_control_assert(tcphy->tcphy_rst); + reset_control_assert(tcphy->uphy_rst); + reset_control_assert(tcphy->pipe_rst); + clk_disable_unprepare(tcphy->clk_core); + clk_disable_unprepare(tcphy->clk_ref); +} + +static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) +{ + struct extcon_dev *edev = tcphy->extcon; + union extcon_property_value property; + unsigned int id; + bool dfp, ufp, dp; + u8 mode; + int ret; + + ufp = extcon_get_state(edev, EXTCON_USB); + dfp = extcon_get_state(edev, EXTCON_USB_HOST); + dp = extcon_get_state(edev, EXTCON_DISP_DP); + + mode = MODE_DFP_USB; + id = EXTCON_USB_HOST; + + if (ufp) { + mode = MODE_UFP_USB; + id = EXTCON_USB; + } else if (dp) { + mode = MODE_DFP_DP; + id = EXTCON_DISP_DP; + + ret = extcon_get_property(edev, id, EXTCON_PROP_USB_SS, + &property); + if (ret) { + dev_err(tcphy->dev, "get superspeed property failed\n"); + return ret; + } + + if (property.intval) + mode |= MODE_DFP_USB; + } + + ret = extcon_get_property(edev, id, EXTCON_PROP_USB_TYPEC_POLARITY, + &property); + if (ret) { + dev_err(tcphy->dev, "get polarity property failed\n"); + return ret; + } + + tcphy->flip = property.intval ? 1 : 0; + + return mode; +} + +static int rockchip_usb3_phy_power_on(struct phy *phy) +{ + struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); + struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs; + const struct usb3phy_reg *reg = &cfg->pipe_status; + int timeout, new_mode, ret = 0; + u32 val; + + mutex_lock(&tcphy->lock); + + new_mode = tcphy_get_mode(tcphy); + if (new_mode < 0) { + ret = new_mode; + goto unlock_ret; + } + + /* DP-only mode; fall back to USB2 */ + if (!(new_mode & (MODE_DFP_USB | MODE_UFP_USB))) + goto unlock_ret; + + if (tcphy->mode == new_mode) + goto unlock_ret; + + if (tcphy->mode == MODE_DISCONNECT) + tcphy_phy_init(tcphy, new_mode); + + /* wait TCPHY for pipe ready */ + for (timeout = 0; timeout < 100; timeout++) { + regmap_read(tcphy->grf_regs, reg->offset, &val); + if (!(val & BIT(reg->enable_bit))) { + tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB); + goto unlock_ret; + } + usleep_range(10, 20); + } + + if (tcphy->mode == MODE_DISCONNECT) + tcphy_phy_deinit(tcphy); + + ret = -ETIMEDOUT; + +unlock_ret: + mutex_unlock(&tcphy->lock); + return ret; +} + +static int rockchip_usb3_phy_power_off(struct phy *phy) +{ + struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); + + mutex_lock(&tcphy->lock); + + if (tcphy->mode == MODE_DISCONNECT) + goto unlock; + + tcphy->mode &= ~(MODE_UFP_USB | MODE_DFP_USB); + if (tcphy->mode == MODE_DISCONNECT) + tcphy_phy_deinit(tcphy); + +unlock: + mutex_unlock(&tcphy->lock); + return 0; +} + +static const struct phy_ops rockchip_usb3_phy_ops = { + .power_on = rockchip_usb3_phy_power_on, + .power_off = rockchip_usb3_phy_power_off, + .owner = THIS_MODULE, +}; + +static int rockchip_dp_phy_power_on(struct phy *phy) +{ + struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); + int new_mode, ret = 0; + u32 val; + + mutex_lock(&tcphy->lock); + + new_mode = tcphy_get_mode(tcphy); + if (new_mode < 0) { + ret = new_mode; + goto unlock_ret; + } + + if (!(new_mode & MODE_DFP_DP)) { + ret = -ENODEV; + goto unlock_ret; + } + + if (tcphy->mode == new_mode) + goto unlock_ret; + + /* + * If the PHY has been power on, but the mode is not DP only mode, + * re-init the PHY for setting all of 4 lanes to DP. + */ + if (new_mode == MODE_DFP_DP && tcphy->mode != MODE_DISCONNECT) { + tcphy_phy_deinit(tcphy); + tcphy_phy_init(tcphy, new_mode); + } else if (tcphy->mode == MODE_DISCONNECT) { + tcphy_phy_init(tcphy, new_mode); + } + + ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL, + val, val & DP_MODE_A2, 1000, + PHY_MODE_SET_TIMEOUT); + if (ret < 0) { + dev_err(tcphy->dev, "failed to wait TCPHY enter A2\n"); + goto power_on_finish; + } + + tcphy_dp_aux_calibration(tcphy); + + writel(DP_MODE_ENTER_A0, tcphy->base + DP_MODE_CTL); + + ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL, + val, val & DP_MODE_A0, 1000, + PHY_MODE_SET_TIMEOUT); + if (ret < 0) { + writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL); + dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n"); + goto power_on_finish; + } + + tcphy->mode |= MODE_DFP_DP; + +power_on_finish: + if (tcphy->mode == MODE_DISCONNECT) + tcphy_phy_deinit(tcphy); +unlock_ret: + mutex_unlock(&tcphy->lock); + return ret; +} + +static int rockchip_dp_phy_power_off(struct phy *phy) +{ + struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); + + mutex_lock(&tcphy->lock); + + if (tcphy->mode == MODE_DISCONNECT) + goto unlock; + + tcphy->mode &= ~MODE_DFP_DP; + + writel(DP_MODE_ENTER_A2, tcphy->base + DP_MODE_CTL); + + if (tcphy->mode == MODE_DISCONNECT) + tcphy_phy_deinit(tcphy); + +unlock: + mutex_unlock(&tcphy->lock); + return 0; +} + +static const struct phy_ops rockchip_dp_phy_ops = { + .power_on = rockchip_dp_phy_power_on, + .power_off = rockchip_dp_phy_power_off, + .owner = THIS_MODULE, +}; + +static int tcphy_get_param(struct device *dev, + struct usb3phy_reg *reg, + const char *name) +{ + u32 buffer[3]; + int ret; + + ret = of_property_read_u32_array(dev->of_node, name, buffer, 3); + if (ret) { + dev_err(dev, "Can not parse %s\n", name); + return ret; + } + + reg->offset = buffer[0]; + reg->enable_bit = buffer[1]; + reg->write_enable = buffer[2]; + return 0; +} + +static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy, + struct device *dev) +{ + struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs; + int ret; + + ret = tcphy_get_param(dev, &cfg->typec_conn_dir, + "rockchip,typec-conn-dir"); + if (ret) + return ret; + + ret = tcphy_get_param(dev, &cfg->usb3tousb2_en, + "rockchip,usb3tousb2-en"); + if (ret) + return ret; + + ret = tcphy_get_param(dev, &cfg->external_psm, + "rockchip,external-psm"); + if (ret) + return ret; + + ret = tcphy_get_param(dev, &cfg->pipe_status, + "rockchip,pipe-status"); + if (ret) + return ret; + + tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + if (IS_ERR(tcphy->grf_regs)) { + dev_err(dev, "could not find grf dt node\n"); + return PTR_ERR(tcphy->grf_regs); + } + + tcphy->clk_core = devm_clk_get(dev, "tcpdcore"); + if (IS_ERR(tcphy->clk_core)) { + dev_err(dev, "could not get uphy core clock\n"); + return PTR_ERR(tcphy->clk_core); + } + + tcphy->clk_ref = devm_clk_get(dev, "tcpdphy-ref"); + if (IS_ERR(tcphy->clk_ref)) { + dev_err(dev, "could not get uphy ref clock\n"); + return PTR_ERR(tcphy->clk_ref); + } + + tcphy->uphy_rst = devm_reset_control_get(dev, "uphy"); + if (IS_ERR(tcphy->uphy_rst)) { + dev_err(dev, "no uphy_rst reset control found\n"); + return PTR_ERR(tcphy->uphy_rst); + } + + tcphy->pipe_rst = devm_reset_control_get(dev, "uphy-pipe"); + if (IS_ERR(tcphy->pipe_rst)) { + dev_err(dev, "no pipe_rst reset control found\n"); + return PTR_ERR(tcphy->pipe_rst); + } + + tcphy->tcphy_rst = devm_reset_control_get(dev, "uphy-tcphy"); + if (IS_ERR(tcphy->tcphy_rst)) { + dev_err(dev, "no tcphy_rst reset control found\n"); + return PTR_ERR(tcphy->tcphy_rst); + } + + return 0; +} + +static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy) +{ + struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs; + + reset_control_assert(tcphy->tcphy_rst); + reset_control_assert(tcphy->uphy_rst); + reset_control_assert(tcphy->pipe_rst); + + /* select external psm clock */ + property_enable(tcphy, &cfg->external_psm, 1); + property_enable(tcphy, &cfg->usb3tousb2_en, 0); + + tcphy->mode = MODE_DISCONNECT; +} + +static int rockchip_typec_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child_np; + struct rockchip_typec_phy *tcphy; + struct phy_provider *phy_provider; + struct resource *res; + int ret; + + tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL); + if (!tcphy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tcphy->base = devm_ioremap_resource(dev, res); + if (IS_ERR(tcphy->base)) + return PTR_ERR(tcphy->base); + + ret = tcphy_parse_dt(tcphy, dev); + if (ret) + return ret; + + tcphy->dev = dev; + platform_set_drvdata(pdev, tcphy); + mutex_init(&tcphy->lock); + + typec_phy_pre_init(tcphy); + + tcphy->extcon = extcon_get_edev_by_phandle(dev, 0); + if (IS_ERR(tcphy->extcon)) { + if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER) + dev_err(dev, "Invalid or missing extcon\n"); + return PTR_ERR(tcphy->extcon); + } + + for_each_available_child_of_node(np, child_np) { + struct phy *phy; + + if (!of_node_cmp(child_np->name, "dp-port")) + phy = devm_phy_create(dev, child_np, + &rockchip_dp_phy_ops); + else if (!of_node_cmp(child_np->name, "usb3-port")) + phy = devm_phy_create(dev, child_np, + &rockchip_usb3_phy_ops); + else + continue; + + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy: %s\n", + child_np->name); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy, tcphy); + } + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + dev_err(dev, "Failed to register phy provider\n"); + return PTR_ERR(phy_provider); + } + + return 0; +} + +static const struct of_device_id rockchip_typec_phy_dt_ids[] = { + { .compatible = "rockchip,rk3399-typec-phy" }, + {} +}; + +MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids); + +static struct platform_driver rockchip_typec_phy_driver = { + .probe = rockchip_typec_phy_probe, + .driver = { + .name = "rockchip-typec-phy", + .of_match_table = rockchip_typec_phy_dt_ids, + }, +}; + +module_platform_driver(rockchip_typec_phy_driver); + +MODULE_AUTHOR("Chris Zhong "); +MODULE_AUTHOR("Kever Yang "); +MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver"); +MODULE_LICENSE("GPL v2"); From d83614e45b37dddd4118d76f5b8a37a9d8f8993f Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Tue, 6 Sep 2016 10:00:20 -0700 Subject: [PATCH 274/343] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY This patch adds a binding that describes the Rockchip USB Type-C PHY for rk3399 Signed-off-by: Chris Zhong Reviewed-by: Tomasz Figa Reviewed-by: Kever Yang Reviewed-by: Guenter Roeck Acked-by: Rob Herring Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/phy-rockchip-typec.txt | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file mode 100644 index 000000000000..6ea867e3176f --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt @@ -0,0 +1,101 @@ +* ROCKCHIP type-c PHY +--------------------- + +Required properties: + - compatible : must be "rockchip,rk3399-typec-phy" + - reg: Address and length of the usb phy control register set + - rockchip,grf : phandle to the syscon managing the "general + register files" + - clocks : phandle + clock specifier for the phy clocks + - clock-names : string, clock name, must be "tcpdcore", "tcpdphy-ref"; + - assigned-clocks: main clock, should be <&cru SCLK_UPHY0_TCPDCORE> or + <&cru SCLK_UPHY1_TCPDCORE>; + - assigned-clock-rates : the phy core clk frequency, shall be: 50000000 + - resets : a list of phandle + reset specifier pairs + - reset-names : string reset name, must be: + "uphy", "uphy-pipe", "uphy-tcphy" + - extcon : extcon specifier for the Power Delivery + +Note, there are 2 type-c phys for RK3399, and they are almost identical, except +these registers(description below), every register node contains 3 sections: +offset, enable bit, write mask bit. + - rockchip,typec-conn-dir : the register of type-c connector direction, + for type-c phy0, it must be <0xe580 0 16>; + for type-c phy1, it must be <0xe58c 0 16>; + - rockchip,usb3tousb2-en : the register of type-c force usb3 to usb2 enable + control. + for type-c phy0, it must be <0xe580 3 19>; + for type-c phy1, it must be <0xe58c 3 19>; + - rockchip,external-psm : the register of type-c phy external psm clock + selection. + for type-c phy0, it must be <0xe588 14 30>; + for type-c phy1, it must be <0xe594 14 30>; + - rockchip,pipe-status : the register of type-c phy pipe status. + for type-c phy0, it must be <0xe5c0 0 0>; + for type-c phy1, it must be <0xe5c0 16 16>; + +Required nodes : a sub-node is required for each port the phy provides. + The sub-node name is used to identify dp or usb3 port, + and shall be the following entries: + * "dp-port" : the name of DP port. + * "usb3-port" : the name of USB3 port. + +Required properties (port (child) node): +- #phy-cells : must be 0, See ./phy-bindings.txt for details. + +Example: + tcphy0: phy@ff7c0000 { + compatible = "rockchip,rk3399-typec-phy"; + reg = <0x0 0xff7c0000 0x0 0x40000>; + rockchip,grf = <&grf>; + extcon = <&fusb0>; + clocks = <&cru SCLK_UPHY0_TCPDCORE>, + <&cru SCLK_UPHY0_TCPDPHY_REF>; + clock-names = "tcpdcore", "tcpdphy-ref"; + assigned-clocks = <&cru SCLK_UPHY0_TCPDCORE>; + assigned-clock-rates = <50000000>; + resets = <&cru SRST_UPHY0>, + <&cru SRST_UPHY0_PIPE_L00>, + <&cru SRST_P_UPHY0_TCPHY>; + reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,typec-conn-dir = <0xe580 0 16>; + rockchip,usb3tousb2-en = <0xe580 3 19>; + rockchip,external-psm = <0xe588 14 30>; + rockchip,pipe-status = <0xe5c0 0 0>; + + tcphy0_dp: dp-port { + #phy-cells = <0>; + }; + + tcphy0_usb3: usb3-port { + #phy-cells = <0>; + }; + }; + + tcphy1: phy@ff800000 { + compatible = "rockchip,rk3399-typec-phy"; + reg = <0x0 0xff800000 0x0 0x40000>; + rockchip,grf = <&grf>; + extcon = <&fusb1>; + clocks = <&cru SCLK_UPHY1_TCPDCORE>, + <&cru SCLK_UPHY1_TCPDPHY_REF>; + clock-names = "tcpdcore", "tcpdphy-ref"; + assigned-clocks = <&cru SCLK_UPHY1_TCPDCORE>; + assigned-clock-rates = <50000000>; + resets = <&cru SRST_UPHY1>, + <&cru SRST_UPHY1_PIPE_L00>, + <&cru SRST_P_UPHY1_TCPHY>; + reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + rockchip,typec-conn-dir = <0xe58c 0 16>; + rockchip,usb3tousb2-en = <0xe58c 3 19>; + rockchip,external-psm = <0xe594 14 30>; + rockchip,pipe-status = <0xe5c0 16 16>; + + tcphy1_dp: dp-port { + #phy-cells = <0>; + }; + + tcphy1_usb3: usb3-port { + #phy-cells = <0>; + }; + }; From cddbc4b7ef39ac5d84f183a46ee279cb0ae31a9f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 6 Sep 2016 14:54:46 +0200 Subject: [PATCH 275/343] usb: phy: add USB_SUPPORT dependency The driver now calls of_usb_get_dr_mode_by_phy, which is part of the USB core layer, and it fails to build when that is not provided: drivers/phy/phy-sun4i-usb.o: In function `sun4i_usb_phy_probe': phy-sun4i-usb.c:(.text.sun4i_usb_phy_probe+0x140): undefined reference to `of_usb_get_dr_mode_by_phy' We already have a couple of other PHY drivers with a dependency on USB_SUPPORT, so that seems to be the easiest fix here. An alternative would be to adjust the #ifdef in include/linux/usb/of.h to also check for CONFIG_USB_SUPPORT. Signed-off-by: Arnd Bergmann Reviewed-by: Hans de Goede Fixes: b33ecca87df9 ("phy-sun4i-usb: Add support for peripheral-only mode") Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 1f3e1fbef529..fe00f9134d51 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -267,7 +267,9 @@ config PHY_SUN4I_USB depends on RESET_CONTROLLER depends on EXTCON depends on POWER_SUPPLY + depends on USB_SUPPORT select GENERIC_PHY + select USB_COMMON help Enable this to support the transceiver that is part of Allwinner sunxi SoCs. From 2a4d59625bf0f0ae57d6fecf5970ca03613f5db8 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Wed, 7 Sep 2016 22:57:33 -0700 Subject: [PATCH 276/343] phy: rockchip-typec: add pm runtime support Adds pm_runtime support for rockchip Type-C, so that power domain is enabled only when there is a transaction going on to help save power. Signed-off-by: Chris Zhong Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-rockchip-typec.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/phy/phy-rockchip-typec.c b/drivers/phy/phy-rockchip-typec.c index fb58a2775a49..7cfb0f8995de 100644 --- a/drivers/phy/phy-rockchip-typec.c +++ b/drivers/phy/phy-rockchip-typec.c @@ -960,6 +960,8 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) return PTR_ERR(tcphy->extcon); } + pm_runtime_enable(dev); + for_each_available_child_of_node(np, child_np) { struct phy *phy; @@ -990,6 +992,13 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) return 0; } +static int rockchip_typec_phy_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + static const struct of_device_id rockchip_typec_phy_dt_ids[] = { { .compatible = "rockchip,rk3399-typec-phy" }, {} @@ -999,6 +1008,7 @@ MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids); static struct platform_driver rockchip_typec_phy_driver = { .probe = rockchip_typec_phy_probe, + .remove = rockchip_typec_phy_remove, .driver = { .name = "rockchip-typec-phy", .of_match_table = rockchip_typec_phy_dt_ids, From 9745ceebc4e1e593ddba1b1a104a4a99f2b9a556 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 7 Sep 2016 22:20:37 +0200 Subject: [PATCH 277/343] phy-sun4i-usb: Use bool where appropriate We're using bool as true/false type in most places in phy-sun4i-usb.c for consistency fixup the remaining uses of ints which are ever only 0 or 1 to be bools too. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index fcf4d95ecc6d..1cb84a8a4253 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -445,7 +445,8 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) struct sun4i_usb_phy_data *data = container_of(work, struct sun4i_usb_phy_data, detect.work); struct phy *phy0 = data->phys[0].phy; - int id_det, vbus_det, id_notify = 0, vbus_notify = 0; + bool id_notify = false, vbus_notify = false; + int id_det, vbus_det; if (phy0 == NULL) return; @@ -474,13 +475,13 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) } sun4i_usb_phy0_set_id_detect(phy0, id_det); data->id_det = id_det; - id_notify = 1; + id_notify = true; } if (vbus_det != data->vbus_det) { sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det); data->vbus_det = vbus_det; - vbus_notify = 1; + vbus_notify = true; } mutex_unlock(&phy0->mutex); From 36f9159ba99076ab643794a83735197b4042b16f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 7 Sep 2016 22:20:38 +0200 Subject: [PATCH 278/343] phy-sun4i-usb: Refactor forced session ending The phy-sun4i-usb code supports forced ending a session on systems which lack Vbus detection, to allow switching between host and peripheral mode on such systems. Role switching via the musb driver "mode" sysfs attribute requires force ending the session too. This commit refactors the code to allow other parts of the phy-sun4i-usb code to request a forced session end. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 1cb84a8a4253..02cb65ef52d0 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -133,6 +133,7 @@ struct sun4i_usb_phy_data { struct power_supply *vbus_power_supply; struct notifier_block vbus_power_nb; bool vbus_power_nb_registered; + bool force_session_end; int id_det_irq; int vbus_det_irq; int id_det; @@ -445,7 +446,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) struct sun4i_usb_phy_data *data = container_of(work, struct sun4i_usb_phy_data, detect.work); struct phy *phy0 = data->phys[0].phy; - bool id_notify = false, vbus_notify = false; + bool force_session_end, id_notify = false, vbus_notify = false; int id_det, vbus_det; if (phy0 == NULL) @@ -461,14 +462,17 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) return; } + force_session_end = data->force_session_end; + data->force_session_end = false; + if (id_det != data->id_det) { - /* - * When a host cable (id == 0) gets plugged in on systems - * without vbus detection report vbus low for long enough for - * the musb-ip to end the current device session. - */ + /* id-change, force session end if we've no vbus detection */ if (data->dr_mode == USB_DR_MODE_OTG && - !sun4i_usb_phy0_have_vbus_det(data) && id_det == 0) { + !sun4i_usb_phy0_have_vbus_det(data)) + force_session_end = true; + + /* When entering host mode (id = 0) force end the session now */ + if (force_session_end && id_det == 0) { sun4i_usb_phy0_set_vbus_detect(phy0, 0); msleep(200); sun4i_usb_phy0_set_vbus_detect(phy0, 1); @@ -489,13 +493,8 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) if (id_notify) { extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST, !id_det); - /* - * When a host cable gets unplugged (id == 1) on systems - * without vbus detection report vbus low for long enough to - * the musb-ip to end the current host session. - */ - if (data->dr_mode == USB_DR_MODE_OTG && - !sun4i_usb_phy0_have_vbus_det(data) && id_det == 1) { + /* When leaving host mode force end the session here */ + if (force_session_end && id_det == 1) { mutex_lock(&phy0->mutex); sun4i_usb_phy0_set_vbus_detect(phy0, 0); msleep(1000); From 5f90d31cab915e2405f8875e21239d4a6003a170 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 7 Sep 2016 22:20:39 +0200 Subject: [PATCH 279/343] phy-sun4i-usb: Simplify missing dr_mode handling If we cannot get dr_mode or no id gpio is specified simply assume peripheral mode, as this is always safe. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 42 +++++++++++++------------------------ 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 02cb65ef52d0..fb2d4f3666a5 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -124,7 +124,6 @@ struct sun4i_usb_phy_data { bool regulator_on; int index; } phys[MAX_PHYS]; - int first_phy; /* phy0 / otg related variables */ struct extcon_dev *extcon; bool phy0_init; @@ -326,7 +325,10 @@ static int sun4i_usb_phy0_get_id_det(struct sun4i_usb_phy_data *data) { switch (data->dr_mode) { case USB_DR_MODE_OTG: - return gpiod_get_value_cansleep(data->id_det_gpio); + if (data->id_det_gpio) + return gpiod_get_value_cansleep(data->id_det_gpio); + else + return 1; /* Fallback to peripheral mode */ case USB_DR_MODE_HOST: return 0; case USB_DR_MODE_PERIPHERAL: @@ -539,8 +541,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev, { struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); - if (args->args[0] < data->first_phy || - args->args[0] >= data->cfg->num_phys) + if (args->args[0] >= data->cfg->num_phys) return ERR_PTR(-ENODEV); return data->phys[args->args[0]].phy; @@ -615,33 +616,18 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } data->dr_mode = of_usb_get_dr_mode_by_phy(np, 0); - switch (data->dr_mode) { - case USB_DR_MODE_OTG: - /* otg without id_det makes no sense, and is not supported */ - if (!data->id_det_gpio) { - dev_err(dev, "usb0_id_det missing or invalid\n"); - return -ENODEV; - } - /* fall through */ - case USB_DR_MODE_HOST: - case USB_DR_MODE_PERIPHERAL: - data->extcon = devm_extcon_dev_allocate(dev, - sun4i_usb_phy0_cable); - if (IS_ERR(data->extcon)) - return PTR_ERR(data->extcon); - ret = devm_extcon_dev_register(dev, data->extcon); - if (ret) { - dev_err(dev, "failed to register extcon: %d\n", ret); - return ret; - } - break; - default: - dev_info(dev, "dr_mode unknown, not registering usb phy0\n"); - data->first_phy = 1; + data->extcon = devm_extcon_dev_allocate(dev, sun4i_usb_phy0_cable); + if (IS_ERR(data->extcon)) + return PTR_ERR(data->extcon); + + ret = devm_extcon_dev_register(dev, data->extcon); + if (ret) { + dev_err(dev, "failed to register extcon: %d\n", ret); + return ret; } - for (i = data->first_phy; i < data->cfg->num_phys; i++) { + for (i = 0; i < data->cfg->num_phys; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[16]; From 6ba43c2919613dad1a880fcab19cda1d68a5ce3d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 7 Sep 2016 22:20:40 +0200 Subject: [PATCH 280/343] phy-sun4i-usb: Add support for phy_set_mode Together with some musb sunxi glue changes this allows run-time dr_mode switching support via the "mode" musb sysfs attribute. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index fb2d4f3666a5..af42f8d40ac1 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -427,6 +427,35 @@ static int sun4i_usb_phy_power_off(struct phy *_phy) return 0; } +static int sun4i_usb_phy_set_mode(struct phy *_phy, enum phy_mode mode) +{ + struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + + if (phy->index != 0) + return -EINVAL; + + switch (mode) { + case PHY_MODE_USB_HOST: + data->dr_mode = USB_DR_MODE_HOST; + break; + case PHY_MODE_USB_DEVICE: + data->dr_mode = USB_DR_MODE_PERIPHERAL; + break; + case PHY_MODE_USB_OTG: + data->dr_mode = USB_DR_MODE_OTG; + break; + default: + return -EINVAL; + } + + dev_info(&_phy->dev, "Changing dr_mode to %d\n", (int)data->dr_mode); + data->force_session_end = true; + queue_delayed_work(system_wq, &data->detect, 0); + + return 0; +} + void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); @@ -440,6 +469,7 @@ static const struct phy_ops sun4i_usb_phy_ops = { .exit = sun4i_usb_phy_exit, .power_on = sun4i_usb_phy_power_on, .power_off = sun4i_usb_phy_power_off, + .set_mode = sun4i_usb_phy_set_mode, .owner = THIS_MODULE, }; From 91d6e3b6bcf2625a07fec22a9af37ddbfd91a0df Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 7 Sep 2016 22:20:41 +0200 Subject: [PATCH 281/343] phy-sun4i-usb: Warn when external vbus is detected Warn when external vbus is detected when we're trying to enable our own vbus. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index af42f8d40ac1..03f030b491d6 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -390,8 +390,10 @@ static int sun4i_usb_phy_power_on(struct phy *_phy) /* For phy0 only turn on Vbus if we don't have an ext. Vbus */ if (phy->index == 0 && sun4i_usb_phy0_have_vbus_det(data) && - data->vbus_det) + data->vbus_det) { + dev_warn(&_phy->dev, "External vbus detected, not enabling our own vbus\n"); return 0; + } ret = regulator_enable(phy->vbus); if (ret) From cac18ecb6f44b11bc303d7afbae3887b27938fa4 Mon Sep 17 00:00:00 2001 From: Randy Li Date: Sat, 10 Sep 2016 02:59:37 +0800 Subject: [PATCH 282/343] phy: Add reset callback The only use for this is for solving a hardware design problem in usb of Rockchip RK3288. Signed-off-by: Randy Li Reviewed-by: Heiko Stuebner Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-core.c | 15 +++++++++++++++ include/linux/phy/phy.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 8eca906b6e70..a268f4d6f3e9 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -357,6 +357,21 @@ int phy_set_mode(struct phy *phy, enum phy_mode mode) } EXPORT_SYMBOL_GPL(phy_set_mode); +int phy_reset(struct phy *phy) +{ + int ret; + + if (!phy || !phy->ops->reset) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->reset(phy); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_reset); + /** * _of_phy_get() - lookup and obtain a reference to a phy by phandle * @np: device_node for which to get the phy diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index f08b67238b58..ee1bed7dbfc6 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -36,6 +36,7 @@ enum phy_mode { * @power_on: powering on the phy * @power_off: powering off the phy * @set_mode: set the mode of the phy + * @reset: resetting the phy * @owner: the module owner containing the ops */ struct phy_ops { @@ -44,6 +45,7 @@ struct phy_ops { int (*power_on)(struct phy *phy); int (*power_off)(struct phy *phy); int (*set_mode)(struct phy *phy, enum phy_mode mode); + int (*reset)(struct phy *phy); struct module *owner; }; @@ -136,6 +138,7 @@ int phy_exit(struct phy *phy); int phy_power_on(struct phy *phy); int phy_power_off(struct phy *phy); int phy_set_mode(struct phy *phy, enum phy_mode mode); +int phy_reset(struct phy *phy); static inline int phy_get_bus_width(struct phy *phy) { return phy->attrs.bus_width; From 0f74ab59ce8712e7e2bb1e4517033328e626b27c Mon Sep 17 00:00:00 2001 From: Randy Li Date: Sat, 10 Sep 2016 02:59:38 +0800 Subject: [PATCH 283/343] phy: rockchip-usb: use rockchip_usb_phy_reset to reset phy during wakeup It is a hardware bug in RK3288, the only way to solve it is to reset the phy. Signed-off-by: Randy Li Signed-off-by: Kishon Vijay Abraham I --- .../bindings/phy/rockchip-usb-phy.txt | 3 +++ drivers/phy/phy-rockchip-usb.c | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt index cc6be9680a6d..57dc388e2fa2 100644 --- a/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt @@ -27,6 +27,9 @@ Optional Properties: - clocks : phandle + clock specifier for the phy clocks - clock-names: string, clock name, must be "phyclk" - #clock-cells: for users of the phy-pll, should be 0 +- reset-names: Only allow the following entries: + - phy-reset +- resets: Must contain an entry for each entry in reset-names. Example: diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index 2a7381f4fe4c..734987fa0ad7 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -29,6 +29,7 @@ #include #include #include +#include static int enable_usb_uart; @@ -64,6 +65,7 @@ struct rockchip_usb_phy { struct clk_hw clk480m_hw; struct phy *phy; bool uart_enabled; + struct reset_control *reset; }; static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy, @@ -144,9 +146,23 @@ static int rockchip_usb_phy_power_on(struct phy *_phy) return clk_prepare_enable(phy->clk480m); } +static int rockchip_usb_phy_reset(struct phy *_phy) +{ + struct rockchip_usb_phy *phy = phy_get_drvdata(_phy); + + if (phy->reset) { + reset_control_assert(phy->reset); + udelay(10); + reset_control_deassert(phy->reset); + } + + return 0; +} + static const struct phy_ops ops = { .power_on = rockchip_usb_phy_power_on, .power_off = rockchip_usb_phy_power_off, + .reset = rockchip_usb_phy_reset, .owner = THIS_MODULE, }; @@ -185,6 +201,10 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base, return -EINVAL; } + rk_phy->reset = of_reset_control_get(child, "phy-reset"); + if (IS_ERR(rk_phy->reset)) + rk_phy->reset = NULL; + rk_phy->reg_offset = reg_offset; rk_phy->clk = of_clk_get_by_name(child, "phyclk"); From 919ab2524c52e5f801d8873f09145ce822cdd43a Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 9 Sep 2016 11:58:18 +0800 Subject: [PATCH 284/343] phy: sun4i-usb: Use spinlock to guard phyctl register access The musb driver calls into this phy driver to disable/enable squelch detection. This function was introduced in 24fe86a617c5 ("phy: sun4i-usb: Add a sunxi specific function for setting squelch-detect"). This function in turn calls sun4i_usb_phy_write, which uses a mutex to guard the common access register. Unfortunately musb does this in atomic context, which results in the following warning with lock debugging enabled: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:97 in_atomic(): 1, irqs_disabled(): 128, pid: 96, name: kworker/0:2 CPU: 0 PID: 96 Comm: kworker/0:2 Not tainted 4.8.0-rc4-00181-gd502f8ad1c3e #13 Hardware name: Allwinner sun8i Family Workqueue: events musb_deassert_reset [] (unwind_backtrace) from [] (show_stack+0xb/0xc) [] (show_stack) from [] (dump_stack+0x67/0x74) [] (dump_stack) from [] (mutex_lock+0x15/0x2c) [] (mutex_lock) from [] (sun4i_usb_phy_write+0x39/0xec) [] (sun4i_usb_phy_write) from [] (musb_port_reset+0xfb/0x184) [] (musb_port_reset) from [] (musb_deassert_reset+0x1f/0x2c) [] (musb_deassert_reset) from [] (process_one_work+0x129/0x2b8) [] (process_one_work) from [] (worker_thread+0xf3/0x424) [] (worker_thread) from [] (kthread+0xa1/0xb8) [] (kthread) from [] (ret_from_fork+0x11/0x20) Since the register access is mmio, we can use a spinlock to guard this specific access, rather than the mutex that guards the entire phy. Fixes: ba4bdc9e1dc0 ("PHY: sunxi: Add driver for sunxi usb phy") Cc: Hans de Goede Cc: stable@vger.kernel.org Signed-off-by: Chen-Yu Tsai Reviewed-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 03f030b491d6..b9342a2af7b3 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -114,7 +115,7 @@ struct sun4i_usb_phy_data { void __iomem *base; const struct sun4i_usb_phy_cfg *cfg; enum usb_dr_mode dr_mode; - struct mutex mutex; + spinlock_t reg_lock; /* guard access to phyctl reg */ struct sun4i_usb_phy { struct phy *phy; void __iomem *pmu; @@ -181,9 +182,10 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy); u32 temp, usbc_bit = BIT(phy->index * 2); void __iomem *phyctl = phy_data->base + phy_data->cfg->phyctl_offset; + unsigned long flags; int i; - mutex_lock(&phy_data->mutex); + spin_lock_irqsave(&phy_data->reg_lock, flags); if (phy_data->cfg->type == sun8i_a33_phy || phy_data->cfg->type == sun50i_a64_phy) { @@ -221,7 +223,8 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, data >>= 1; } - mutex_unlock(&phy_data->mutex); + + spin_unlock_irqrestore(&phy_data->reg_lock, flags); } static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable) @@ -615,7 +618,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) if (!data) return -ENOMEM; - mutex_init(&data->mutex); + spin_lock_init(&data->reg_lock); INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); dev_set_drvdata(dev, data); data->cfg = of_device_get_match_data(dev); From 5e6c88d28ccbe72bedee1fbf4f9fea4764208598 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Fri, 9 Sep 2016 12:51:27 +0800 Subject: [PATCH 285/343] usb: dwc3: fix Clear Stall EP command failure Commit 50c763f8c1bac ("usb: dwc3: Set the ClearPendIN bit on Clear Stall EP command") sets ClearPendIN bit for all IN endpoints of v2.60a+ cores. This causes ClearStall command fails on 2.60+ cores operating in HighSpeed mode. In page 539 of 2.60a specification: "When issuing Clear Stall command for IN endpoints in SuperSpeed mode, the software must set the "ClearPendIN" bit to '1' to clear any pending IN transcations, so that the device does not expect any ACK TP from the host for the data sent earlier." It's obvious that we only need to apply this rule to those IN endpoints that currently operating in SuperSpeed mode. Fixes: 50c763f8c1bac ("usb: dwc3: Set the ClearPendIN bit on Clear Stall EP command") Cc: # v4.7+ Signed-off-by: Lu Baolu Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a5d496dd53b2..e49082f9edeb 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -341,7 +341,8 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) * IN transfers due to a mishandled error condition. Synopsys * STAR 9000614252. */ - if (dep->direction && (dwc->revision >= DWC3_REVISION_260A)) + if (dep->direction && (dwc->revision >= DWC3_REVISION_260A) && + (dwc->gadget.speed >= USB_SPEED_SUPER)) cmd |= DWC3_DEPCMD_CLEARPENDIN; memset(¶ms, 0, sizeof(params)); From 8d53e626759415700022d421e4e0eab245c2dc23 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Vulisha Date: Fri, 9 Sep 2016 18:58:37 +0530 Subject: [PATCH 286/343] usb: dwc3: of-simple: Fix warning during unbind In dwc3_of_simple_remove() we are using clk_unprepare() before doing any clk_disable(). If we enable Common CLK framework (CCF) and try to unbind dwc3-of-simple driver, we see kernel WARN messages. This patch fixes this kernel warning by using clk_disable_unprepare() instead of clk_unprepare(). Signed-off-by: Anurag Kumar Vulisha Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-of-simple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index 283f9980a260..ce9a070f4fe6 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -112,7 +112,7 @@ static int dwc3_of_simple_remove(struct platform_device *pdev) int i; for (i = 0; i < simple->num_clocks; i++) { - clk_unprepare(simple->clks[i]); + clk_disable_unprepare(simple->clks[i]); clk_put(simple->clks[i]); } From 6406c3d226374c28d452b11db3b5ac241ce26191 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Mon, 12 Sep 2016 16:38:46 +0800 Subject: [PATCH 287/343] usb: Kconfig: let USB_ULPI_BUS depends on USB_COMMON Since ulpi bus driver is located at usb/common/ulpi.c, whether it is compiled or not depends on CONFIG_USB_COMMON which needs either USB Host or USB Gadget is enabled, so even CONFIG_USB_ULPI_BUS is chosen, its source may still not be compiled when both USB HOST and USB gadget are disabled. It fixed compile error with below configurations: - # CONFIG_USB is not set - # CONFIG_USB_GADGET is not set - CONFIG_PHY_TUSB1210=m - CONFIG_USB_ULPI_BUS=m >> All errors (new ones prefixed by >>): >> >> ERROR: "ulpi_unregister_driver" [drivers/phy/phy-tusb1210.ko] undefined! >> ERROR: "__ulpi_register_driver" [drivers/phy/phy-tusb1210.ko] undefined! >> ERROR: "ulpi_write" [drivers/phy/phy-tusb1210.ko] undefined! Fixes: ad764c49f65a ("usb: Kconfig: move ulpi bus support out of host") Reported-by: kbuild test robot Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 6dfa10af7185..2b9159a9ab4f 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -162,6 +162,7 @@ config USB_LED_TRIG config USB_ULPI_BUS tristate "USB ULPI PHY interface support" + depends on USB_COMMON help UTMI+ Low Pin Interface (ULPI) is specification for a commonly used USB 2.0 PHY interface. The ULPI specification defines a standard set From c7914e8dfa4032d24ef7af4c86b9c841ec6b74e6 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Fri, 9 Sep 2016 19:15:44 -0700 Subject: [PATCH 288/343] extcon: Introduce EXTCON_PROP_DISP_HPD property EXTCON_PROP_DISP_HPD is need by display port, if the system has no hpd interrupt, this property can be used. - HPD (Hot Plug Detect) send the signal whether display device is on or off to source device. Signed-off-by: Chris Zhong Reviewed-by: Guenter Roeck [cw00.choi: Add the description of HPD and full name of HPD] Signed-off-by: Chanwoo Choi --- include/linux/extcon.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/linux/extcon.h b/include/linux/extcon.h index b34d1ae9011f..5c35f9d1822c 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -133,9 +133,20 @@ #define EXTCON_PROP_JACK_MAX 100 #define EXTCON_PROP_JACK_CNT (EXTCON_PROP_JACK_MAX - EXTCON_PROP_JACK_MIN + 1) +/* + * Properties of EXTCON_TYPE_DISP. + * + * - EXTCON_PROP_DISP_HPD (Hot Plug Detect) + * @type: integer (intval) + * @value: 0 (no hpd) or 1 (hpd) + * @default: 0 (no hpd) + * + */ +#define EXTCON_PROP_DISP_HPD 150 + /* Properties of EXTCON_TYPE_DISP. */ #define EXTCON_PROP_DISP_MIN 150 -#define EXTCON_PROP_DISP_MAX 150 +#define EXTCON_PROP_DISP_MAX 151 #define EXTCON_PROP_DISP_CNT (EXTCON_PROP_DISP_MAX - EXTCON_PROP_DISP_MIN + 1) /* From e5b07e555b02da6a171d8c4c670c4da0f219abde Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 17 Aug 2016 14:07:44 +0200 Subject: [PATCH 289/343] extcon: max14577: Change Krzysztof Kozlowski's email to kernel.org Change my email address to kernel.org instead of Samsung one for the purpose of any future contact. The copyrights remain untouched and are attributed to Samsung. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max14577.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c index 852a7112f451..a0cd6522a0ea 100644 --- a/drivers/extcon/extcon-max14577.c +++ b/drivers/extcon/extcon-max14577.c @@ -3,7 +3,7 @@ * * Copyright (C) 2013,2014 Samsung Electronics * Chanwoo Choi - * Krzysztof Kozlowski + * Krzysztof Kozlowski * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -791,6 +791,6 @@ static struct platform_driver max14577_muic_driver = { module_platform_driver(max14577_muic_driver); MODULE_DESCRIPTION("Maxim 14577/77836 Extcon driver"); -MODULE_AUTHOR("Chanwoo Choi , Krzysztof Kozlowski "); +MODULE_AUTHOR("Chanwoo Choi , Krzysztof Kozlowski "); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:extcon-max14577"); From 525867dbd11899835a029da3532eeee9f773db31 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 17 Aug 2016 19:02:35 +0100 Subject: [PATCH 290/343] extcon: axp288: Fix spelling mistake This patch fixes the spelling mistake in dev_dbg messages. Signed-off-by: Colin Ian King [cw00.choi: Modify the patch title/description] Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-axp288.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index fd55c2f2080a..04610f851437 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -189,19 +189,19 @@ static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) switch (chrg_type) { case DET_STAT_SDP: - dev_dbg(info->dev, "sdp cable is connecetd\n"); + dev_dbg(info->dev, "sdp cable is connected\n"); notify_otg = true; notify_charger = true; cable = EXTCON_CHG_USB_SDP; break; case DET_STAT_CDP: - dev_dbg(info->dev, "cdp cable is connecetd\n"); + dev_dbg(info->dev, "cdp cable is connected\n"); notify_otg = true; notify_charger = true; cable = EXTCON_CHG_USB_CDP; break; case DET_STAT_DCP: - dev_dbg(info->dev, "dcp cable is connecetd\n"); + dev_dbg(info->dev, "dcp cable is connected\n"); notify_charger = true; cable = EXTCON_CHG_USB_DCP; break; From 8670b4598064007abfc44554e713fa2004734e1d Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 16 Aug 2016 15:55:34 +0900 Subject: [PATCH 291/343] extcon: Use the extcon_set_state_sync() instead of deprecated functions This patch alters the renamed extcon API to set the state of the external connectors instead of deprecated extcon_set_cable_state_(). Because the patch[1] modifies the function name to maintain the function naming pattern. - extcon_set_cable_state_() -> extcon_set_state_sync() - extcon_get_cable_state_() -> extcon_get_state() [1] https://lkml.org/lkml/2016/8/4/729 - extcon: Rename the extcon_set/get_state() to maintain the function naming pattern Signed-off-by: Chanwoo Choi Acked-by: Charles Keepax Acked-by: Roger Quadros --- drivers/extcon/extcon-adc-jack.c | 4 +-- drivers/extcon/extcon-arizona.c | 16 +++++------ drivers/extcon/extcon-axp288.c | 2 +- drivers/extcon/extcon-gpio.c | 2 +- drivers/extcon/extcon-max14577.c | 14 +++++----- drivers/extcon/extcon-max3355.c | 8 +++--- drivers/extcon/extcon-max77693.c | 46 ++++++++++++++++---------------- drivers/extcon/extcon-max77843.c | 22 +++++++-------- drivers/extcon/extcon-max8997.c | 20 +++++++------- drivers/extcon/extcon-palmas.c | 16 +++++------ drivers/extcon/extcon-rt8973a.c | 4 +-- drivers/extcon/extcon-sm5502.c | 4 +-- drivers/extcon/extcon-usb-gpio.c | 8 +++--- 13 files changed, 83 insertions(+), 83 deletions(-) diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index e62e6cd7e00a..bc538708c753 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -75,7 +75,7 @@ static void adc_jack_handler(struct work_struct *work) for (i = 0; i < data->num_conditions; i++) { def = &data->adc_conditions[i]; if (def->min_adc <= adc_val && def->max_adc >= adc_val) { - extcon_set_cable_state_(data->edev, def->id, true); + extcon_set_state_sync(data->edev, def->id, true); return; } } @@ -83,7 +83,7 @@ static void adc_jack_handler(struct work_struct *work) /* Set the detached state if adc value is not included in the range */ for (i = 0; i < data->num_conditions; i++) { def = &data->adc_conditions[i]; - extcon_set_cable_state_(data->edev, def->id, false); + extcon_set_state_sync(data->edev, def->id, false); } } diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 493bd9fe5f67..56e6c4c7c60d 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -614,7 +614,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) } /* If the cable was removed while measuring ignore the result */ - ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL); + ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); if (ret < 0) { dev_err(arizona->dev, "Failed to check cable state: %d\n", ret); @@ -649,7 +649,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) else report = EXTCON_JACK_HEADPHONE; - ret = extcon_set_cable_state_(info->edev, report, true); + ret = extcon_set_state_sync(info->edev, report, true); if (ret != 0) dev_err(arizona->dev, "Failed to report HP/line: %d\n", ret); @@ -732,7 +732,7 @@ err: ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); /* Just report headphone */ - ret = extcon_set_cable_state_(info->edev, EXTCON_JACK_HEADPHONE, true); + ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); if (ret != 0) dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); @@ -789,7 +789,7 @@ err: ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); /* Just report headphone */ - ret = extcon_set_cable_state_(info->edev, EXTCON_JACK_HEADPHONE, true); + ret = extcon_set_state_sync(info->edev, EXTCON_JACK_HEADPHONE, true); if (ret != 0) dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); @@ -829,7 +829,7 @@ static void arizona_micd_detect(struct work_struct *work) mutex_lock(&info->lock); /* If the cable was removed while measuring ignore the result */ - ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL); + ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); if (ret < 0) { dev_err(arizona->dev, "Failed to check cable state: %d\n", ret); @@ -914,7 +914,7 @@ static void arizona_micd_detect(struct work_struct *work) arizona_identify_headphone(info); - ret = extcon_set_cable_state_(info->edev, + ret = extcon_set_state_sync(info->edev, EXTCON_JACK_MICROPHONE, true); if (ret != 0) dev_err(arizona->dev, "Headset report failed: %d\n", @@ -1108,7 +1108,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) if (info->last_jackdet == present) { dev_dbg(arizona->dev, "Detected jack\n"); - ret = extcon_set_cable_state_(info->edev, + ret = extcon_set_state_sync(info->edev, EXTCON_MECHANICAL, true); if (ret != 0) @@ -1150,7 +1150,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) input_sync(info->input); for (i = 0; i < ARRAY_SIZE(arizona_cable) - 1; i++) { - ret = extcon_set_cable_state_(info->edev, + ret = extcon_set_state_sync(info->edev, arizona_cable[i], false); if (ret != 0) dev_err(arizona->dev, diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index 04610f851437..42f41e808292 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -226,7 +226,7 @@ notify_otg: } if (notify_charger) - extcon_set_cable_state_(info->edev, cable, vbus_attach); + extcon_set_state_sync(info->edev, cable, vbus_attach); /* Clear the flags on disconnect event */ if (!vbus_attach) diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index b1b0264eb12d..e7aebbc945f6 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -49,7 +49,7 @@ static void gpio_extcon_work(struct work_struct *work) state = gpiod_get_value_cansleep(data->id_gpiod); if (data->pdata->gpio_active_low) state = !state; - extcon_set_cable_state_(data->edev, data->pdata->extcon_id, state); + extcon_set_state_sync(data->edev, data->pdata->extcon_id, state); } static irqreturn_t gpio_irq_handler(int irq, void *dev_id) diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c index a0cd6522a0ea..12e26c4e7763 100644 --- a/drivers/extcon/extcon-max14577.c +++ b/drivers/extcon/extcon-max14577.c @@ -357,7 +357,7 @@ static int max14577_muic_jig_handler(struct max14577_muic_info *info, if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_JIG, attached); + extcon_set_state_sync(info->edev, EXTCON_JIG, attached); return 0; } @@ -454,24 +454,24 @@ static int max14577_muic_chg_handler(struct max14577_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_USB, attached); - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_USB, attached); + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, attached); break; case MAX14577_CHARGER_TYPE_DEDICATED_CHG: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, attached); break; case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_CDP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_CDP, attached); break; case MAX14577_CHARGER_TYPE_SPECIAL_500MA: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SLOW, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SLOW, attached); break; case MAX14577_CHARGER_TYPE_SPECIAL_1A: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_FAST, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_FAST, attached); break; case MAX14577_CHARGER_TYPE_NONE: diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c index c24abec5d06c..533e16a952b8 100644 --- a/drivers/extcon/extcon-max3355.c +++ b/drivers/extcon/extcon-max3355.c @@ -39,16 +39,16 @@ static irqreturn_t max3355_id_irq(int irq, void *dev_id) * As we don't have event for USB peripheral cable attached, * we simulate USB peripheral attach here. */ - extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, false); - extcon_set_cable_state_(data->edev, EXTCON_USB, true); + extcon_set_state_sync(data->edev, EXTCON_USB_HOST, false); + extcon_set_state_sync(data->edev, EXTCON_USB, true); } else { /* * ID = 0 means USB HOST cable attached. * As we don't have event for USB peripheral cable detached, * we simulate USB peripheral detach here. */ - extcon_set_cable_state_(data->edev, EXTCON_USB, false); - extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, true); + extcon_set_state_sync(data->edev, EXTCON_USB, false); + extcon_set_state_sync(data->edev, EXTCON_USB_HOST, true); } return IRQ_HANDLED; diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index f17cb76b567c..68dbcb814b2f 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -505,8 +505,8 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached); - extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached); + extcon_set_state_sync(info->edev, EXTCON_DOCK, attached); + extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached); goto out; case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */ dock_id = EXTCON_DOCK; @@ -514,8 +514,8 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ dock_id = EXTCON_DOCK; if (!attached) { - extcon_set_cable_state_(info->edev, EXTCON_USB, false); - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_USB, false); + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, false); } break; @@ -530,7 +530,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, attached); if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, dock_id, attached); + extcon_set_state_sync(info->edev, dock_id, attached); out: return 0; @@ -596,7 +596,7 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) attached); if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached); + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, attached); break; case MAX77693_MUIC_GND_AV_CABLE_LOAD: /* Audio Video Cable with load, PATH:AUDIO */ @@ -604,14 +604,14 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) attached); if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_USB, attached); - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_USB, attached); + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, attached); break; case MAX77693_MUIC_GND_MHL: case MAX77693_MUIC_GND_MHL_VB: /* MHL or MHL with USB/TA cable */ - extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached); + extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached); break; default: dev_err(info->dev, "failed to detect %s cable of gnd type\n", @@ -653,7 +653,7 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info, if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_JIG, attached); + extcon_set_state_sync(info->edev, EXTCON_JIG, attached); return 0; } @@ -807,10 +807,10 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) * - Support charging through micro-usb port without * data connection */ - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, attached); if (!cable_attached) - extcon_set_cable_state_(info->edev, + extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, cable_attached); break; } @@ -834,13 +834,13 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) * - Support charging through micro-usb port without * data connection. */ - extcon_set_cable_state_(info->edev, EXTCON_USB, + extcon_set_state_sync(info->edev, EXTCON_USB, attached); - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, attached); if (!cable_attached) - extcon_set_cable_state_(info->edev, EXTCON_DOCK, + extcon_set_state_sync(info->edev, EXTCON_DOCK, cable_attached); break; case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ @@ -869,9 +869,9 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_DOCK, + extcon_set_state_sync(info->edev, EXTCON_DOCK, attached); - extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, + extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached); break; } @@ -905,28 +905,28 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_USB, + extcon_set_state_sync(info->edev, EXTCON_USB, attached); - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, attached); break; case MAX77693_CHARGER_TYPE_DEDICATED_CHG: /* Only TA cable */ - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, attached); break; } break; case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_CDP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_CDP, attached); break; case MAX77693_CHARGER_TYPE_APPLE_500MA: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SLOW, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SLOW, attached); break; case MAX77693_CHARGER_TYPE_APPLE_1A_2A: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_FAST, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_FAST, attached); break; case MAX77693_CHARGER_TYPE_DEAD_BATTERY: diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index b188bd650efa..5d11fdf36e94 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -346,7 +346,7 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached); + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, attached); break; case MAX77843_MUIC_GND_MHL_VB: case MAX77843_MUIC_GND_MHL: @@ -356,7 +356,7 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached); + extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached); break; default: dev_err(info->dev, "failed to detect %s accessory(gnd:0x%x)\n", @@ -392,7 +392,7 @@ static int max77843_muic_jig_handler(struct max77843_muic_info *info, if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_JIG, attached); + extcon_set_state_sync(info->edev, EXTCON_JIG, attached); return 0; } @@ -486,8 +486,8 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_USB, attached); - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_USB, attached); + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, attached); break; case MAX77843_MUIC_CHG_DOWNSTREAM: @@ -497,7 +497,7 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_CDP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_CDP, attached); break; case MAX77843_MUIC_CHG_DEDICATED: @@ -507,7 +507,7 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, attached); break; case MAX77843_MUIC_CHG_SPECIAL_500MA: @@ -517,7 +517,7 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SLOW, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SLOW, attached); break; case MAX77843_MUIC_CHG_SPECIAL_1A: @@ -527,7 +527,7 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) if (ret < 0) return ret; - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_FAST, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_FAST, attached); break; case MAX77843_MUIC_CHG_GND: @@ -536,10 +536,10 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) /* Charger cable on MHL accessory is attach or detach */ if (gnd_type == MAX77843_MUIC_GND_MHL_VB) - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, true); else if (gnd_type == MAX77843_MUIC_GND_MHL) - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, false); break; case MAX77843_MUIC_CHG_NONE: diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 9a89320d09a8..4a0612fb9c07 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -331,11 +331,11 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info, switch (usb_type) { case MAX8997_USB_HOST: - extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached); + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, attached); break; case MAX8997_USB_DEVICE: - extcon_set_cable_state_(info->edev, EXTCON_USB, attached); - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_USB, attached); + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, attached); break; default: @@ -361,7 +361,7 @@ static int max8997_muic_handle_dock(struct max8997_muic_info *info, switch (cable_type) { case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD: case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON: - extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached); + extcon_set_state_sync(info->edev, EXTCON_DOCK, attached); break; default: dev_err(info->dev, "failed to detect %s dock device\n", @@ -384,7 +384,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, return ret; } - extcon_set_cable_state_(info->edev, EXTCON_JIG, attached); + extcon_set_state_sync(info->edev, EXTCON_JIG, attached); return 0; } @@ -406,7 +406,7 @@ static int max8997_muic_adc_handler(struct max8997_muic_info *info) return ret; break; case MAX8997_MUIC_ADC_MHL: - extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached); + extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached); break; case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF: case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON: @@ -489,19 +489,19 @@ static int max8997_muic_chg_handler(struct max8997_muic_info *info) } break; case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_CDP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_CDP, attached); break; case MAX8997_CHARGER_TYPE_DEDICATED_CHG: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, attached); break; case MAX8997_CHARGER_TYPE_500MA: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SLOW, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SLOW, attached); break; case MAX8997_CHARGER_TYPE_1A: - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_FAST, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_FAST, attached); break; default: diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index caff46c0e214..634ba70782de 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -61,7 +61,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb) if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) { if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) { palmas_usb->linkstat = PALMAS_USB_STATE_VBUS; - extcon_set_cable_state_(edev, EXTCON_USB, true); + extcon_set_state_sync(edev, EXTCON_USB, true); dev_info(palmas_usb->dev, "USB cable is attached\n"); } else { dev_dbg(palmas_usb->dev, @@ -70,7 +70,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb) } else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) { if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) { palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; - extcon_set_cable_state_(edev, EXTCON_USB, false); + extcon_set_state_sync(edev, EXTCON_USB, false); dev_info(palmas_usb->dev, "USB cable is detached\n"); } else { dev_dbg(palmas_usb->dev, @@ -98,7 +98,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) PALMAS_USB_ID_INT_LATCH_CLR, PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND); palmas_usb->linkstat = PALMAS_USB_STATE_ID; - extcon_set_cable_state_(edev, EXTCON_USB_HOST, true); + extcon_set_state_sync(edev, EXTCON_USB_HOST, true); dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); } else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) && (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) { @@ -106,17 +106,17 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) PALMAS_USB_ID_INT_LATCH_CLR, PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT); palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; - extcon_set_cable_state_(edev, EXTCON_USB_HOST, false); + extcon_set_state_sync(edev, EXTCON_USB_HOST, false); dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) && (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) { palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; - extcon_set_cable_state_(edev, EXTCON_USB_HOST, false); + extcon_set_state_sync(edev, EXTCON_USB_HOST, false); dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) && (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) { palmas_usb->linkstat = PALMAS_USB_STATE_ID; - extcon_set_cable_state_(edev, EXTCON_USB_HOST, true); + extcon_set_state_sync(edev, EXTCON_USB_HOST, true); dev_info(palmas_usb->dev, " USB-HOST cable is attached\n"); } @@ -137,10 +137,10 @@ static void palmas_gpio_id_detect(struct work_struct *work) id = gpiod_get_value_cansleep(palmas_usb->id_gpiod); if (id) { - extcon_set_cable_state_(edev, EXTCON_USB_HOST, false); + extcon_set_state_sync(edev, EXTCON_USB_HOST, false); dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); } else { - extcon_set_cable_state_(edev, EXTCON_USB_HOST, true); + extcon_set_state_sync(edev, EXTCON_USB_HOST, true); dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); } } diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c index 97e074d70eca..174c388739ea 100644 --- a/drivers/extcon/extcon-rt8973a.c +++ b/drivers/extcon/extcon-rt8973a.c @@ -398,9 +398,9 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info, return ret; /* Change the state of external accessory */ - extcon_set_cable_state_(info->edev, id, attached); + extcon_set_state_sync(info->edev, id, attached); if (id == EXTCON_USB) - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, attached); return 0; diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index df769a17e736..b22325688503 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c @@ -411,9 +411,9 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, return ret; /* Change the state of external accessory */ - extcon_set_cable_state_(info->edev, id, attached); + extcon_set_state_sync(info->edev, id, attached); if (id == EXTCON_USB) - extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, + extcon_set_state_sync(info->edev, EXTCON_CHG_USB_SDP, attached); return 0; diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 2512660dc4b9..a27d350f69e3 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -63,16 +63,16 @@ static void usb_extcon_detect_cable(struct work_struct *work) * As we don't have event for USB peripheral cable attached, * we simulate USB peripheral attach here. */ - extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, false); - extcon_set_cable_state_(info->edev, EXTCON_USB, true); + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false); + extcon_set_state_sync(info->edev, EXTCON_USB, true); } else { /* * ID = 0 means USB HOST cable attached. * As we don't have event for USB peripheral cable detached, * we simulate USB peripheral detach here. */ - extcon_set_cable_state_(info->edev, EXTCON_USB, false); - extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, true); + extcon_set_state_sync(info->edev, EXTCON_USB, false); + extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true); } } From 38085c987f52674c2cc84fa0c0788eb71137cb2b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 9 Sep 2016 14:48:47 -0700 Subject: [PATCH 292/343] extcon: Add support for qcom SPMI PMIC USB id detection hardware Some Qualcomm PMICs have a misc device that performs USB id pin detection via an interrupt. When the interrupt triggers, we should read the interrupt line to see if it has gone high or low. If the interrupt is low then the ID pin is grounded, and if the interrupt is high then the ID pin is being held high. Cc: Roger Quadros Signed-off-by: Stephen Boyd [cw00.choi: Edited the driver description and added the author information] Signed-off-by: Chanwoo Choi --- .../bindings/extcon/qcom,pm8941-misc.txt | 41 +++++ drivers/extcon/Kconfig | 6 + drivers/extcon/Makefile | 1 + drivers/extcon/extcon-qcom-spmi-misc.c | 170 ++++++++++++++++++ 4 files changed, 218 insertions(+) create mode 100644 Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt create mode 100644 drivers/extcon/extcon-qcom-spmi-misc.c diff --git a/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt new file mode 100644 index 000000000000..35383adb10f1 --- /dev/null +++ b/Documentation/devicetree/bindings/extcon/qcom,pm8941-misc.txt @@ -0,0 +1,41 @@ +Qualcomm's PM8941 USB ID Extcon device + +Some Qualcomm PMICs have a "misc" module that can be used to detect when +the USB ID pin has been pulled low or high. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,pm8941-misc"; + +- reg: + Usage: required + Value type: + Definition: Should contain the offset to the misc address space + +- interrupts: + Usage: required + Value type: + Definition: Should contain the usb id interrupt + +- interrupt-names: + Usage: required + Value type: + Definition: Should contain the string "usb_id" for the usb id interrupt + +Example: + + pmic { + usb_id: misc@900 { + compatible = "qcom,pm8941-misc"; + reg = <0x900>; + interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "usb_id"; + }; + } + + usb-controller { + extcon = <&usb_id>; + }; diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 3d89e60a3e71..04788d92ea52 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -96,6 +96,12 @@ config EXTCON_PALMAS Say Y here to enable support for USB peripheral and USB host detection by palmas usb. +config EXTCON_QCOM_SPMI_MISC + tristate "Qualcomm USB extcon support" + help + Say Y here to enable SPMI PMIC based USB cable detection + support on Qualcomm PMICs such as PM8941. + config EXTCON_RT8973A tristate "Richtek RT8973A EXTCON support" depends on I2C diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 972c813c375b..31a0a999c4fb 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o +obj-$(CONFIG_EXTCON_QCOM_SPMI_MISC) += extcon-qcom-spmi-misc.o obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c new file mode 100644 index 000000000000..ca957a5f4291 --- /dev/null +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -0,0 +1,170 @@ +/** + * extcon-qcom-spmi-misc.c - Qualcomm USB extcon driver to support USB ID + * detection based on extcon-usb-gpio.c. + * + * Copyright (C) 2016 Linaro, Ltd. + * Stephen Boyd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define USB_ID_DEBOUNCE_MS 5 /* ms */ + +struct qcom_usb_extcon_info { + struct extcon_dev *edev; + int irq; + struct delayed_work wq_detcable; + unsigned long debounce_jiffies; +}; + +static const unsigned int qcom_usb_extcon_cable[] = { + EXTCON_USB_HOST, + EXTCON_NONE, +}; + +static void qcom_usb_extcon_detect_cable(struct work_struct *work) +{ + bool id; + int ret; + struct qcom_usb_extcon_info *info = container_of(to_delayed_work(work), + struct qcom_usb_extcon_info, + wq_detcable); + + /* check ID and update cable state */ + ret = irq_get_irqchip_state(info->irq, IRQCHIP_STATE_LINE_LEVEL, &id); + if (ret) + return; + + extcon_set_state(info->edev, EXTCON_USB_HOST, !id); +} + +static irqreturn_t qcom_usb_irq_handler(int irq, void *dev_id) +{ + struct qcom_usb_extcon_info *info = dev_id; + + queue_delayed_work(system_power_efficient_wq, &info->wq_detcable, + info->debounce_jiffies); + + return IRQ_HANDLED; +} + +static int qcom_usb_extcon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct qcom_usb_extcon_info *info; + int ret; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->edev = devm_extcon_dev_allocate(dev, qcom_usb_extcon_cable); + if (IS_ERR(info->edev)) { + dev_err(dev, "failed to allocate extcon device\n"); + return -ENOMEM; + } + + ret = devm_extcon_dev_register(dev, info->edev); + if (ret < 0) { + dev_err(dev, "failed to register extcon device\n"); + return ret; + } + + info->debounce_jiffies = msecs_to_jiffies(USB_ID_DEBOUNCE_MS); + INIT_DELAYED_WORK(&info->wq_detcable, qcom_usb_extcon_detect_cable); + + info->irq = platform_get_irq_byname(pdev, "usb_id"); + if (info->irq < 0) + return info->irq; + + ret = devm_request_threaded_irq(dev, info->irq, NULL, + qcom_usb_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + pdev->name, info); + if (ret < 0) { + dev_err(dev, "failed to request handler for ID IRQ\n"); + return ret; + } + + platform_set_drvdata(pdev, info); + device_init_wakeup(dev, 1); + + /* Perform initial detection */ + qcom_usb_extcon_detect_cable(&info->wq_detcable.work); + + return 0; +} + +static int qcom_usb_extcon_remove(struct platform_device *pdev) +{ + struct qcom_usb_extcon_info *info = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&info->wq_detcable); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int qcom_usb_extcon_suspend(struct device *dev) +{ + struct qcom_usb_extcon_info *info = dev_get_drvdata(dev); + int ret = 0; + + if (device_may_wakeup(dev)) + ret = enable_irq_wake(info->irq); + + return ret; +} + +static int qcom_usb_extcon_resume(struct device *dev) +{ + struct qcom_usb_extcon_info *info = dev_get_drvdata(dev); + int ret = 0; + + if (device_may_wakeup(dev)) + ret = disable_irq_wake(info->irq); + + return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(qcom_usb_extcon_pm_ops, + qcom_usb_extcon_suspend, qcom_usb_extcon_resume); + +static const struct of_device_id qcom_usb_extcon_dt_match[] = { + { .compatible = "qcom,pm8941-misc", }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_usb_extcon_dt_match); + +static struct platform_driver qcom_usb_extcon_driver = { + .probe = qcom_usb_extcon_probe, + .remove = qcom_usb_extcon_remove, + .driver = { + .name = "extcon-pm8941-misc", + .pm = &qcom_usb_extcon_pm_ops, + .of_match_table = qcom_usb_extcon_dt_match, + }, +}; +module_platform_driver(qcom_usb_extcon_driver); + +MODULE_DESCRIPTION("QCOM USB ID extcon driver"); +MODULE_AUTHOR("Stephen Boyd "); +MODULE_LICENSE("GPL v2"); From 26c9cac402c491c552caf7483eda49aee095243a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 12 Sep 2016 21:20:22 +0300 Subject: [PATCH 293/343] usb: dwc3: of-simple: allow glues without clocks Instead of erroring out when we don't have clocks, let's just avoid any calls to the clk API. Tested-by: Steven J. Hill Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-of-simple.c | 46 +++++++++++++++++++------------ 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index ce9a070f4fe6..ed6bbb31ec90 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -36,36 +36,25 @@ struct dwc3_of_simple { int num_clocks; }; -static int dwc3_of_simple_probe(struct platform_device *pdev) +static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count) { - struct dwc3_of_simple *simple; - struct device *dev = &pdev->dev; + struct device *dev = simple->dev; struct device_node *np = dev->of_node; - - unsigned int count; - int ret; int i; - simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); - if (!simple) - return -ENOMEM; - - count = of_clk_get_parent_count(np); - if (!count) - return -ENOENT; - simple->num_clocks = count; + if (!count) + return 0; + simple->clks = devm_kcalloc(dev, simple->num_clocks, sizeof(struct clk *), GFP_KERNEL); if (!simple->clks) return -ENOMEM; - platform_set_drvdata(pdev, simple); - simple->dev = dev; - for (i = 0; i < simple->num_clocks; i++) { struct clk *clk; + int ret; clk = of_clk_get(np, i); if (IS_ERR(clk)) { @@ -88,6 +77,29 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) simple->clks[i] = clk; } + return 0; +} + +static int dwc3_of_simple_probe(struct platform_device *pdev) +{ + struct dwc3_of_simple *simple; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + int ret; + int i; + + simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); + if (!simple) + return -ENOMEM; + + platform_set_drvdata(pdev, simple); + simple->dev = dev; + + ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np)); + if (ret) + return ret; + ret = of_platform_populate(np, NULL, NULL, dev); if (ret) { for (i = 0; i < simple->num_clocks; i++) { From 050bc4e846af24e77af82d0fa5f718e0919d15a4 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 12 Sep 2016 15:19:41 +0200 Subject: [PATCH 294/343] scsi: introduce a quirk for false cache reporting Some SATA to USB bridges fail to cooperate with some drives resulting in no cache being present being reported to the host. That causes the host to skip sending a command to synchronize caches. That causes data loss when the drive is powered down. Signed-off-by: Oliver Neukum Reviewed-by: Martin K. Petersen Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 2 ++ drivers/usb/storage/scsiglue.c | 8 ++++++++ drivers/usb/storage/unusual_devs.h | 7 +++++++ drivers/usb/storage/usb.c | 6 +++++- include/linux/usb_usual.h | 2 ++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a4f4d693e2c1..edb7d5d9db83 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -4238,6 +4238,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted. u = IGNORE_UAS (don't bind to the uas driver); w = NO_WP_DETECT (don't test whether the medium is write-protected). + y = ALWAYS_SYNC (issue a SYNCHRONIZE_CACHE + even if the device claims no cache) Example: quirks=0419:aaf5:rl,0421:0433:rc user_debug= [KNL,ARM] diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 33eb923df892..8cd2926fb1fe 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -296,6 +296,14 @@ static int slave_configure(struct scsi_device *sdev) if (us->fflags & US_FL_BROKEN_FUA) sdev->broken_fua = 1; + /* Some even totally fail to indicate a cache */ + if (us->fflags & US_FL_ALWAYS_SYNC) { + /* don't read caching information */ + sdev->skip_ms_page_8 = 1; + sdev->skip_ms_page_3f = 1; + /* assume sync is needed */ + sdev->wce_default_on = 1; + } } else { /* diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index aa3539238848..af3c7eecff91 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -338,6 +338,13 @@ UNUSUAL_DEV( 0x046b, 0xff40, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_WP_DETECT), +/* Reported by Egbert Eich */ +UNUSUAL_DEV( 0x0480, 0xd010, 0x0100, 0x9999, + "Toshiba", + "External USB 3.0", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_ALWAYS_SYNC), + /* Patch submitted by Philipp Friedrich */ UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, "Kyocera", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index c8afd2d4c40b..2cba13a532cd 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -498,7 +498,8 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags) US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 | US_FL_INITIAL_READ10 | US_FL_WRITE_CACHE | US_FL_NO_ATA_1X | US_FL_NO_REPORT_OPCODES | - US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS); + US_FL_MAX_SECTORS_240 | US_FL_NO_REPORT_LUNS | + US_FL_ALWAYS_SYNC); p = quirks; while (*p) { @@ -581,6 +582,9 @@ void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags) case 'w': f |= US_FL_NO_WP_DETECT; break; + case 'y': + f |= US_FL_ALWAYS_SYNC; + break; /* Ignore unrecognized flag characters */ } } diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h index 245f57dbbb61..0aae1b2ee931 100644 --- a/include/linux/usb_usual.h +++ b/include/linux/usb_usual.h @@ -81,6 +81,8 @@ /* Sets max_sectors to 240 */ \ US_FLAG(NO_REPORT_LUNS, 0x10000000) \ /* Cannot handle REPORT_LUNS */ \ + US_FLAG(ALWAYS_SYNC, 0x20000000) \ + /* lies about caching, so always sync */ \ #define US_FLAG(name, value) US_FL_##name = value , enum { US_DO_ALL_FLAGS }; From b281dc630b41cd5d0c8600ffb3230ef9dc222b30 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 12 Sep 2016 21:24:58 +0300 Subject: [PATCH 295/343] usb: dwc3: of-simple: add compatible for Cavium Add necessary compatible flag for Cavium's DWC3 so dwc3-of-simple will probe. Tested-by: Steven J. Hill Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/dwc3-cavium.txt | 28 +++++++++++++++++++ drivers/usb/dwc3/dwc3-of-simple.c | 1 + 2 files changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/dwc3-cavium.txt diff --git a/Documentation/devicetree/bindings/usb/dwc3-cavium.txt b/Documentation/devicetree/bindings/usb/dwc3-cavium.txt new file mode 100644 index 000000000000..710b782ccf65 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/dwc3-cavium.txt @@ -0,0 +1,28 @@ +Cavium SuperSpeed DWC3 USB SoC controller + +Required properties: +- compatible: Should contain "cavium,octeon-7130-usb-uctl" + +Required child node: +A child node must exist to represent the core DWC3 IP block. The name of +the node is not important. The content of the node is defined in dwc3.txt. + +Example device node: + + uctl@1180069000000 { + compatible = "cavium,octeon-7130-usb-uctl"; + reg = <0x00011800 0x69000000 0x00000000 0x00000100>; + ranges; + #address-cells = <0x00000002>; + #size-cells = <0x00000002>; + refclk-frequency = <0x05f5e100>; + refclk-type-ss = "dlmc_ref_clk0"; + refclk-type-hs = "dlmc_ref_clk0"; + power = <0x00000002 0x00000002 0x00000001>; + xhci@1690000000000 { + compatible = "cavium,octeon-7130-xhci", "synopsys,dwc3"; + reg = <0x00016900 0x00000000 0x00000010 0x00000000>; + interrupt-parent = <0x00000010>; + interrupts = <0x00000009 0x00000004>; + }; + }; diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index ed6bbb31ec90..fe414e7a9c78 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -176,6 +176,7 @@ static const struct of_device_id of_dwc3_simple_match[] = { { .compatible = "qcom,dwc3" }, { .compatible = "rockchip,rk3399-dwc3" }, { .compatible = "xlnx,zynqmp-dwc3" }, + { .compatible = "cavium,octeon-7130-usb-uctl" }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, of_dwc3_simple_match); From e6be244a83211f3a9daaf5e29ee97fe0bf1efe5a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 12 Sep 2016 17:34:57 +0200 Subject: [PATCH 296/343] usb: gadget: uvc: add V4L2 dependency Building the UVC gadget into the kernel fails to build when CONFIG_VIDEO_V4L2 is a loadable module: drivers/usb/gadget/function/usb_f_uvc.o: In function `uvc_function_ep0_complete': uvc_configfs.c:(.text.uvc_function_ep0_complete+0x84): undefined reference to `v4l2_event_queue' drivers/usb/gadget/function/usb_f_uvc.o: In function `uvc_function_disable': uvc_configfs.c:(.text.uvc_function_disable+0x34): undefined reference to `v4l2_event_queue' Adding a dependency in USB_CONFIGFS_F_UVC (which is a bool symbol) make the 'select USB_F_UVC' statement turn the USB_F_UVC into 'm' whenever CONFIG_VIDEO_V4L2=m too, avoiding the link failure. Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2ea3fc3c41b9..8ad203296079 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -420,6 +420,7 @@ config USB_CONFIGFS_F_HID config USB_CONFIGFS_F_UVC bool "USB Webcam function" depends on USB_CONFIGFS + depends on VIDEO_V4L2 depends on VIDEO_DEV select VIDEOBUF2_VMALLOC select USB_F_UVC From 467d5c980709b262df288a0d0e7780f295c56882 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 12 Sep 2016 21:48:28 -0500 Subject: [PATCH 297/343] usb: musb: Implement session bit based runtime PM for musb-core We want to keep musb enabled always when the session bit is set. This simplifies the PM runtime and allows making it more generic across the various glue layers. So far the only exception to just following the session bit is host mode disconnect where the session bit stays set. In that case, just allow PM and let the PM runtime autoidle timeout deal with it. Signed-off-by: Tony Lindgren [b-liu@ti.com: changed using dev_dbg() to musb_dbg()] Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 66 ++++++++++++++++++++++++++++++++++++ drivers/usb/musb/musb_core.h | 1 + 2 files changed, 67 insertions(+) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 74fc3069cb42..7104604914ab 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1831,11 +1831,77 @@ static const struct attribute_group musb_attr_group = { .attrs = musb_attributes, }; +#define MUSB_QUIRK_B_INVALID_VBUS_91 (MUSB_DEVCTL_BDEVICE | \ + (2 << MUSB_DEVCTL_VBUS_SHIFT) | \ + MUSB_DEVCTL_SESSION) +#define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \ + MUSB_DEVCTL_SESSION) + +/* + * Check the musb devctl session bit to determine if we want to + * allow PM runtime for the device. In general, we want to keep things + * active when the session bit is set except after host disconnect. + * + * Only called from musb_irq_work. If this ever needs to get called + * elsewhere, proper locking must be implemented for musb->session. + */ +static void musb_pm_runtime_check_session(struct musb *musb) +{ + u8 devctl, s; + int error; + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + /* Handle session status quirks first */ + s = MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV | + MUSB_DEVCTL_HR; + switch (devctl & ~s) { + case MUSB_QUIRK_B_INVALID_VBUS_91: + if (musb->session) + break; + musb_dbg(musb, "Allow PM as device with invalid vbus: %02x", + devctl); + return; + case MUSB_QUIRK_A_DISCONNECT_19: + if (!musb->session) + break; + musb_dbg(musb, "Allow PM on possible host mode disconnect"); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); + musb->session = false; + return; + default: + break; + } + + /* No need to do anything if session has not changed */ + s = devctl & MUSB_DEVCTL_SESSION; + if (s == musb->session) + return; + + /* Block PM or allow PM? */ + if (s) { + musb_dbg(musb, "Block PM on active session: %02x", devctl); + error = pm_runtime_get_sync(musb->controller); + if (error < 0) + dev_err(musb->controller, "Could not enable: %i\n", + error); + } else { + musb_dbg(musb, "Allow PM with no session: %02x", devctl); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); + } + + musb->session = s; +} + /* Only used to provide driver mode change events */ static void musb_irq_work(struct work_struct *data) { struct musb *musb = container_of(data, struct musb, irq_work); + musb_pm_runtime_check_session(musb); + if (musb->xceiv->otg->state != musb->xceiv_old_state) { musb->xceiv_old_state = musb->xceiv->otg->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index b55a776b03eb..65288a53c19b 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -378,6 +378,7 @@ struct musb { u8 min_power; /* vbus for periph, in mA/2 */ int port_mode; /* MUSB_PORT_MODE_* */ + bool session; bool is_host; int a_wait_bcon; /* VBUS timeout in msecs */ From 2f3fd2c5bde1f94513c3dc311ae64494085ec371 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 12 Sep 2016 21:48:29 -0500 Subject: [PATCH 298/343] usb: musb: Prepare dsps glue layer for PM runtime support We want to be polling the state when nothing is connected. Let's change the polling logic in preparation for PM runtime support. Signed-off-by: Tony Lindgren [b-liu@ti.com: undo unnecessary line leading whitespace change] Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_dsps.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 2537179636db..ef955c7afd52 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -247,6 +247,10 @@ static void otg_timer(unsigned long _musb) spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->otg->state) { + case OTG_STATE_A_WAIT_VRISE: + mod_timer(&glue->timer, jiffies + + msecs_to_jiffies(wrp->poll_timeout)); + break; case OTG_STATE_A_WAIT_BCON: musb_writeb(musb->mregs, MUSB_DEVCTL, 0); skip_session = 1; @@ -338,7 +342,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; - del_timer(&glue->timer); + mod_timer(&glue->timer, jiffies + + msecs_to_jiffies(wrp->poll_timeout)); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); @@ -358,11 +363,17 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) if (musb->int_tx || musb->int_rx || musb->int_usb) ret |= musb_interrupt(musb); - /* Poll for ID change in OTG port mode */ - if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && - musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) + /* Poll for ID change and connect */ + switch (musb->xceiv->otg->state) { + case OTG_STATE_B_IDLE: + case OTG_STATE_A_WAIT_BCON: mod_timer(&glue->timer, jiffies + msecs_to_jiffies(wrp->poll_timeout)); + break; + default: + break; + } + out: spin_unlock_irqrestore(&musb->lock, flags); @@ -461,6 +472,9 @@ static int dsps_musb_init(struct musb *musb) musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } + mod_timer(&glue->timer, jiffies + + msecs_to_jiffies(glue->wrp->poll_timeout)); + return dsps_musb_dbg_init(musb, glue); } From ae909fe4f4e8718bd0cba6f89c9d19de3ead7a04 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 12 Sep 2016 21:48:30 -0500 Subject: [PATCH 299/343] usb: musb: Simplify PM runtime for 2430 glue layer With musb core now blocking PM based on the devctl status bit, we can remove related quirks from the 2430 glue layer and simplify PM runtime further. Lets's also use musb->controller instead of dev to make it clear we make the PM runtime calls for the core, not the glue layer. And we can now also lower the autoidle timeout. Signed-off-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/omap2430.c | 76 +++++-------------------------------- 1 file changed, 10 insertions(+), 66 deletions(-) diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 0b4cec940386..1ab6973d4f61 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -49,9 +49,6 @@ struct omap2430_glue { enum musb_vbus_id_status status; struct work_struct omap_musb_mailbox_work; struct device *control_otghs; - bool cable_connected; - bool enabled; - bool powered; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) @@ -141,45 +138,6 @@ static inline void omap2430_low_level_init(struct musb *musb) musb_writel(musb->mregs, OTG_FORCESTDBY, l); } -/* - * We can get multiple cable events so we need to keep track - * of the power state. Only keep power enabled if USB cable is - * connected and a gadget is started. - */ -static void omap2430_set_power(struct musb *musb, bool enabled, bool cable) -{ - struct device *dev = musb->controller; - struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - bool power_up; - int res; - - if (glue->enabled != enabled) - glue->enabled = enabled; - - if (glue->cable_connected != cable) - glue->cable_connected = cable; - - power_up = glue->enabled && glue->cable_connected; - if (power_up == glue->powered) { - dev_warn(musb->controller, "power state already %i\n", - power_up); - return; - } - - glue->powered = power_up; - - if (power_up) { - res = pm_runtime_get_sync(musb->controller); - if (res < 0) { - dev_err(musb->controller, "could not enable: %i", res); - glue->powered = false; - } - } else { - pm_runtime_mark_last_busy(musb->controller); - pm_runtime_put_autosuspend(musb->controller); - } -} - static int omap2430_musb_mailbox(enum musb_vbus_id_status status) { struct omap2430_glue *glue = _glue; @@ -203,21 +161,15 @@ static int omap2430_musb_mailbox(enum musb_vbus_id_status status) static void omap_musb_set_mailbox(struct omap2430_glue *glue) { struct musb *musb = glue_to_musb(glue); - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev); + struct musb_hdrc_platform_data *pdata = + dev_get_platdata(musb->controller); struct omap_musb_board_data *data = pdata->board_data; struct usb_otg *otg = musb->xceiv->otg; - bool cable_connected; - - cable_connected = ((glue->status == MUSB_ID_GROUND) || - (glue->status == MUSB_VBUS_VALID)); - - if (cable_connected) - omap2430_set_power(musb, glue->enabled, cable_connected); + pm_runtime_get_sync(musb->controller); switch (glue->status) { case MUSB_ID_GROUND: - dev_dbg(dev, "ID GND\n"); + dev_dbg(musb->controller, "ID GND\n"); otg->default_a = true; musb->xceiv->otg->state = OTG_STATE_A_IDLE; @@ -230,7 +182,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) break; case MUSB_VBUS_VALID: - dev_dbg(dev, "VBUS Connect\n"); + dev_dbg(musb->controller, "VBUS Connect\n"); otg->default_a = false; musb->xceiv->otg->state = OTG_STATE_B_IDLE; @@ -240,7 +192,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) case MUSB_ID_FLOAT: case MUSB_VBUS_OFF: - dev_dbg(dev, "VBUS Disconnect\n"); + dev_dbg(musb->controller, "VBUS Disconnect\n"); musb->xceiv->last_event = USB_EVENT_NONE; if (musb->gadget_driver) @@ -253,12 +205,10 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) USB_MODE_DISCONNECT); break; default: - dev_dbg(dev, "ID float\n"); + dev_dbg(musb->controller, "ID float\n"); } - - if (!cable_connected) - omap2430_set_power(musb, glue->enabled, cable_connected); - + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); atomic_notifier_call_chain(&musb->xceiv->notifier, musb->xceiv->last_event, NULL); } @@ -376,8 +326,6 @@ static void omap2430_musb_enable(struct musb *musb) if (!WARN_ON(!musb->phy)) phy_power_on(musb->phy); - omap2430_set_power(musb, true, glue->cable_connected); - switch (glue->status) { case MUSB_ID_GROUND: @@ -419,8 +367,6 @@ static void omap2430_musb_disable(struct musb *musb) if (glue->status != MUSB_UNKNOWN) omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DISCONNECT); - - omap2430_set_power(musb, false, glue->cable_connected); } static int omap2430_musb_exit(struct musb *musb) @@ -571,7 +517,7 @@ static int omap2430_probe(struct platform_device *pdev) pm_runtime_enable(glue->dev); pm_runtime_use_autosuspend(glue->dev); - pm_runtime_set_autosuspend_delay(glue->dev, 500); + pm_runtime_set_autosuspend_delay(glue->dev, 100); ret = platform_device_add(musb); if (ret) { @@ -591,11 +537,9 @@ err0: static int omap2430_remove(struct platform_device *pdev) { struct omap2430_glue *glue = platform_get_drvdata(pdev); - struct musb *musb = glue_to_musb(glue); pm_runtime_get_sync(glue->dev); platform_device_unregister(glue->musb); - omap2430_set_power(musb, false, false); pm_runtime_put_sync(glue->dev); pm_runtime_dont_use_autosuspend(glue->dev); pm_runtime_disable(glue->dev); From 65b3f50ed6fa121f2f8f0cb51c49bf038016ab46 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 12 Sep 2016 21:48:31 -0500 Subject: [PATCH 300/343] usb: musb: Add PM runtime support for MUSB DSPS glue layer We can now just use PM runtime autoidle support as musb core keeps things enabled when the devctl session bit is set. And there's no need for dsps_musb_try_idle() so let's just remove it. Note that as cppi41 dma is clocked by musb, this only makes PM work for dsps glue layer if CONFIG_MUSB_PIO_ONLY=y and cppi41.ko is unloaded. This will get fixed when cppi41.c has PM runtime implemented. Signed-off-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_dsps.c | 58 +++++++++++------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index ef955c7afd52..0f17d2140db6 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -145,43 +145,6 @@ static const struct debugfs_reg32 dsps_musb_regs[] = { { "mode", 0xe8 }, }; -static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - struct device *dev = musb->controller; - struct dsps_glue *glue = dev_get_drvdata(dev->parent); - - if (timeout == 0) - timeout = jiffies + msecs_to_jiffies(3); - - /* Never idle if active, or when VBUS timeout is not set as host */ - if (musb->is_active || (musb->a_wait_bcon == 0 && - musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON)) { - dev_dbg(musb->controller, "%s active, deleting timer\n", - usb_otg_state_string(musb->xceiv->otg->state)); - del_timer(&glue->timer); - glue->last_timer = jiffies; - return; - } - if (musb->port_mode != MUSB_PORT_MODE_DUAL_ROLE) - return; - - if (!musb->g.dev.driver) - return; - - if (time_after(glue->last_timer, timeout) && - timer_pending(&glue->timer)) { - dev_dbg(musb->controller, - "Longer idle timer already pending, ignoring...\n"); - return; - } - glue->last_timer = timeout; - - dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - usb_otg_state_string(musb->xceiv->otg->state), - jiffies_to_msecs(timeout - jiffies)); - mod_timer(&glue->timer, timeout); -} - /** * dsps_musb_enable - enable interrupts */ @@ -206,7 +169,6 @@ static void dsps_musb_enable(struct musb *musb) musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) mod_timer(&glue->timer, jiffies + msecs_to_jiffies(wrp->poll_timeout)); - dsps_musb_try_idle(musb, 0); } /** @@ -236,6 +198,11 @@ static void otg_timer(unsigned long _musb) u8 devctl; unsigned long flags; int skip_session = 0; + int err; + + err = pm_runtime_get_sync(dev); + if (err < 0) + dev_err(dev, "Poll could not pm_runtime_get: %i\n", err); /* * We poll because DSPS IP's won't expose several OTG-critical @@ -279,6 +246,9 @@ static void otg_timer(unsigned long _musb) break; } spin_unlock_irqrestore(&musb->lock, flags); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); } static irqreturn_t dsps_interrupt(int irq, void *hci) @@ -634,7 +604,6 @@ static struct musb_platform_ops dsps_ops = { .enable = dsps_musb_enable, .disable = dsps_musb_disable, - .try_idle = dsps_musb_try_idle, .set_mode = dsps_musb_set_mode, .recover = dsps_musb_recover, }; @@ -798,6 +767,8 @@ static int dsps_probe(struct platform_device *pdev) platform_set_drvdata(pdev, glue); pm_runtime_enable(&pdev->dev); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 200); ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) { @@ -809,11 +780,15 @@ static int dsps_probe(struct platform_device *pdev) if (ret) goto err3; + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + return 0; err3: - pm_runtime_put(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); err2: + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); return ret; } @@ -825,7 +800,8 @@ static int dsps_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); /* disable usbss clocks */ - pm_runtime_put(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; From 7cba17ec9adc8cf6c7e165adc831b4a73570a898 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 12 Sep 2016 21:48:32 -0500 Subject: [PATCH 301/343] musb: sunxi: Add support for platform_set_mode This allows run-time dr_mode switching support via the "mode" musb sysfs attribute. Signed-off-by: Hans de Goede Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/sunxi.c | 61 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index c6ee16660572..1408245be18e 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -74,6 +74,7 @@ #define SUNXI_MUSB_FL_HAS_SRAM 5 #define SUNXI_MUSB_FL_HAS_RESET 6 #define SUNXI_MUSB_FL_NO_CONFIGDATA 7 +#define SUNXI_MUSB_FL_PHY_MODE_PEND 8 /* Our read/write methods need access and do not get passed in a musb ref :| */ static struct musb *sunxi_musb; @@ -87,6 +88,7 @@ struct sunxi_glue { struct phy *phy; struct platform_device *usb_phy; struct usb_phy *xceiv; + enum phy_mode phy_mode; unsigned long flags; struct work_struct work; struct extcon_dev *extcon; @@ -140,6 +142,9 @@ static void sunxi_musb_work(struct work_struct *work) clear_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); } } + + if (test_and_clear_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags)) + phy_set_mode(glue->phy, glue->phy_mode); } static void sunxi_musb_set_vbus(struct musb *musb, int is_on) @@ -341,6 +346,50 @@ static void sunxi_musb_dma_controller_destroy(struct dma_controller *c) { } +static int sunxi_musb_set_mode(struct musb *musb, u8 mode) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + enum phy_mode new_mode; + + switch (mode) { + case MUSB_HOST: + new_mode = PHY_MODE_USB_HOST; + break; + case MUSB_PERIPHERAL: + new_mode = PHY_MODE_USB_DEVICE; + break; + case MUSB_OTG: + new_mode = PHY_MODE_USB_OTG; + break; + default: + dev_err(musb->controller->parent, + "Error requested mode not supported by this kernel\n"); + return -EINVAL; + } + + if (glue->phy_mode == new_mode) + return 0; + + if (musb->port_mode != MUSB_PORT_MODE_DUAL_ROLE) { + dev_err(musb->controller->parent, + "Error changing modes is only supported in dual role mode\n"); + return -EINVAL; + } + + if (musb->port1_status & USB_PORT_STAT_ENABLE) + musb_root_disconnect(musb); + + /* + * phy_set_mode may sleep, and we're called with a spinlock held, + * so let sunxi_musb_work deal with it. + */ + glue->phy_mode = new_mode; + set_bit(SUNXI_MUSB_FL_PHY_MODE_PEND, &glue->flags); + schedule_work(&glue->work); + + return 0; +} + /* * sunxi musb register layout * 0x00 - 0x17 fifo regs, 1 long per fifo @@ -568,6 +617,7 @@ static const struct musb_platform_ops sunxi_musb_ops = { .writew = sunxi_musb_writew, .dma_init = sunxi_musb_dma_controller_create, .dma_exit = sunxi_musb_dma_controller_destroy, + .set_mode = sunxi_musb_set_mode, .set_vbus = sunxi_musb_set_vbus, .pre_root_reset_end = sunxi_musb_pre_root_reset_end, .post_root_reset_end = sunxi_musb_post_root_reset_end, @@ -614,21 +664,28 @@ static int sunxi_musb_probe(struct platform_device *pdev) return -EINVAL; } + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + memset(&pdata, 0, sizeof(pdata)); switch (usb_get_dr_mode(&pdev->dev)) { #if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST case USB_DR_MODE_HOST: pdata.mode = MUSB_PORT_MODE_HOST; + glue->phy_mode = PHY_MODE_USB_HOST; break; #endif #if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_GADGET case USB_DR_MODE_PERIPHERAL: pdata.mode = MUSB_PORT_MODE_GADGET; + glue->phy_mode = PHY_MODE_USB_DEVICE; break; #endif #ifdef CONFIG_USB_MUSB_DUAL_ROLE case USB_DR_MODE_OTG: pdata.mode = MUSB_PORT_MODE_DUAL_ROLE; + glue->phy_mode = PHY_MODE_USB_OTG; break; #endif default: @@ -638,10 +695,6 @@ static int sunxi_musb_probe(struct platform_device *pdev) pdata.platform_ops = &sunxi_musb_ops; pdata.config = &sunxi_musb_hdrc_config; - glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); - if (!glue) - return -ENOMEM; - glue->dev = &pdev->dev; INIT_WORK(&glue->work, sunxi_musb_work); glue->host_nb.notifier_call = sunxi_musb_host_notifier; From d458fe9a71a14737d1d8ff50d33c9ccf0403f435 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 12 Sep 2016 21:48:33 -0500 Subject: [PATCH 302/343] usb: musb: da8xx: Use devm in probe Simplify things a bit by using devm functions where possible. Signed-off-by: David Lechner [b-liu@ti.com: fixed merge conflict] Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/da8xx.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 3c4dd1658f28..35d24496ea71 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -490,18 +490,16 @@ static int da8xx_probe(struct platform_device *pdev) struct da8xx_glue *glue; struct platform_device_info pinfo; struct clk *clk; + int ret; - int ret = -ENOMEM; - - glue = kzalloc(sizeof(*glue), GFP_KERNEL); + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); if (!glue) - goto err0; + return -ENOMEM; - clk = clk_get(&pdev->dev, "usb20"); + clk = devm_clk_get(&pdev->dev, "usb20"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get clock\n"); - ret = PTR_ERR(clk); - goto err3; + return PTR_ERR(clk); } ret = clk_enable(clk); @@ -558,12 +556,7 @@ err5: clk_disable(clk); err4: - clk_put(clk); -err3: - kfree(glue); - -err0: return ret; } @@ -574,8 +567,6 @@ static int da8xx_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->phy); clk_disable(glue->clk); - clk_put(glue->clk); - kfree(glue); return 0; } From 947c49afe41fca4c062a8a780b0e003115d7238c Mon Sep 17 00:00:00 2001 From: David Lechner Date: Mon, 12 Sep 2016 21:48:34 -0500 Subject: [PATCH 303/343] usb: musb: da8xx: Remove mach code Use the new phy-da8xx-usb driver to take the place of the mach code that pokes CFGCHIP2 in the da8xx musb glue driver. This unbreaks the driver. Signed-off-by: David Lechner Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/Kconfig | 2 +- drivers/usb/musb/da8xx.c | 135 +++++++++++++++------------------------ 2 files changed, 51 insertions(+), 86 deletions(-) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 886526b5fcdd..c73221a819c8 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -82,7 +82,7 @@ config USB_MUSB_DA8XX tristate "DA8xx/OMAP-L1x" depends on ARCH_DAVINCI_DA8XX depends on NOP_USB_XCEIV - depends on BROKEN + select PHY_DA8XX_USB config USB_MUSB_TUSB6010 tristate "TUSB6010" diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 35d24496ea71..2358f636e48c 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -30,13 +30,11 @@ #include #include #include +#include #include #include #include -#include -#include - #include "musb_core.h" /* @@ -80,60 +78,14 @@ #define DA8XX_MENTOR_CORE_OFFSET 0x400 -#define CFGCHIP2 IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG) - struct da8xx_glue { struct device *dev; struct platform_device *musb; - struct platform_device *phy; + struct platform_device *usb_phy; struct clk *clk; + struct phy *phy; }; -/* - * REVISIT (PM): we should be able to keep the PHY in low power mode most - * of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0 - * and, when in host mode, autosuspending idle root ports... PHY_PLLON - * (overriding SUSPENDM?) then likely needs to stay off. - */ - -static inline void phy_on(void) -{ - u32 cfgchip2 = __raw_readl(CFGCHIP2); - - /* - * Start the on-chip PHY and its PLL. - */ - cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN); - cfgchip2 |= CFGCHIP2_PHY_PLLON; - __raw_writel(cfgchip2, CFGCHIP2); - - pr_info("Waiting for USB PHY clock good...\n"); - while (!(__raw_readl(CFGCHIP2) & CFGCHIP2_PHYCLKGD)) - cpu_relax(); -} - -static inline void phy_off(void) -{ - u32 cfgchip2 = __raw_readl(CFGCHIP2); - - /* - * Ensure that USB 1.1 reference clock is not being sourced from - * USB 2.0 PHY. Otherwise do not power down the PHY. - */ - if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX) && - (cfgchip2 & CFGCHIP2_USB1SUSPENDM)) { - pr_warning("USB 1.1 clocked from USB 2.0 PHY -- " - "can't power it down\n"); - return; - } - - /* - * Power down the on-chip PHY. - */ - cfgchip2 |= CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN; - __raw_writel(cfgchip2, CFGCHIP2); -} - /* * Because we don't set CTRL.UINT, it's "important" to: * - not read/write INTRUSB/INTRUSBE (except during @@ -385,29 +337,29 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode) { - u32 cfgchip2 = __raw_readl(CFGCHIP2); + struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent); + enum phy_mode phy_mode; - cfgchip2 &= ~CFGCHIP2_OTGMODE; switch (musb_mode) { case MUSB_HOST: /* Force VBUS valid, ID = 0 */ - cfgchip2 |= CFGCHIP2_FORCE_HOST; + phy_mode = PHY_MODE_USB_HOST; break; case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */ - cfgchip2 |= CFGCHIP2_FORCE_DEVICE; + phy_mode = PHY_MODE_USB_DEVICE; break; case MUSB_OTG: /* Don't override the VBUS/ID comparators */ - cfgchip2 |= CFGCHIP2_NO_OVERRIDE; + phy_mode = PHY_MODE_USB_OTG; break; default: - dev_dbg(musb->controller, "Trying to set unsupported mode %u\n", musb_mode); + return -EINVAL; } - __raw_writel(cfgchip2, CFGCHIP2); - return 0; + return phy_set_mode(glue->phy, phy_mode); } static int da8xx_musb_init(struct musb *musb) { + struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent); void __iomem *reg_base = musb->ctrl_base; u32 rev; int ret = -ENODEV; @@ -425,32 +377,56 @@ static int da8xx_musb_init(struct musb *musb) goto fail; } + ret = clk_prepare_enable(glue->clk); + if (ret) { + dev_err(glue->dev, "failed to enable clock\n"); + goto fail; + } + setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); /* Reset the controller */ musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK); /* Start the on-chip PHY and its PLL. */ - phy_on(); + ret = phy_init(glue->phy); + if (ret) { + dev_err(glue->dev, "Failed to init phy.\n"); + goto err_phy_init; + } + + ret = phy_power_on(glue->phy); + if (ret) { + dev_err(glue->dev, "Failed to power on phy.\n"); + goto err_phy_power_on; + } msleep(5); /* NOTE: IRQs are in mixed mode, not bypass to pure MUSB */ - pr_debug("DA8xx OTG revision %08x, PHY %03x, control %02x\n", - rev, __raw_readl(CFGCHIP2), + pr_debug("DA8xx OTG revision %08x, control %02x\n", rev, musb_readb(reg_base, DA8XX_USB_CTRL_REG)); musb->isr = da8xx_musb_interrupt; return 0; + +err_phy_power_on: + phy_exit(glue->phy); +err_phy_init: + clk_disable_unprepare(glue->clk); fail: return ret; } static int da8xx_musb_exit(struct musb *musb) { + struct da8xx_glue *glue = dev_get_drvdata(musb->controller->parent); + del_timer_sync(&otg_workaround); - phy_off(); + phy_power_off(glue->phy); + phy_exit(glue->phy); + clk_disable_unprepare(glue->clk); usb_put_phy(musb->xceiv); @@ -502,10 +478,10 @@ static int da8xx_probe(struct platform_device *pdev) return PTR_ERR(clk); } - ret = clk_enable(clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto err4; + glue->phy = devm_phy_get(&pdev->dev, "usb-phy"); + if (IS_ERR(glue->phy)) { + dev_err(&pdev->dev, "failed to get phy\n"); + return PTR_ERR(glue->phy); } glue->dev = &pdev->dev; @@ -513,10 +489,10 @@ static int da8xx_probe(struct platform_device *pdev) pdata->platform_ops = &da8xx_ops; - glue->phy = usb_phy_generic_register(); - if (IS_ERR(glue->phy)) { - ret = PTR_ERR(glue->phy); - goto err5; + glue->usb_phy = usb_phy_generic_register(); + if (IS_ERR(glue->usb_phy)) { + dev_err(&pdev->dev, "failed to register usb_phy\n"); + return PTR_ERR(glue->usb_phy); } platform_set_drvdata(pdev, glue); @@ -542,22 +518,12 @@ static int da8xx_probe(struct platform_device *pdev) glue->musb = musb = platform_device_register_full(&pinfo); if (IS_ERR(musb)) { - ret = PTR_ERR(musb); dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); - goto err6; + usb_phy_generic_unregister(glue->usb_phy); + return PTR_ERR(musb); } return 0; - -err6: - usb_phy_generic_unregister(glue->phy); - -err5: - clk_disable(clk); - -err4: - - return ret; } static int da8xx_remove(struct platform_device *pdev) @@ -565,8 +531,7 @@ static int da8xx_remove(struct platform_device *pdev) struct da8xx_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); - usb_phy_generic_unregister(glue->phy); - clk_disable(glue->clk); + usb_phy_generic_unregister(glue->usb_phy); return 0; } From 48fed03b4b37f03f469333269fec50b2b41ed7fb Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 12 Sep 2016 21:48:35 -0500 Subject: [PATCH 304/343] usb: musb: am35x: fix error return code in am35x_probe() Fix to return a negative error code from the usb_phy_generic_register() error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/am35x.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index c14577dbedf7..50ca8052bc8e 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -510,8 +510,10 @@ static int am35x_probe(struct platform_device *pdev) pdata->platform_ops = &am35x_ops; glue->phy = usb_phy_generic_register(); - if (IS_ERR(glue->phy)) + if (IS_ERR(glue->phy)) { + ret = PTR_ERR(glue->phy); goto err7; + } platform_set_drvdata(pdev, glue); pinfo = am35x_dev_info; From 21b031fbd165398b8e3ba323a8a11f13f721be6f Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Mon, 12 Sep 2016 21:48:36 -0500 Subject: [PATCH 305/343] usb: musb: remove redundant stack buffers aDate is always the empty string, so entirely pointless. The aRevision formatting might as well be done as part of the pr_debug() call - that also avoids it altogether if pr_debug is compiled out. Signed-off-by: Rasmus Villemoes Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 7104604914ab..0319ea67e5a1 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1448,7 +1448,7 @@ static int musb_core_init(u16 musb_type, struct musb *musb) { u8 reg; char *type; - char aInfo[90], aRevision[32], aDate[12]; + char aInfo[90]; void __iomem *mbase = musb->mregs; int status = 0; int i; @@ -1482,7 +1482,6 @@ static int musb_core_init(u16 musb_type, struct musb *musb) pr_debug("%s: ConfigData=0x%02x (%s)\n", musb_driver_name, reg, aInfo); - aDate[0] = 0; if (MUSB_CONTROLLER_MHDRC == musb_type) { musb->is_multipoint = 1; type = "M"; @@ -1497,11 +1496,10 @@ static int musb_core_init(u16 musb_type, struct musb *musb) /* log release info */ musb->hwvers = musb_read_hwvers(mbase); - snprintf(aRevision, 32, "%d.%d%s", MUSB_HWVERS_MAJOR(musb->hwvers), - MUSB_HWVERS_MINOR(musb->hwvers), - (musb->hwvers & MUSB_HWVERS_RC) ? "RC" : ""); - pr_debug("%s: %sHDRC RTL version %s %s\n", - musb_driver_name, type, aRevision, aDate); + pr_debug("%s: %sHDRC RTL version %d.%d%s\n", + musb_driver_name, type, MUSB_HWVERS_MAJOR(musb->hwvers), + MUSB_HWVERS_MINOR(musb->hwvers), + (musb->hwvers & MUSB_HWVERS_RC) ? "RC" : ""); /* configure ep0 */ musb_configure_ep0(musb); From 46e75075baec1f8c239faa74f2549400e1caaa2f Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 13 Sep 2016 16:44:36 +0200 Subject: [PATCH 306/343] cdc-acm: cleanup debugging in submission path Actually make it retutn useful information. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index fef0d8fcd916..faab151d9fdc 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -368,17 +368,17 @@ static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) if (!test_and_clear_bit(index, &acm->read_urbs_free)) return 0; - dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index); - res = usb_submit_urb(acm->read_urbs[index], mem_flags); if (res) { if (res != -EPERM) { dev_err(&acm->data->dev, - "%s - usb_submit_urb failed: %d\n", - __func__, res); + "urb %d failed submission with %d\n", + index, res); } set_bit(index, &acm->read_urbs_free); return res; + } else { + dev_vdbg(&acm->data->dev, "submitted urb %d\n", index); } return 0; From efbe27b3cf604effa77ab7e23a359e64fee06998 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 13 Sep 2016 16:44:37 +0200 Subject: [PATCH 307/343] cdc-acm: cleaning up debug in data submission path Further cleanup making the debug messages more precise, useful and removing mere trace points. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index faab151d9fdc..15ffe389b86f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -415,8 +415,9 @@ static void acm_read_bulk_callback(struct urb *urb) unsigned long flags; int status = urb->status; - dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__, - rb->index, urb->actual_length); + dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n", + rb->index, urb->actual_length, + status); if (!acm->dev) { set_bit(rb->index, &acm->read_urbs_free); @@ -426,8 +427,6 @@ static void acm_read_bulk_callback(struct urb *urb) if (status) { set_bit(rb->index, &acm->read_urbs_free); - dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", - __func__, status); if ((status != -ENOENT) || (urb->actual_length == 0)) return; } @@ -462,8 +461,7 @@ static void acm_write_bulk(struct urb *urb) int status = urb->status; if (status || (urb->actual_length != urb->transfer_buffer_length)) - dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n", - __func__, + dev_vdbg(&acm->data->dev, "wrote len %d/%d, status %d\n", urb->actual_length, urb->transfer_buffer_length, status); @@ -478,8 +476,6 @@ static void acm_softint(struct work_struct *work) { struct acm *acm = container_of(work, struct acm, work); - dev_vdbg(&acm->data->dev, "%s\n", __func__); - tty_port_tty_wakeup(&acm->port); } @@ -674,7 +670,7 @@ static int acm_tty_write(struct tty_struct *tty, if (!count) return 0; - dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count); + dev_vdbg(&acm->data->dev, "%d bytes from tty layer\n", count); spin_lock_irqsave(&acm->write_lock, flags); wbn = acm_wb_alloc(acm); @@ -691,7 +687,7 @@ static int acm_tty_write(struct tty_struct *tty, } count = (count > acm->writesize) ? acm->writesize : count; - dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count); + dev_vdbg(&acm->data->dev, "writing %d bytes\n", count); memcpy(wb->buf, buf, count); wb->len = count; From f409440703f302791f7ee209c4214d22ff9b7ec6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 12 Sep 2016 14:19:17 +0100 Subject: [PATCH 308/343] USB: wusbcore: add in missing white space in error message text A dev_err message spans two lines and the literal string is missing a white space between words. Add the white space and reformat the message to not span multiple lines. Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/usb/wusbcore/cbaf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c index da1b872918b5..fb70cbef0671 100644 --- a/drivers/usb/wusbcore/cbaf.c +++ b/drivers/usb/wusbcore/cbaf.c @@ -610,8 +610,7 @@ static int cbaf_probe(struct usb_interface *iface, cbaf->usb_iface = usb_get_intf(iface); result = cbaf_check(cbaf); if (result < 0) { - dev_err(dev, "This device is not WUSB-CBAF compliant" - "and is not supported yet.\n"); + dev_err(dev, "This device is not WUSB-CBAF compliant and is not supported yet.\n"); goto error_check; } From 36ae6776e42de0f9c3d5039dad466642fa2341fa Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 11 Sep 2016 15:05:58 +0200 Subject: [PATCH 309/343] ezusb: constify local structures For structure types defined in the same file or local header files, find top-level static structure declarations that have the following properties: 1. Never reassigned. 2. Address never taken 3. Not passed to a top-level macro call 4. No pointer or array-typed field passed to a function or stored in a variable. Declare structures having all of these properties as const. Done using Coccinelle. Based on a suggestion by Joe Perches . Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ezusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/ezusb.c b/drivers/usb/misc/ezusb.c index 947811bc8126..837208f14f86 100644 --- a/drivers/usb/misc/ezusb.c +++ b/drivers/usb/misc/ezusb.c @@ -22,7 +22,7 @@ struct ezusb_fx_type { unsigned short max_internal_adress; }; -static struct ezusb_fx_type ezusb_fx1 = { +static const struct ezusb_fx_type ezusb_fx1 = { .cpucs_reg = 0x7F92, .max_internal_adress = 0x1B3F, }; From b175b38a0fa6767e1eae2e94b9d5f81d7342850a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 10 Sep 2016 11:54:03 +0000 Subject: [PATCH 310/343] usb: host: xhci-tegra: Fix error return code in tegra_xusb_probe() Fix to return error code -ENOMEM from the usb_create_shared_hcd() error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index d39b37be71f0..a59fafb4b329 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1116,6 +1116,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) tegra->hcd); if (!xhci->shared_hcd) { dev_err(&pdev->dev, "failed to create shared HCD\n"); + err = -ENOMEM; goto remove_usb2; } From 9cdd8e11c2a2f4b7553823240dc16a35ffa243e9 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 10 Sep 2016 11:53:42 +0000 Subject: [PATCH 311/343] USB: host: ohci-at91: fix non static symbol warning Fixes the following sparse warning: drivers/usb/host/ohci-at91.c:141:15: warning: symbol 'at91_dt_syscon_sfr' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 31102170c7a0..5b5880c0ae19 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -138,7 +138,7 @@ static void at91_stop_hc(struct platform_device *pdev) static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); -struct regmap *at91_dt_syscon_sfr(void) +static struct regmap *at91_dt_syscon_sfr(void) { struct regmap *regmap; From b44bbc46a8bbcd9c6bb1d167ca3f78d3aa5ee41d Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Tue, 13 Sep 2016 11:16:03 +0300 Subject: [PATCH 312/343] usb: core: setup dma_pfn_offset for USB devices and, interfaces If dma_pfn_offset is not inherited correctly from the host controller, it might result in sub-optimal configuration as bounce buffer limit might be set to less than optimal level. Consider the mass storage device case. USB storage driver creates a scsi host for the mass storage interface in drivers/usb/storage/usb.c The scsi host parent device is nothing but the the USB interface device. Now, __scsi_init_queue() calls scsi_calculate_bounce_limit() to find out and set the block layer bounce limit. scsi_calculate_bounce_limit() uses dma_max_pfn(host_dev) to get the bounce_limit. host_dev is nothing but the device representing the mass storage interface. If that device doesn't have the right dma_pfn_offset, then dma_max_pfn() is messed up and the bounce buffer limit is wrong. e.g. On Keystone 2 systems, dma_max_pfn() is 0x87FFFF and dma_mask_pfn is 0xFFFFF. Consider a mass storage use case: Without this patch, usb scsi host device (usb-storage) will get a dma_pfn_offset of 0 resulting in a dma_max_pfn() of 0xFFFFF within the scsi layer (scsi_calculate_bounce_limit()). This will result in bounce buffers being unnecessarily used. Hint: On 32-bit ARM platforms dma_max_pfn() = dma_mask_pfn + dma_pfn_offset Signed-off-by: Roger Quadros Acked-by: Arnd Bergmann Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 5 +++++ drivers/usb/core/usb.c | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 5ab5c1a81462..3a4707746157 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1859,7 +1859,12 @@ free_interfaces: intf->dev.bus = &usb_bus_type; intf->dev.type = &usb_if_device_type; intf->dev.groups = usb_interface_groups; + /* + * Please refer to usb_alloc_dev() to see why we set + * dma_mask and dma_pfn_offset. + */ intf->dev.dma_mask = dev->dev.dma_mask; + intf->dev.dma_pfn_offset = dev->dev.dma_pfn_offset; INIT_WORK(&intf->reset_ws, __usb_queue_reset_device); intf->minor = -1; device_initialize(&intf->dev); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 5e80697ef952..592151461017 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -440,7 +440,18 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->dev.bus = &usb_bus_type; dev->dev.type = &usb_device_type; dev->dev.groups = usb_device_groups; + /* + * Fake a dma_mask/offset for the USB device: + * We cannot really use the dma-mapping API (dma_alloc_* and + * dma_map_*) for USB devices but instead need to use + * usb_alloc_coherent and pass data in 'urb's, but some subsystems + * manually look into the mask/offset pair to determine whether + * they need bounce buffers. + * Note: calling dma_set_mask() on a USB device would set the + * mask for the entire HCD, so don't do that. + */ dev->dev.dma_mask = bus->controller->dma_mask; + dev->dev.dma_pfn_offset = bus->controller->dma_pfn_offset; set_dev_node(&dev->dev, dev_to_node(bus->controller)); dev->state = USB_STATE_ATTACHED; dev->lpm_disable_count = 1; From 54a2ec67f1db62a763f57b7f8f2e82874f5f358b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 9 Sep 2016 10:58:24 -0700 Subject: [PATCH 313/343] usb: ohci: Allow ohci on omap5 also With LPAE config we don't have omap3 or omap4 selected for omap5 variants. Signed-off-by: Tony Lindgren Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 2e710a4cca52..0b80cee30da4 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -472,7 +472,7 @@ config USB_OHCI_HCD_AT91 config USB_OHCI_HCD_OMAP3 tristate "OHCI support for OMAP3 and later chips" - depends on (ARCH_OMAP3 || ARCH_OMAP4) + depends on (ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5) default y ---help--- Enables support for the on-chip OHCI controller on From 66b76dbe37df88b250ffdac186adba3e5dc24631 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 9 Jul 2016 14:16:38 +0000 Subject: [PATCH 314/343] usb: chipidea: udc: move write barrier into hw_ep_prime Since there should be a write barrier before every call of hw_ep_prime we could move it into hw_ep_prime. Signed-off-by: Stefan Wahren Signed-off-by: Peter Chen --- drivers/usb/chipidea/udc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b93356834bb5..b0c4ae1cd206 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -188,6 +188,9 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl) { int n = hw_ep_bit(num, dir); + /* Synchronize before ep prime */ + wmb(); + if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num))) return -EAGAIN; @@ -506,8 +509,6 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) hwep->qh.ptr->cap |= mul << __ffs(QH_MULT); } - wmb(); /* synchronize before ep prime */ - ret = hw_ep_prime(ci, hwep->num, hwep->dir, hwep->type == USB_ENDPOINT_XFER_CONTROL); done: @@ -534,9 +535,6 @@ static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep, hwep->qh.ptr->td.token &= cpu_to_le32(~(TD_STATUS_HALTED | TD_STATUS_ACTIVE)); - /* Synchronize before ep prime */ - wmb(); - return hw_ep_prime(ci, hwep->num, hwep->dir, hwep->type == USB_ENDPOINT_XFER_CONTROL); } From 8007eb4e1824e52483ad99fb229fc56e6a73cec6 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 9 Jul 2016 14:16:39 +0000 Subject: [PATCH 315/343] usb: chipidea: udc: Don't flush endpoint fifo twice The endpoint fifo is already flushed in _ep_nuke so there is no need to flush it twice. Signed-off-by: Stefan Wahren Signed-off-by: Peter Chen --- drivers/usb/chipidea/udc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b0c4ae1cd206..a66a47a9d2a7 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -121,7 +121,6 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir) */ static int hw_ep_disable(struct ci_hdrc *ci, int num, int dir) { - hw_ep_flush(ci, num, dir); hw_write(ci, OP_ENDPTCTRL + num, dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); return 0; From 5de97f8bd74dd87d8856f17b585a7c221b535969 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Wed, 20 Jul 2016 16:02:40 +0800 Subject: [PATCH 316/343] doc: usb: usbmisc-imx: add imx7d compatible string Add compatible string for imx7d-usbmisc. Acked-by: Rob Herring Signed-off-by: Li Jun Signed-off-by: Peter Chen --- Documentation/devicetree/bindings/usb/usbmisc-imx.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt index 3539d4e7d23e..f1e27faf528e 100644 --- a/Documentation/devicetree/bindings/usb/usbmisc-imx.txt +++ b/Documentation/devicetree/bindings/usb/usbmisc-imx.txt @@ -6,6 +6,7 @@ Required properties: "fsl,imx6q-usbmisc" for imx6q "fsl,vf610-usbmisc" for Vybrid vf610 "fsl,imx6sx-usbmisc" for imx6sx + "fsl,imx7d-usbmisc" for imx7d - reg: Should contain registers location and length Examples: From e5b3253dcc8c6a2cb2b13916e77afe9fdfe55d27 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Wed, 20 Jul 2016 16:02:41 +0800 Subject: [PATCH 317/343] doc: usb: ci-hdrc-usb2: add property over-current-active-high Adding over-current-active-high to indicate the over current flag is high active as typically we use active low for over current polarity. Signed-off-by: Li Jun Signed-off-by: Peter Chen Acked-by: Rob Herring --- Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index 341dc67f3472..0e03344e2e8b 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -81,6 +81,8 @@ i.mx specific properties - fsl,usbmisc: phandler of non-core register device, with one argument that indicate usb controller index - disable-over-current: disable over current detect +- over-current-active-high: over current signal polarity is high active, + typically over current signal polarity is low active. - external-vbus-divider: enables off-chip resistor divider for Vbus Example: From 9dba516ed282e3d16481051be547b54caa312029 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Wed, 20 Jul 2016 16:02:42 +0800 Subject: [PATCH 318/343] usb: chipidea: imx: set over current polarity per dts setting imx usb over current polarity is low active by default, with over-current-active-high property added, user can config it to be high active. Meanwhile keep this setting unchanged for existing platforms so new platform must set the right value for active low by its usbmisc init function if over current is enabled. Signed-off-by: Li Jun Signed-off-by: Peter Chen --- drivers/usb/chipidea/ci_hdrc_imx.c | 3 +++ drivers/usb/chipidea/ci_hdrc_imx.h | 1 + drivers/usb/chipidea/usbmisc_imx.c | 22 +++++++++++++++++----- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index dedc33e589f4..099179457f60 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -140,6 +140,9 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) if (of_find_property(np, "disable-over-current", NULL)) data->disable_oc = 1; + if (of_find_property(np, "over-current-active-high", NULL)) + data->oc_polarity = 1; + if (of_find_property(np, "external-vbus-divider", NULL)) data->evdo = 1; diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 635717e9354a..409aa5ca8dda 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -17,6 +17,7 @@ struct imx_usbmisc_data { int index; unsigned int disable_oc:1; /* over current detect disabled */ + unsigned int oc_polarity:1; /* over current polarity if oc enabled */ unsigned int evdo:1; /* set external vbus divider option */ }; diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index ab8b027e8cc8..20d02a5e418d 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -56,6 +56,7 @@ #define MX6_BM_NON_BURST_SETTING BIT(1) #define MX6_BM_OVER_CUR_DIS BIT(7) +#define MX6_BM_OVER_CUR_POLARITY BIT(8) #define MX6_BM_WAKEUP_ENABLE BIT(10) #define MX6_BM_ID_WAKEUP BIT(16) #define MX6_BM_VBUS_WAKEUP BIT(17) @@ -266,11 +267,14 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data) spin_lock_irqsave(&usbmisc->lock, flags); + reg = readl(usbmisc->base + data->index * 4); if (data->disable_oc) { - reg = readl(usbmisc->base + data->index * 4); - writel(reg | MX6_BM_OVER_CUR_DIS, - usbmisc->base + data->index * 4); + reg |= MX6_BM_OVER_CUR_DIS; + } else if (data->oc_polarity == 1) { + /* High active */ + reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY); } + writel(reg, usbmisc->base + data->index * 4); /* SoC non-burst setting */ reg = readl(usbmisc->base + data->index * 4); @@ -365,10 +369,14 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data) return -EINVAL; spin_lock_irqsave(&usbmisc->lock, flags); + reg = readl(usbmisc->base); if (data->disable_oc) { - reg = readl(usbmisc->base); - writel(reg | MX6_BM_OVER_CUR_DIS, usbmisc->base); + reg |= MX6_BM_OVER_CUR_DIS; + } else if (data->oc_polarity == 1) { + /* High active */ + reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY); } + writel(reg, usbmisc->base); reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2); reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK; @@ -492,6 +500,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = { .compatible = "fsl,imx6ul-usbmisc", .data = &imx6sx_usbmisc_ops, }, + { + .compatible = "fsl,imx7d-usbmisc", + .data = &imx7d_usbmisc_ops, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids); From c6ee9f2345a2d95a986309a6486ae780f563230a Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Thu, 11 Aug 2016 17:19:13 +0000 Subject: [PATCH 319/343] usb: chipidea: udc: Use direction flags consequently This driver make assumptions about the value of the direction flags. So better use them in comparisons to improve the readability. Signed-off-by: Stefan Wahren Signed-off-by: Peter Chen --- drivers/usb/chipidea/udc.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index a66a47a9d2a7..c1eea62ab998 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -59,7 +59,7 @@ ctrl_endpt_in_desc = { */ static inline int hw_ep_bit(int num, int dir) { - return num + (dir ? 16 : 0); + return num + ((dir == TX) ? 16 : 0); } static inline int ep_to_bit(struct ci_hdrc *ci, int n) @@ -122,7 +122,7 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir) static int hw_ep_disable(struct ci_hdrc *ci, int num, int dir) { hw_write(ci, OP_ENDPTCTRL + num, - dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); + (dir == TX) ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); return 0; } @@ -138,7 +138,7 @@ static int hw_ep_enable(struct ci_hdrc *ci, int num, int dir, int type) { u32 mask, data; - if (dir) { + if (dir == TX) { mask = ENDPTCTRL_TXT; /* type */ data = type << __ffs(mask); @@ -170,7 +170,7 @@ static int hw_ep_enable(struct ci_hdrc *ci, int num, int dir, int type) */ static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir) { - u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; + u32 mask = (dir == TX) ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; return hw_read(ci, OP_ENDPTCTRL + num, mask) ? 1 : 0; } @@ -220,8 +220,8 @@ static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value) do { enum ci_hw_regs reg = OP_ENDPTCTRL + num; - u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; - u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; + u32 mask_xs = (dir == TX) ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; + u32 mask_xr = (dir == TX) ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; /* data toggle - reserved for EP0 but it's in ESS */ hw_write(ci, reg, mask_xs|mask_xr, @@ -587,7 +587,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) } if (remaining_length) { - if (hwep->dir) { + if (hwep->dir == TX) { hwreq->req.status = -EPROTO; break; } @@ -1048,9 +1048,9 @@ __acquires(ci->lock) if (req.wLength != 0) break; num = le16_to_cpu(req.wIndex); - dir = num & USB_ENDPOINT_DIR_MASK; + dir = (num & USB_ENDPOINT_DIR_MASK) ? TX : RX; num &= USB_ENDPOINT_NUMBER_MASK; - if (dir) /* TX */ + if (dir == TX) num += ci->hw_ep_max / 2; if (!ci->ci_hw_ep[num].wedge) { spin_unlock(&ci->lock); @@ -1100,9 +1100,9 @@ __acquires(ci->lock) if (req.wLength != 0) break; num = le16_to_cpu(req.wIndex); - dir = num & USB_ENDPOINT_DIR_MASK; + dir = (num & USB_ENDPOINT_DIR_MASK) ? TX : RX; num &= USB_ENDPOINT_NUMBER_MASK; - if (dir) /* TX */ + if (dir == TX) num += ci->hw_ep_max / 2; spin_unlock(&ci->lock); From c744a0db756b34c7e2b60100bcfc58beb6b68c99 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 15 Aug 2016 16:09:07 +0200 Subject: [PATCH 320/343] usb: chipidea: host: disable io watchdog The Chipidea EHCI core seems to behave sanely and doesn't need the IO watchdog. This kills off 10 non-deferrable wakeup events per second when the controller is otherwise idle. Signed-off-by: Lucas Stach Tested-by: Stefan Agner Signed-off-by: Peter Chen --- drivers/usb/chipidea/host.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 053bac9d983c..96ae69502c86 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -81,12 +81,15 @@ static int ehci_ci_reset(struct usb_hcd *hcd) { struct device *dev = hcd->self.controller; struct ci_hdrc *ci = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); int ret; ret = ehci_setup(hcd); if (ret) return ret; + ehci->need_io_watchdog = 0; + ci_platform_configure(ci); return ret; From 382c1b38d8e70b2fe239c96bb9137c10f3229ba3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 8 Sep 2016 09:34:30 -0300 Subject: [PATCH 321/343] usb: chipidea: udc: Use dma_pool_zalloc() We can make the code simpler by using dma_pool_zalloc() instead of calling dma_pool_alloc() and then a memset(). Signed-off-by: Fabio Estevam Signed-off-by: Peter Chen --- drivers/usb/chipidea/udc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index c1eea62ab998..a0b208dfb959 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1677,12 +1677,10 @@ static int init_eps(struct ci_hdrc *ci) usb_ep_set_maxpacket_limit(&hwep->ep, (unsigned short)~0); INIT_LIST_HEAD(&hwep->qh.queue); - hwep->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL, - &hwep->qh.dma); + hwep->qh.ptr = dma_pool_zalloc(ci->qh_pool, GFP_KERNEL, + &hwep->qh.dma); if (hwep->qh.ptr == NULL) retval = -ENOMEM; - else - memset(hwep->qh.ptr, 0, sizeof(*hwep->qh.ptr)); /* * set up shorthands for ep0 out and in endpoints, From 58001effe172f300d558dffbd723c8521b9404f2 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 8 Sep 2016 09:34:31 -0300 Subject: [PATCH 322/343] usb: chipidea: udc: Fit into a single line No need to split the dma_pool_zalloc() line into two as it can perfectly fit into a single line. Signed-off-by: Fabio Estevam Signed-off-by: Peter Chen --- drivers/usb/chipidea/udc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index a0b208dfb959..22534a1622d9 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -350,8 +350,7 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq, if (node == NULL) return -ENOMEM; - node->ptr = dma_pool_zalloc(hwep->td_pool, GFP_ATOMIC, - &node->dma); + node->ptr = dma_pool_zalloc(hwep->td_pool, GFP_ATOMIC, &node->dma); if (node->ptr == NULL) { kfree(node); return -ENOMEM; From e74e83724808b72173b557bd8008202109fb6091 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 8 Sep 2016 09:34:32 -0300 Subject: [PATCH 323/343] usb: chipidea: udc: Use the preferred form for passing a size of a struct According to Documentation/CodingStyle: "The preferred form for passing a size of a struct is the following: p = kmalloc(sizeof(*p), ...); " , so do as suggested to improve readability. Signed-off-by: Fabio Estevam Signed-off-by: Peter Chen --- drivers/usb/chipidea/udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 22534a1622d9..661f43fe0f9e 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1993,7 +1993,7 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci) if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC)) return -ENXIO; - rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL); + rdrv = devm_kzalloc(ci->dev, sizeof(*rdrv), GFP_KERNEL); if (!rdrv) return -ENOMEM; From 78489c7c48d462c2a4fa9f388dd091f829573b64 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Mon, 22 Aug 2016 21:24:22 +0200 Subject: [PATCH 324/343] phy-twl4030-usb: better handle musb_mailbox() failure setting twl->linkstat = MUSB_UNKNOWN upon error in musb_mailbox as introduced in commit 12b7db2bf8b8 ("usb: musb: Return error value from musb_mailbox") causes twl4030_usb_irq() to not detect a state change form cable connected to cable disconnected after such an error so that pm_runtime_put_autosuspend() will not be called and the usage counter gets unbalanced. Such errors happen e.g. if the omap2430 module is not (yet) loaded during plug/unplug events. This patch introduces a flag instead that indicates whether there is information for the musb_mailbox pending and calls musb_mailbox() if that flag is set. Signed-off-by: Andreas Kemnade Tested-by: Tony Lindgren Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-twl4030-usb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index d9b10a39a2cf..81067b461098 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -172,6 +172,7 @@ struct twl4030_usb { int irq; enum musb_vbus_id_status linkstat; bool vbus_supplied; + bool musb_mailbox_pending; struct delayed_work id_workaround_work; }; @@ -569,9 +570,12 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) pm_runtime_mark_last_busy(twl->dev); pm_runtime_put_autosuspend(twl->dev); } + twl->musb_mailbox_pending = true; + } + if (twl->musb_mailbox_pending) { err = musb_mailbox(status); - if (err) - twl->linkstat = MUSB_UNKNOWN; + if (!err) + twl->musb_mailbox_pending = false; } /* don't schedule during sleep - irq works right then */ @@ -676,6 +680,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) twl->irq = platform_get_irq(pdev, 0); twl->vbus_supplied = false; twl->linkstat = MUSB_UNKNOWN; + twl->musb_mailbox_pending = false; twl->phy.dev = twl->dev; twl->phy.label = "twl4030"; From b78ea84a7d45b9e5ad2eee429a2140065a39d755 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Thu, 25 Aug 2016 00:27:59 +0200 Subject: [PATCH 325/343] phy-twl4030-usb: initialize charging-related stuff via pm_runtime twl4030_phy_power_on() initializes some bits which are required for charging. As they are not set in twl4030_usb_runtime_resume() a call to pm_runtime_get_sync() is not sufficient to enable charging. This patch moves the initialization to twl4030_usb_runtime_resume() so everything needed for charging is initialized upon pm_runtime_get_sync(). That also gives improved possibilities to debug problems in that area because the relevant parts can be checked separately. Charging can be enabled without having the musb subsystem active. As a side effect this hides some bugs in musb which causes unbalanced calls to phy_power_off()/phy_power_on() so that phy->power_count becomes -1. The result is that e.g. the GTA04 phone (dm3730 + twl4030) works finally as a usb gadget again and charging is working. Signed-off-by: Andreas Kemnade Acked-by: Tony Lindgren Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-twl4030-usb.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index 81067b461098..87e6334eab93 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -440,6 +440,17 @@ static int __maybe_unused twl4030_usb_runtime_resume(struct device *dev) (PHY_CLK_CTRL_CLOCKGATING_EN | PHY_CLK_CTRL_CLK32K_EN)); + twl4030_i2c_access(twl, 1); + twl4030_usb_set_mode(twl, twl->usb_mode); + if (twl->usb_mode == T2_USB_MODE_ULPI) + twl4030_i2c_access(twl, 0); + /* + * According to the TPS65950 TRM, there has to be at least 50ms + * delay between setting POWER_CTRL_OTG_ENAB and enabling charging + * so wait here so that a fully enabled phy can be expected after + * resume + */ + msleep(50); return 0; } @@ -460,11 +471,6 @@ static int twl4030_phy_power_on(struct phy *phy) dev_dbg(twl->dev, "%s\n", __func__); pm_runtime_get_sync(twl->dev); - twl4030_i2c_access(twl, 1); - twl4030_usb_set_mode(twl, twl->usb_mode); - if (twl->usb_mode == T2_USB_MODE_ULPI) - twl4030_i2c_access(twl, 0); - twl->linkstat = MUSB_UNKNOWN; schedule_delayed_work(&twl->id_workaround_work, HZ); return 0; From 5ee05309e7b394b4fe1ccc041f333ba0aa1caa50 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 14 Sep 2016 14:17:41 +0200 Subject: [PATCH 326/343] MAINTAINERS: add tree entry for USB Serial Add tree entry for USB Serial. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index b3e939563402..94e97a514157 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12267,6 +12267,7 @@ F: drivers/net/usb/rtl8150.c USB SERIAL SUBSYSTEM M: Johan Hovold L: linux-usb@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial.git S: Maintained F: Documentation/usb/usb-serial.txt F: drivers/usb/serial/ From eeb7df270f1c4629b52fc1f98035fe9e7fe63df2 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 16 Sep 2016 12:19:07 +0530 Subject: [PATCH 327/343] include: extcon: Fix compilation error caused because of incomplete merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following compilation error caused due to incomplete merge. This is observed if CONFIG_EXTCON is not set. In file included from ./include/linux/mfd/palmas.h:23:0, from drivers/input/misc/palmas-pwrbutton.c:22: ./include/linux/extcon.h: In function ‘extcon_sync’: ./include/linux/extcon.h:361:1: error: expected declaration specifiers before ‘<<’ token ./include/linux/extcon.h:370:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token ./include/linux/extcon.h:376:1: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘>>’ token ./include/linux/extcon.h:381:1: error: expected declaration specifiers before ‘<<’ token ./include/linux/extcon.h:390:1: error: expected declaration specifiers or ‘...’ before ‘==’ token ./include/linux/extcon.h:476:11: warning: ‘struct extcon_specific_cable_nb’ declared inside parameter list [enabled by default] ./include/linux/extcon.h:476:11: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default] ./include/linux/extcon.h:474:19: error: storage class specified for parameter ‘extcon_register_interest’ ./include/linux/extcon.h:474:19: warning: parameter ‘extcon_register_interest’ declared ‘inline’ [enabled by default] ./include/linux/extcon.h:477:1: warning: ‘always_inline’ attribute ignored [-Wattributes] ./include/linux/extcon.h:474:19: error: ‘no_instrument_function’ attribute applies only to functions ./include/linux/extcon.h:477:1: error: expected ‘;’, ‘,’ or ‘)’ before ‘{’ token Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Greg Kroah-Hartman --- include/linux/extcon.h | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 2b9f15156115..b871c0cb1f02 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -358,8 +358,6 @@ static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id } static inline int extcon_sync(struct extcon_dev *edev, unsigned int id) -<<<<<<< HEAD -======= { return 0; } @@ -373,50 +371,23 @@ static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val) ->>>>>>> next { return 0; } -<<<<<<< HEAD -static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, - unsigned int prop, - union extcon_property_value *prop_val) -{ - return 0; -} -static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, - unsigned int prop, -======= -static inline int extcon_set_property_sync(struct extcon_dev *edev, - unsigned int id, unsigned int prop, ->>>>>>> next - union extcon_property_value prop_val) -{ - return 0; -} - -<<<<<<< HEAD static inline int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, unsigned int prop, union extcon_property_value prop_val) -======= -static inline int extcon_get_property_capability(struct extcon_dev *edev, - unsigned int id, unsigned int prop) ->>>>>>> next { return 0; } -<<<<<<< HEAD static inline int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop) { return 0; } -======= ->>>>>>> next static inline int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, unsigned int prop) { From 3a383cc0b8cc33af188fe2062b6ba5a69af25fa7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 19 Sep 2016 11:05:43 +0200 Subject: [PATCH 328/343] Revert "usb: gadget: NCM: Protect dev->port_usb using dev->lock" This reverts commit c9ffc78745f89e300fe704348dd8e6800acf4d18 as it was reported to be broken. Cc: Felipe Balbi Cc: Jim Baxter Cc: Harish Jenny K N Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/u_ether.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 8cb08033b7c1..9c8c9ed1dc9e 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -553,16 +553,14 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, spin_lock_irqsave(&dev->lock, flags); if (dev->port_usb) skb = dev->wrap(dev->port_usb, skb); + spin_unlock_irqrestore(&dev->lock, flags); if (!skb) { /* Multi frame CDC protocols may store the frame for * later which is not a dropped frame. */ if (dev->port_usb && - dev->port_usb->supports_multi_frame) { - spin_unlock_irqrestore(&dev->lock, flags); + dev->port_usb->supports_multi_frame) goto multiframe; - } - spin_unlock_irqrestore(&dev->lock, flags); goto drop; } } @@ -580,7 +578,6 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, req->zero = 0; else req->zero = 1; - spin_unlock_irqrestore(&dev->lock, flags); /* use zlp framing on tx for strict CDC-Ether conformance, * though any robust network rx path ignores extra padding. From 2ad9d544f2497a7bf239c34bd2b86fd19683dbb5 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 20 Sep 2016 15:45:42 +0200 Subject: [PATCH 329/343] cdc-acm: hardening against malicious devices This should fix the last holes against malicious devices still open in cdc-acm. It cannot go into stable due to the introduction of the common parser. The fix for stable already merged also covers the problems this patch fixes. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 15ffe389b86f..78f0f85bebdc 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1179,6 +1179,9 @@ static int acm_probe(struct usb_interface *intf, return -EINVAL; } + if (!intf->cur_altsetting) + return -EINVAL; + if (!buflen) { if (intf->cur_altsetting->endpoint && intf->cur_altsetting->endpoint->extralen && @@ -1232,6 +1235,8 @@ static int acm_probe(struct usb_interface *intf, dev_dbg(&intf->dev, "no interfaces\n"); return -ENODEV; } + if (!data_interface->cur_altsetting || !control_interface->cur_altsetting) + return -ENODEV; if (data_intf_num != call_intf_num) dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n"); From 2fae9e5a7babada041e2e161699ade2447a01989 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 19 Sep 2016 19:09:51 +0100 Subject: [PATCH 330/343] usb: misc: legousbtower: Fix NULL pointer deference This patch fixes a NULL pointer dereference caused by a race codition in the probe function of the legousbtower driver. It re-structures the probe function to only register the interface after successfully reading the board's firmware ID. The probe function does not deregister the usb interface after an error receiving the devices firmware ID. The device file registered (/dev/usb/legousbtower%d) may be read/written globally before the probe function returns. When tower_delete is called in the probe function (after an r/w has been initiated), core dev structures are deleted while the file operation functions are still running. If the 0 address is mappable on the machine, this vulnerability can be used to create a Local Priviege Escalation exploit via a write-what-where condition by remapping dev->interrupt_out_buffer in tower_write. A forged USB device and local program execution would be required for LPE. The USB device would have to delay the control message in tower_probe and accept the control urb in tower_open whilst guest code initiated a write to the device file as tower_delete is called from the error in tower_probe. This bug has existed since 2003. Patch tested by emulated device. Reported-by: James Patrick-Evans Tested-by: James Patrick-Evans Signed-off-by: James Patrick-Evans Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 35 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index ece9b3c1eaac..c8fbe7b739a0 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -886,24 +886,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; - /* we can register the device now, as it is ready */ - usb_set_intfdata (interface, dev); - - retval = usb_register_dev (interface, &tower_class); - - if (retval) { - /* something prevented us from registering this driver */ - dev_err(idev, "Not able to get a minor for this device.\n"); - usb_set_intfdata (interface, NULL); - goto error; - } - dev->minor = interface->minor; - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major " - "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), - USB_MAJOR, dev->minor); - /* get the firmware version and log it */ result = usb_control_msg (udev, usb_rcvctrlpipe(udev, 0), @@ -924,6 +906,23 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device get_version_reply.minor, le16_to_cpu(get_version_reply.build_no)); + /* we can register the device now, as it is ready */ + usb_set_intfdata (interface, dev); + + retval = usb_register_dev (interface, &tower_class); + + if (retval) { + /* something prevented us from registering this driver */ + dev_err(idev, "Not able to get a minor for this device.\n"); + usb_set_intfdata (interface, NULL); + goto error; + } + dev->minor = interface->minor; + + /* let the user know what node this device is now attached to */ + dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major " + "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), + USB_MAJOR, dev->minor); exit: return retval; From b36df0905ef808a8e9e46ded5f0b4967f21a2114 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 17 Sep 2016 12:08:10 +0200 Subject: [PATCH 331/343] musb: Export musb_root_disconnect for use in modules Export musb_root_disconnect for use in modules, so that musb glue code build as module can use it. This fixes the buildbot errors for -next in arm64-allmodconfig and arm-allmodconfig. Reported-by: kbuild test robot Fixes: 7cba17ec9adc8cf ("musb: sunxi: Add support for platform_set_mode") Signed-off-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_virthub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index fe08e776fec3..61b5f1c3c5bc 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -245,6 +245,7 @@ void musb_root_disconnect(struct musb *musb) usb_otg_state_string(musb->xceiv->otg->state)); } } +EXPORT_SYMBOL_GPL(musb_root_disconnect); /*---------------------------------------------------------------------*/ From 4e719183667e1363b0d81add5212aee2f149d727 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 22 Sep 2016 15:58:29 -0500 Subject: [PATCH 332/343] usb: musb: Fix PM runtime for disconnect after unconfigure If we unconfigure musb as a USB peripheral with cable connected, and then remove the cable, no interrupts will happen. And musb thinks we're still connected keeping the device active. Now with the session bit based PM runtime working for musb, we can fix this issue by calling musb irq_work. That rechecks the devctl register and reconfigures PM runtime based on the devctl. Fixes: 467d5c980709 ("usb: musb: Implement session bit based runtime PM for musb-core") Signed-off-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 6d1e975e9605..bff4869a57cd 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1964,6 +1964,9 @@ static int musb_gadget_stop(struct usb_gadget *g) * that currently misbehaves. */ + /* Force check of devctl register for PM runtime */ + schedule_work(&musb->irq_work); + pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); From 2b9a8c40836930a45f42f06f98731eb9614ba86b Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 22 Sep 2016 15:58:30 -0500 Subject: [PATCH 333/343] usb: musb: Fix session based PM for first invalid VBUS With the session bit based PM runtime working on musb, we've implemented few quirks to attempt to detect the current state of the hardware. One of the quirks is for invalid VBUS as peripheral, but it is not working in all cases. If we start musb on dm3730 as a peripheral with no cable connected, we will get the devctl 91 state once and will never idle as there are not further interrupts from musb. So we need to ignore the first devctl 91 state as there will be more interrupts if we're connected. The invalid VBUS state also can happen always when connected to certain USB hubs. Looks like musb on dm3730 can claim invalid VBUS with some hubs while 3717-evm and BeagleBone don't. This causes session as peripheral to fail for dm3730 with some hubs. This too is fixed by ignoring only the first invalid VBUS. When connected, we can just look at the session bit as that will clear automatically when the session ends. Fixes: 467d5c980709 ("usb: musb: Implement session bit based runtime PM for musb-core") Signed-off-by: Tony Lindgren Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 13 ++++++++----- drivers/usb/musb/musb_core.h | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 0319ea67e5a1..27dadc0d9114 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1855,11 +1855,13 @@ static void musb_pm_runtime_check_session(struct musb *musb) MUSB_DEVCTL_HR; switch (devctl & ~s) { case MUSB_QUIRK_B_INVALID_VBUS_91: - if (musb->session) - break; - musb_dbg(musb, "Allow PM as device with invalid vbus: %02x", - devctl); - return; + if (!musb->session && !musb->quirk_invalid_vbus) { + musb->quirk_invalid_vbus = true; + musb_dbg(musb, + "First invalid vbus, assume no session"); + return; + } + break; case MUSB_QUIRK_A_DISCONNECT_19: if (!musb->session) break; @@ -1886,6 +1888,7 @@ static void musb_pm_runtime_check_session(struct musb *musb) error); } else { musb_dbg(musb, "Allow PM with no session: %02x", devctl); + musb->quirk_invalid_vbus = false; pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); } diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 65288a53c19b..2cb88a498f8a 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -379,6 +379,7 @@ struct musb { int port_mode; /* MUSB_PORT_MODE_* */ bool session; + bool quirk_invalid_vbus; bool is_host; int a_wait_bcon; /* VBUS timeout in msecs */ From 984f3be5910c640bbff469bb3d4679036fce6395 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Sep 2016 15:58:31 -0500 Subject: [PATCH 334/343] usb: musb: da8xx: fix error handling message in probe We print an error message when platform_device_register_full() fails, but the initialization of the argument has been removed, as shown in this warning: drivers/usb/musb/da8xx.c: In function 'da8xx_probe': drivers/usb/musb/da8xx.c:521:3: error: 'ret' may be used uninitialized in this function [-Werror=maybe-uninitialized] This modifies the function to assign the return code before checking it, and does uses the same method in the check for usb_phy_generic_register() as well. Fixes: 947c49afe41f ("usb: musb: da8xx: Remove mach code") Signed-off-by: Arnd Bergmann Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/da8xx.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 2358f636e48c..210b7e43a6fd 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -462,7 +462,6 @@ static int da8xx_probe(struct platform_device *pdev) { struct resource musb_resources[2]; struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct platform_device *musb; struct da8xx_glue *glue; struct platform_device_info pinfo; struct clk *clk; @@ -490,9 +489,10 @@ static int da8xx_probe(struct platform_device *pdev) pdata->platform_ops = &da8xx_ops; glue->usb_phy = usb_phy_generic_register(); - if (IS_ERR(glue->usb_phy)) { + ret = PTR_ERR_OR_ZERO(glue->usb_phy); + if (ret) { dev_err(&pdev->dev, "failed to register usb_phy\n"); - return PTR_ERR(glue->usb_phy); + return ret; } platform_set_drvdata(pdev, glue); @@ -516,14 +516,14 @@ static int da8xx_probe(struct platform_device *pdev) pinfo.data = pdata; pinfo.size_data = sizeof(*pdata); - glue->musb = musb = platform_device_register_full(&pinfo); - if (IS_ERR(musb)) { + glue->musb = platform_device_register_full(&pinfo); + ret = PTR_ERR_OR_ZERO(glue->musb); + if (ret) { dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); usb_phy_generic_unregister(glue->usb_phy); - return PTR_ERR(musb); } - return 0; + return ret; } static int da8xx_remove(struct platform_device *pdev) From 35be784cdb9c81e9fa0c7cac3492069cadd6a726 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Fri, 23 Sep 2016 21:44:13 +0800 Subject: [PATCH 335/343] usb: core: hcd: add missing header dependencies We get 1 warning when building kernel with W=1: drivers/usb/core/hcd.c:2390:5: warning: no previous prototype for 'usb_bus_start_enum' [-Wmissing-prototypes] In fact, these functions are declared in linux/usb/otg.h, so this patch adds the missing header dependencies. Signed-off-by: Baoyou Xie Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 746c47d86cf5..479e223f9cff 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "usb.h" From e8624859dde2ad07633dac7ec86629a516411ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 21 Sep 2016 18:01:43 +0200 Subject: [PATCH 336/343] USB: bcma: drop Northstar PHY 2.0 initialization code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver should initialize controller only, PHY initialization should be handled by separated PHY driver. We already have phy-bcm-ns-usb2 in place so let it makes its duty. Signed-off-by: Rafał Miłecki Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 80 ++++++++++++------------------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index e0761d92f2b6..5f425c89faf1 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -239,44 +239,10 @@ static int bcma_hcd_usb20_old_arm_init(struct bcma_hcd_device *usb_dev) return 0; } -static void bcma_hcd_init_chip_arm_phy(struct bcma_device *dev) -{ - struct bcma_device *arm_core; - void __iomem *dmu; - - arm_core = bcma_find_core(dev->bus, BCMA_CORE_ARMCA9); - if (!arm_core) { - dev_err(&dev->dev, "can not find ARM Cortex A9 ihost core\n"); - return; - } - - dmu = ioremap_nocache(arm_core->addr_s[0], 0x1000); - if (!dmu) { - dev_err(&dev->dev, "can not map ARM Cortex A9 ihost core\n"); - return; - } - - /* Unlock DMU PLL settings */ - iowrite32(0x0000ea68, dmu + 0x180); - - /* Write USB 2.0 PLL control setting */ - iowrite32(0x00dd10c3, dmu + 0x164); - - /* Lock DMU PLL settings */ - iowrite32(0x00000000, dmu + 0x180); - - iounmap(dmu); -} - -static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev) +static void bcma_hcd_usb20_ns_init_hc(struct bcma_device *dev) { u32 val; - /* - * Delay after PHY initialized to ensure HC is ready to be configured - */ - usleep_range(1000, 2000); - /* Set packet buffer OUT threshold */ val = bcma_read32(dev, 0x94); val &= 0xffff; @@ -287,20 +253,33 @@ static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev) val = bcma_read32(dev, 0x9c); val |= 1; bcma_write32(dev, 0x9c, val); + + /* + * Broadcom initializes PHY and then waits to ensure HC is ready to be + * configured. In our case the order is reversed. We just initialized + * controller and we let HCD initialize PHY, so let's wait (sleep) now. + */ + usleep_range(1000, 2000); } -static void bcma_hcd_init_chip_arm(struct bcma_device *dev) +/** + * bcma_hcd_usb20_ns_init - Initialize Northstar USB 2.0 controller + */ +static int bcma_hcd_usb20_ns_init(struct bcma_hcd_device *bcma_hcd) { - bcma_core_enable(dev, 0); + struct bcma_device *core = bcma_hcd->core; + struct bcma_chipinfo *ci = &core->bus->chipinfo; + struct device *dev = &core->dev; - if (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4707 || - dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM53018) { - if (dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4707 || - dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4708) - bcma_hcd_init_chip_arm_phy(dev); + bcma_core_enable(core, 0); - bcma_hcd_init_chip_arm_hc(dev); - } + if (ci->id == BCMA_CHIP_ID_BCM4707 || + ci->id == BCMA_CHIP_ID_BCM53018) + bcma_hcd_usb20_ns_init_hc(core); + + of_platform_default_populate(dev->of_node, NULL, dev); + + return 0; } static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val) @@ -373,16 +352,7 @@ static int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev) if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) return -EOPNOTSUPP; - switch (dev->id.id) { - case BCMA_CORE_NS_USB20: - bcma_hcd_init_chip_arm(dev); - break; - case BCMA_CORE_USB20_HOST: - bcma_hcd_init_chip_mips(dev); - break; - default: - return -ENODEV; - } + bcma_hcd_init_chip_mips(dev); /* In AI chips EHCI is addrspace 0, OHCI is 1 */ ohci_addr = dev->addr_s[0]; @@ -451,7 +421,7 @@ static int bcma_hcd_probe(struct bcma_device *core) err = -ENOTSUPP; break; case BCMA_CORE_NS_USB20: - err = bcma_hcd_usb20_init(usb_dev); + err = bcma_hcd_usb20_ns_init(usb_dev); break; case BCMA_CORE_NS_USB30: err = bcma_hcd_usb30_init(usb_dev); From 0f247626cbbfa2010d2b86fdee652605e084e248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 16 Sep 2016 16:13:48 +0200 Subject: [PATCH 337/343] usb: core: Introduce a USB port LED trigger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a new trigger responsible for turning on LED when USB device gets connected to the selected USB port. This can can useful for various home routers that have USB port(s) and a proper LED telling user a device is connected. The trigger gets its documentation file but basically it just requires enabling it and selecting USB ports (e.g. echo 1 > ports/usb1-1). There was a long discussion on design of this driver. Its current state is a result of picking them most adjustable solution as others couldn't handle all cases. 1) It wasn't possible for the driver to register separated trigger for each USB port. Some physical USB ports are handled by more than one controller and so by more than one USB port. E.g. USB 2.0 physical port may be handled by OHCI's port and EHCI's port. It's also not possible to assign more than 1 trigger to a single LED and implementing such feature would be tricky due to syncing triggers and sysfs conflicts with old triggers. 2) Another idea was to register trigger per USB hub. This wouldn't allow handling devices with multiple USB LEDs and controllers (hubs) controlling more than 1 physical port. It's common for hubs to have few ports and each may have its own LED. This final trigger is highly flexible. It allows selecting any USB ports for any LED. It was also modified (comparing to the initial version) to allow choosing ports rather than having user /guess/ proper names. It was successfully tested on SmartRG SR400ac which has 3 USB LEDs, 2 physical ports and 3 controllers. It was noted USB subsystem already has usb-gadget and usb-host triggers but they are pretty trivial ones. They indicate activity only and can't have ports specified. In future it may be good idea to consider adding activity support to usbport as well. This should allow switching to this more generic driver and maybe marking old ones as obsolete. This can be implemented with another sysfs file for setting mode. The default mode wouldn't change so there won't be ABI breakage and so such feature can be safely implemented later. There was also an idea of supporting other devices (PCI, SDIO, etc.) but as this driver already contains some USB specific code (and will get more) these should be probably separated drivers (triggers). Signed-off-by: Rafał Miłecki Signed-off-by: Greg Kroah-Hartman --- .../testing/sysfs-class-led-trigger-usbport | 12 + Documentation/leds/ledtrig-usbport.txt | 41 +++ drivers/usb/core/Kconfig | 8 + drivers/usb/core/Makefile | 2 + drivers/usb/core/ledtrig-usbport.c | 314 ++++++++++++++++++ 5 files changed, 377 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-usbport create mode 100644 Documentation/leds/ledtrig-usbport.txt create mode 100644 drivers/usb/core/ledtrig-usbport.c diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-usbport b/Documentation/ABI/testing/sysfs-class-led-trigger-usbport new file mode 100644 index 000000000000..f440e690daef --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-usbport @@ -0,0 +1,12 @@ +What: /sys/class/leds//ports/ +Date: September 2016 +KernelVersion: 4.9 +Contact: linux-leds@vger.kernel.org + linux-usb@vger.kernel.org +Description: + Every dir entry represents a single USB port that can be + selected for the USB port trigger. Selecting ports makes trigger + observing them for any connected devices and lighting on LED if + there are any. + Echoing "1" value selects USB port. Echoing "0" unselects it. + Current state can be also read. diff --git a/Documentation/leds/ledtrig-usbport.txt b/Documentation/leds/ledtrig-usbport.txt new file mode 100644 index 000000000000..69f54bfb4789 --- /dev/null +++ b/Documentation/leds/ledtrig-usbport.txt @@ -0,0 +1,41 @@ +USB port LED trigger +==================== + +This LED trigger can be used for signalling to the user a presence of USB device +in a given port. It simply turns on LED when device appears and turns it off +when it disappears. + +It requires selecting USB ports that should be observed. All available ones are +listed as separated entries in a "ports" subdirectory. Selecting is handled by +echoing "1" to a chosen port. + +Please note that this trigger allows selecting multiple USB ports for a single +LED. This can be useful in two cases: + +1) Device with single USB LED and few physical ports + +In such a case LED will be turned on as long as there is at least one connected +USB device. + +2) Device with a physical port handled by few controllers + +Some devices may have one controller per PHY standard. E.g. USB 3.0 physical +port may be handled by ohci-platform, ehci-platform and xhci-hcd. If there is +only one LED user will most likely want to assign ports from all 3 hubs. + + +This trigger can be activated from user space on led class devices as shown +below: + + echo usbport > trigger + +This adds sysfs attributes to the LED that are documented in: +Documentation/ABI/testing/sysfs-class-led-trigger-usbport + +Example use-case: + + echo usbport > trigger + echo 1 > ports/usb1-port1 + echo 1 > ports/usb2-port1 + cat ports/usb1-port1 + echo 0 > ports/usb1-port1 diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index d6e43ce96799..0e5a889742b3 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -82,3 +82,11 @@ config USB_OTG_FSM help Implements OTG Finite State Machine as specified in On-The-Go and Embedded Host Supplement to the USB Revision 2.0 Specification. + +config USB_LEDS_TRIGGER_USBPORT + tristate "USB port LED trigger" + depends on USB && LEDS_TRIGGERS + help + This driver allows LEDs to be controlled by USB events. Enabling this + trigger allows specifying list of USB ports that should turn on LED + when some USB device gets connected. diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index da36b784a0ef..b99b871c4b9d 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -12,3 +12,5 @@ usbcore-$(CONFIG_PCI) += hcd-pci.o usbcore-$(CONFIG_ACPI) += usb-acpi.o obj-$(CONFIG_USB) += usbcore.o + +obj-$(CONFIG_USB_LEDS_TRIGGER_USBPORT) += ledtrig-usbport.o diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c new file mode 100644 index 000000000000..3ed5162677ad --- /dev/null +++ b/drivers/usb/core/ledtrig-usbport.c @@ -0,0 +1,314 @@ +/* + * USB port LED trigger + * + * Copyright (C) 2016 Rafał Miłecki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +struct usbport_trig_data { + struct led_classdev *led_cdev; + struct list_head ports; + struct notifier_block nb; + int count; /* Amount of connected matching devices */ +}; + +struct usbport_trig_port { + struct usbport_trig_data *data; + struct usb_device *hub; + int portnum; + char *port_name; + bool observed; + struct device_attribute attr; + struct list_head list; +}; + +/*************************************** + * Helpers + ***************************************/ + +/** + * usbport_trig_usb_dev_observed - Check if dev is connected to observed port + */ +static bool usbport_trig_usb_dev_observed(struct usbport_trig_data *usbport_data, + struct usb_device *usb_dev) +{ + struct usbport_trig_port *port; + + if (!usb_dev->parent) + return false; + + list_for_each_entry(port, &usbport_data->ports, list) { + if (usb_dev->parent == port->hub && + usb_dev->portnum == port->portnum) + return port->observed; + } + + return false; +} + +static int usbport_trig_usb_dev_check(struct usb_device *usb_dev, void *data) +{ + struct usbport_trig_data *usbport_data = data; + + if (usbport_trig_usb_dev_observed(usbport_data, usb_dev)) + usbport_data->count++; + + return 0; +} + +/** + * usbport_trig_update_count - Recalculate amount of connected matching devices + */ +static void usbport_trig_update_count(struct usbport_trig_data *usbport_data) +{ + struct led_classdev *led_cdev = usbport_data->led_cdev; + + usbport_data->count = 0; + usb_for_each_dev(usbport_data, usbport_trig_usb_dev_check); + led_cdev->brightness_set(led_cdev, + usbport_data->count ? LED_FULL : LED_OFF); +} + +/*************************************** + * Device attr + ***************************************/ + +static ssize_t usbport_trig_port_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usbport_trig_port *port = container_of(attr, + struct usbport_trig_port, + attr); + + return sprintf(buf, "%d\n", port->observed) + 1; +} + +static ssize_t usbport_trig_port_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct usbport_trig_port *port = container_of(attr, + struct usbport_trig_port, + attr); + + if (!strcmp(buf, "0") || !strcmp(buf, "0\n")) + port->observed = 0; + else if (!strcmp(buf, "1") || !strcmp(buf, "1\n")) + port->observed = 1; + else + return -EINVAL; + + usbport_trig_update_count(port->data); + + return size; +} + +static struct attribute *ports_attrs[] = { + NULL, +}; +static const struct attribute_group ports_group = { + .name = "ports", + .attrs = ports_attrs, +}; + +/*************************************** + * Adding & removing ports + ***************************************/ + +static int usbport_trig_add_port(struct usbport_trig_data *usbport_data, + struct usb_device *usb_dev, + const char *hub_name, int portnum) +{ + struct led_classdev *led_cdev = usbport_data->led_cdev; + struct usbport_trig_port *port; + size_t len; + int err; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) { + err = -ENOMEM; + goto err_out; + } + + port->data = usbport_data; + port->hub = usb_dev; + port->portnum = portnum; + + len = strlen(hub_name) + 8; + port->port_name = kzalloc(len, GFP_KERNEL); + if (!port->port_name) { + err = -ENOMEM; + goto err_free_port; + } + snprintf(port->port_name, len, "%s-port%d", hub_name, portnum); + + port->attr.attr.name = port->port_name; + port->attr.attr.mode = S_IRUSR | S_IWUSR; + port->attr.show = usbport_trig_port_show; + port->attr.store = usbport_trig_port_store; + + err = sysfs_add_file_to_group(&led_cdev->dev->kobj, &port->attr.attr, + ports_group.name); + if (err) + goto err_free_port_name; + + list_add_tail(&port->list, &usbport_data->ports); + + return 0; + +err_free_port_name: + kfree(port->port_name); +err_free_port: + kfree(port); +err_out: + return err; +} + +static int usbport_trig_add_usb_dev_ports(struct usb_device *usb_dev, + void *data) +{ + struct usbport_trig_data *usbport_data = data; + int i; + + for (i = 1; i <= usb_dev->maxchild; i++) + usbport_trig_add_port(usbport_data, usb_dev, + dev_name(&usb_dev->dev), i); + + return 0; +} + +static void usbport_trig_remove_port(struct usbport_trig_data *usbport_data, + struct usbport_trig_port *port) +{ + struct led_classdev *led_cdev = usbport_data->led_cdev; + + list_del(&port->list); + sysfs_remove_file_from_group(&led_cdev->dev->kobj, &port->attr.attr, + ports_group.name); + kfree(port->port_name); + kfree(port); +} + +static void usbport_trig_remove_usb_dev_ports(struct usbport_trig_data *usbport_data, + struct usb_device *usb_dev) +{ + struct usbport_trig_port *port, *tmp; + + list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) { + if (port->hub == usb_dev) + usbport_trig_remove_port(usbport_data, port); + } +} + +/*************************************** + * Init, exit, etc. + ***************************************/ + +static int usbport_trig_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct usbport_trig_data *usbport_data = + container_of(nb, struct usbport_trig_data, nb); + struct led_classdev *led_cdev = usbport_data->led_cdev; + struct usb_device *usb_dev = data; + bool observed; + + observed = usbport_trig_usb_dev_observed(usbport_data, usb_dev); + + switch (action) { + case USB_DEVICE_ADD: + usbport_trig_add_usb_dev_ports(usb_dev, usbport_data); + if (observed && usbport_data->count++ == 0) + led_cdev->brightness_set(led_cdev, LED_FULL); + return NOTIFY_OK; + case USB_DEVICE_REMOVE: + usbport_trig_remove_usb_dev_ports(usbport_data, usb_dev); + if (observed && --usbport_data->count == 0) + led_cdev->brightness_set(led_cdev, LED_OFF); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} + +static void usbport_trig_activate(struct led_classdev *led_cdev) +{ + struct usbport_trig_data *usbport_data; + int err; + + usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL); + if (!usbport_data) + return; + usbport_data->led_cdev = led_cdev; + + /* List of ports */ + INIT_LIST_HEAD(&usbport_data->ports); + err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group); + if (err) + goto err_free; + usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports); + + /* Notifications */ + usbport_data->nb.notifier_call = usbport_trig_notify, + led_cdev->trigger_data = usbport_data; + usb_register_notify(&usbport_data->nb); + + led_cdev->activated = true; + return; + +err_free: + kfree(usbport_data); +} + +static void usbport_trig_deactivate(struct led_classdev *led_cdev) +{ + struct usbport_trig_data *usbport_data = led_cdev->trigger_data; + struct usbport_trig_port *port, *tmp; + + if (!led_cdev->activated) + return; + + list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) { + usbport_trig_remove_port(usbport_data, port); + } + + usb_unregister_notify(&usbport_data->nb); + + sysfs_remove_group(&led_cdev->dev->kobj, &ports_group); + + kfree(usbport_data); + + led_cdev->activated = false; +} + +static struct led_trigger usbport_led_trigger = { + .name = "usbport", + .activate = usbport_trig_activate, + .deactivate = usbport_trig_deactivate, +}; + +static int __init usbport_trig_init(void) +{ + return led_trigger_register(&usbport_led_trigger); +} + +static void __exit usbport_trig_exit(void) +{ + led_trigger_unregister(&usbport_led_trigger); +} + +module_init(usbport_trig_init); +module_exit(usbport_trig_exit); + +MODULE_AUTHOR("Rafał Miłecki "); +MODULE_DESCRIPTION("USB port trigger"); +MODULE_LICENSE("GPL v2"); From 4e248000e0d3b406bd6612186835467f2f84486e Mon Sep 17 00:00:00 2001 From: Yonglong Wu Date: Fri, 19 Aug 2016 11:37:26 +0800 Subject: [PATCH 338/343] usb: hub: change CLEAR_FEATURE to SET_FEATURE In USB20 specification, describes in chapter 9.4.5: The Remote Wakeup field can be modified by the SetFeature() and ClearFeature() requests using the DEVICE_REMOTE_WAKEUP feature selector. In USB30 specification, also describes in chapter 9.4.5: The Function Remote Wakeup field can be modified by the SetFeature() requests using the FUNCTION_SUSPEND feature selector. In chapter 9.4.9 Set Feature reference, it describes Function Remote Wake Enabled/Disabled at suspend options by SET_FEATURE. In USB30 specification only mentioned SetFeature(), so we need use SET_FEATURE replace CLEAR_FEATURE to disable USB30 function remote wakeup in suspend options. Signed-off-by: Yonglong Wu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b48dc76385b6..cbb146736f57 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3104,7 +3104,7 @@ static int usb_disable_remote_wakeup(struct usb_device *udev) USB_CTRL_SET_TIMEOUT); else return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE, + USB_REQ_SET_FEATURE, USB_RECIP_INTERFACE, USB_INTRF_FUNC_SUSPEND, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); } From 539d3040569b701ed6c826509e2f98b2876b40f0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:03:53 +0200 Subject: [PATCH 339/343] mmc: host: vub300: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/vub300.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index 1e819f98b94f..bb3e0d1dd355 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2116,13 +2116,11 @@ static int vub300_probe(struct usb_interface *interface, command_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!command_out_urb) { retval = -ENOMEM; - dev_err(&udev->dev, "not enough memory for command_out_urb\n"); goto error0; } command_res_urb = usb_alloc_urb(0, GFP_KERNEL); if (!command_res_urb) { retval = -ENOMEM; - dev_err(&udev->dev, "not enough memory for command_res_urb\n"); goto error1; } /* this also allocates memory for our VUB300 mmc host device */ From a2f195a73eba807006fb0cb882ecb552c06eea00 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 11 Aug 2016 23:00:31 +0200 Subject: [PATCH 340/343] bluetooth: bcm203x: don't print error when allocating urb fails kmalloc will print enough information in case of failure. Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/bcm203x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 5b0ef7bbe8ac..5ce6d4176dc3 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -185,10 +185,8 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id data->state = BCM203X_LOAD_MINIDRV; data->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!data->urb) { - BT_ERR("Can't allocate URB"); + if (!data->urb) return -ENOMEM; - } if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { BT_ERR("Mini driver request failed"); From cb9c1cfc86926d0e86d19c8e34f6c23458cd3478 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 14 Sep 2016 09:49:30 +0800 Subject: [PATCH 341/343] usb: Kconfig: using select for USB_COMMON dependency According to (badf6d47f8a9 "usb: common: rework CONFIG_USB_COMMON logic") we should select USB_COMMON at Kconfig when usb common stuffs are needed, but some of Kconfig enties have not followed it, update them. Cc: Felipe Balbi Cc: Heikki Krogerus Signed-off-by: Peter Chen Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 5 +++-- drivers/usb/usbip/Kconfig | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 2b9159a9ab4f..644e978cbd3e 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -152,7 +152,8 @@ source "drivers/usb/gadget/Kconfig" config USB_LED_TRIG bool "USB LED Triggers" - depends on LEDS_CLASS && USB_COMMON && LEDS_TRIGGERS + depends on LEDS_CLASS && LEDS_TRIGGERS + select USB_COMMON help This option adds LED triggers for USB host and/or gadget activity. @@ -162,7 +163,7 @@ config USB_LED_TRIG config USB_ULPI_BUS tristate "USB ULPI PHY interface support" - depends on USB_COMMON + select USB_COMMON help UTMI+ Low Pin Interface (ULPI) is specification for a commonly used USB 2.0 PHY interface. The ULPI specification defines a standard set diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index 29492c70e0e6..eeefa29f8aa2 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -1,6 +1,7 @@ config USBIP_CORE tristate "USB/IP support" - depends on USB_COMMON && NET + depends on NET + select USB_COMMON ---help--- This enables pushing USB packets over IP to allow remote machines direct access to USB devices. It provides the From decc5360f23e9efe0252094f47f57f254dcbb3a9 Mon Sep 17 00:00:00 2001 From: Kyle Jones Date: Fri, 23 Sep 2016 13:28:37 -0500 Subject: [PATCH 342/343] USB: serial: cp210x: Add ID for a Juniper console Signed-off-by: Kyle Jones Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 4d6a5c672a3d..54a4de0efdba 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -118,6 +118,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ + { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */ { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */ { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ From ab21b63e8aedfc73565dd9cdd51eb338341177cb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 28 Sep 2016 11:48:44 +0200 Subject: [PATCH 343/343] Revert "usbtmc: convert to devm_kzalloc" This reverts commit e6c7efdcb76f11b04e3d3f71c8d764ab75c9423b. Turns out it was totally wrong. The memory is supposed to be bound to the kref, as the original code was doing correctly, not the device/driver binding as the devm_kzalloc() would cause. This fixes an oops when read would be called after the device was unbound from the driver. Reported-by: Ladislav Michl Cc: Andy Shevchenko Cc: stable # 3.12+ Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usbtmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index da4f2509f567..a6c1fae7d52a 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -141,6 +141,7 @@ static void usbtmc_delete(struct kref *kref) struct usbtmc_device_data *data = to_usbtmc_data(kref); usb_put_dev(data->usb_dev); + kfree(data); } static int usbtmc_open(struct inode *inode, struct file *filp) @@ -1379,7 +1380,7 @@ static int usbtmc_probe(struct usb_interface *intf, dev_dbg(&intf->dev, "%s called\n", __func__); - data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); + data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;