aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2013-08-09 06:41:58 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-12 15:20:27 -0400
commit3f0d1c67fa20d524fdcb4a7dcda19ed76c59be44 (patch)
treef0d9cefc79b8c7033b39194332cfac68e4709358
parente5162d40b90e3e2e01aadcac9d4f151ecb9ee051 (diff)
usb: misc: usb3503: Support operation with no I2C control
Refactor so that register writes for configuration are only performed if the device has a regmap provided and also register as a platform driver. This allows the driver to be used to manage GPIO based control of the device. Signed-off-by: Mark Brown <broonie@linaro.org> Cc: devicetree@vger.kernel.org Reviewed-by: Dongjin Kim <tobetter@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/devicetree/bindings/usb/usb3503.txt3
-rw-r--r--drivers/usb/misc/usb3503.c93
2 files changed, 78 insertions, 18 deletions
diff --git a/Documentation/devicetree/bindings/usb/usb3503.txt b/Documentation/devicetree/bindings/usb/usb3503.txt
index 44a03f338424..a018da4a7ad7 100644
--- a/Documentation/devicetree/bindings/usb/usb3503.txt
+++ b/Documentation/devicetree/bindings/usb/usb3503.txt
@@ -2,9 +2,10 @@ SMSC USB3503 High-Speed Hub Controller
2 2
3Required properties: 3Required properties:
4- compatible: Should be "smsc,usb3503" or "smsc,usb3503a". 4- compatible: Should be "smsc,usb3503" or "smsc,usb3503a".
5- reg: Specifies the i2c slave address, it should be 0x08.
6 5
7Optional properties: 6Optional properties:
7- reg: Specifies the i2c slave address, it is required and should be 0x08
8 if I2C is used.
8- connect-gpios: Should specify GPIO for connect. 9- connect-gpios: Should specify GPIO for connect.
9- disabled-ports: Should specify the ports unused. 10- disabled-ports: Should specify the ports unused.
10 '1' or '2' or '3' are availe for this property to describe the port 11 '1' or '2' or '3' are availe for this property to describe the port
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
81static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) 81static 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
137static 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
148err_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
280static 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
266static const struct i2c_device_id usb3503_id[] = { 294static 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[] = {
278MODULE_DEVICE_TABLE(of, usb3503_of_match); 306MODULE_DEVICE_TABLE(of, usb3503_of_match);
279#endif 307#endif
280 308
281static struct i2c_driver usb3503_driver = { 309static 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
290module_i2c_driver(usb3503_driver); 318static 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
327static 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}
342module_init(usb3503_init);
343
344static void __exit usb3503_exit(void)
345{
346 platform_driver_unregister(&usb3503_platform_driver);
347 i2c_del_driver(&usb3503_i2c_driver);
348}
349module_exit(usb3503_exit);
291 350
292MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>"); 351MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>");
293MODULE_DESCRIPTION("USB3503 USB HUB driver"); 352MODULE_DESCRIPTION("USB3503 USB HUB driver");