diff options
Diffstat (limited to 'drivers/usb/misc')
-rw-r--r-- | drivers/usb/misc/usb3503.c | 93 |
1 files changed, 76 insertions, 17 deletions
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index da45ed971332..a31641e18d19 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c | |||
@@ -78,22 +78,21 @@ static int usb3503_reset(struct usb3503 *hub, int state) | |||
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
80 | 80 | ||
81 | static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) | 81 | static int usb3503_connect(struct usb3503 *hub) |
82 | { | 82 | { |
83 | struct device *dev = hub->dev; | 83 | struct device *dev = hub->dev; |
84 | int err = 0; | 84 | int err; |
85 | 85 | ||
86 | switch (mode) { | 86 | usb3503_reset(hub, 1); |
87 | case USB3503_MODE_HUB: | ||
88 | usb3503_reset(hub, 1); | ||
89 | 87 | ||
88 | if (hub->regmap) { | ||
90 | /* SP_ILOCK: set connect_n, config_n for config */ | 89 | /* SP_ILOCK: set connect_n, config_n for config */ |
91 | err = regmap_write(hub->regmap, USB3503_SP_ILOCK, | 90 | err = regmap_write(hub->regmap, USB3503_SP_ILOCK, |
92 | (USB3503_SPILOCK_CONNECT | 91 | (USB3503_SPILOCK_CONNECT |
93 | | USB3503_SPILOCK_CONFIG)); | 92 | | USB3503_SPILOCK_CONFIG)); |
94 | if (err < 0) { | 93 | if (err < 0) { |
95 | dev_err(dev, "SP_ILOCK failed (%d)\n", err); | 94 | dev_err(dev, "SP_ILOCK failed (%d)\n", err); |
96 | goto err_hubmode; | 95 | return err; |
97 | } | 96 | } |
98 | 97 | ||
99 | /* PDS : Disable For Self Powered Operation */ | 98 | /* PDS : Disable For Self Powered Operation */ |
@@ -103,7 +102,7 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) | |||
103 | hub->port_off_mask); | 102 | hub->port_off_mask); |
104 | if (err < 0) { | 103 | if (err < 0) { |
105 | dev_err(dev, "PDS failed (%d)\n", err); | 104 | dev_err(dev, "PDS failed (%d)\n", err); |
106 | goto err_hubmode; | 105 | return err; |
107 | } | 106 | } |
108 | } | 107 | } |
109 | 108 | ||
@@ -113,7 +112,7 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) | |||
113 | USB3503_SELF_BUS_PWR); | 112 | USB3503_SELF_BUS_PWR); |
114 | if (err < 0) { | 113 | if (err < 0) { |
115 | dev_err(dev, "CFG1 failed (%d)\n", err); | 114 | dev_err(dev, "CFG1 failed (%d)\n", err); |
116 | goto err_hubmode; | 115 | return err; |
117 | } | 116 | } |
118 | 117 | ||
119 | /* SP_LOCK: clear connect_n, config_n for hub connect */ | 118 | /* SP_LOCK: clear connect_n, config_n for hub connect */ |
@@ -122,14 +121,27 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) | |||
122 | | USB3503_SPILOCK_CONFIG), 0); | 121 | | USB3503_SPILOCK_CONFIG), 0); |
123 | if (err < 0) { | 122 | if (err < 0) { |
124 | dev_err(dev, "SP_ILOCK failed (%d)\n", err); | 123 | dev_err(dev, "SP_ILOCK failed (%d)\n", err); |
125 | goto err_hubmode; | 124 | return err; |
126 | } | 125 | } |
126 | } | ||
127 | 127 | ||
128 | if (gpio_is_valid(hub->gpio_connect)) | 128 | if (gpio_is_valid(hub->gpio_connect)) |
129 | gpio_set_value_cansleep(hub->gpio_connect, 1); | 129 | gpio_set_value_cansleep(hub->gpio_connect, 1); |
130 | 130 | ||
131 | hub->mode = mode; | 131 | hub->mode = USB3503_MODE_HUB; |
132 | dev_info(dev, "switched to HUB mode\n"); | 132 | dev_info(dev, "switched to HUB mode\n"); |
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) | ||
138 | { | ||
139 | struct device *dev = hub->dev; | ||
140 | int err = 0; | ||
141 | |||
142 | switch (mode) { | ||
143 | case USB3503_MODE_HUB: | ||
144 | err = usb3503_connect(hub); | ||
133 | break; | 145 | break; |
134 | 146 | ||
135 | case USB3503_MODE_STANDBY: | 147 | case USB3503_MODE_STANDBY: |
@@ -145,7 +157,6 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) | |||
145 | break; | 157 | break; |
146 | } | 158 | } |
147 | 159 | ||
148 | err_hubmode: | ||
149 | return err; | 160 | return err; |
150 | } | 161 | } |
151 | 162 | ||
@@ -198,6 +209,9 @@ static int usb3503_probe(struct usb3503 *hub) | |||
198 | hub->mode = mode; | 209 | hub->mode = mode; |
199 | } | 210 | } |
200 | 211 | ||
212 | if (hub->port_off_mask && !hub->regmap) | ||
213 | dev_err(dev, "Ports disabled with no control interface\n"); | ||
214 | |||
201 | if (gpio_is_valid(hub->gpio_intn)) { | 215 | if (gpio_is_valid(hub->gpio_intn)) { |
202 | err = devm_gpio_request_one(dev, hub->gpio_intn, | 216 | err = devm_gpio_request_one(dev, hub->gpio_intn, |
203 | GPIOF_OUT_INIT_HIGH, "usb3503 intn"); | 217 | GPIOF_OUT_INIT_HIGH, "usb3503 intn"); |
@@ -263,6 +277,20 @@ static int usb3503_i2c_probe(struct i2c_client *i2c, | |||
263 | return usb3503_probe(hub); | 277 | return usb3503_probe(hub); |
264 | } | 278 | } |
265 | 279 | ||
280 | static int usb3503_platform_probe(struct platform_device *pdev) | ||
281 | { | ||
282 | struct usb3503 *hub; | ||
283 | |||
284 | hub = devm_kzalloc(&pdev->dev, sizeof(struct usb3503), GFP_KERNEL); | ||
285 | if (!hub) { | ||
286 | dev_err(&pdev->dev, "private data alloc fail\n"); | ||
287 | return -ENOMEM; | ||
288 | } | ||
289 | hub->dev = &pdev->dev; | ||
290 | |||
291 | return usb3503_probe(hub); | ||
292 | } | ||
293 | |||
266 | static const struct i2c_device_id usb3503_id[] = { | 294 | static const struct i2c_device_id usb3503_id[] = { |
267 | { USB3503_I2C_NAME, 0 }, | 295 | { USB3503_I2C_NAME, 0 }, |
268 | { } | 296 | { } |
@@ -278,7 +306,7 @@ static const struct of_device_id usb3503_of_match[] = { | |||
278 | MODULE_DEVICE_TABLE(of, usb3503_of_match); | 306 | MODULE_DEVICE_TABLE(of, usb3503_of_match); |
279 | #endif | 307 | #endif |
280 | 308 | ||
281 | static struct i2c_driver usb3503_driver = { | 309 | static struct i2c_driver usb3503_i2c_driver = { |
282 | .driver = { | 310 | .driver = { |
283 | .name = USB3503_I2C_NAME, | 311 | .name = USB3503_I2C_NAME, |
284 | .of_match_table = of_match_ptr(usb3503_of_match), | 312 | .of_match_table = of_match_ptr(usb3503_of_match), |
@@ -287,7 +315,38 @@ static struct i2c_driver usb3503_driver = { | |||
287 | .id_table = usb3503_id, | 315 | .id_table = usb3503_id, |
288 | }; | 316 | }; |
289 | 317 | ||
290 | module_i2c_driver(usb3503_driver); | 318 | static struct platform_driver usb3503_platform_driver = { |
319 | .driver = { | ||
320 | .name = USB3503_I2C_NAME, | ||
321 | .of_match_table = of_match_ptr(usb3503_of_match), | ||
322 | .owner = THIS_MODULE, | ||
323 | }, | ||
324 | .probe = usb3503_platform_probe, | ||
325 | }; | ||
326 | |||
327 | static int __init usb3503_init(void) | ||
328 | { | ||
329 | int err; | ||
330 | |||
331 | err = i2c_register_driver(THIS_MODULE, &usb3503_i2c_driver); | ||
332 | if (err != 0) | ||
333 | pr_err("usb3503: Failed to register I2C driver: %d\n", err); | ||
334 | |||
335 | err = platform_driver_register(&usb3503_platform_driver); | ||
336 | if (err != 0) | ||
337 | pr_err("usb3503: Failed to register platform driver: %d\n", | ||
338 | err); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | module_init(usb3503_init); | ||
343 | |||
344 | static void __exit usb3503_exit(void) | ||
345 | { | ||
346 | platform_driver_unregister(&usb3503_platform_driver); | ||
347 | i2c_del_driver(&usb3503_i2c_driver); | ||
348 | } | ||
349 | module_exit(usb3503_exit); | ||
291 | 350 | ||
292 | MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>"); | 351 | MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>"); |
293 | MODULE_DESCRIPTION("USB3503 USB HUB driver"); | 352 | MODULE_DESCRIPTION("USB3503 USB HUB driver"); |