Reviewed-by: Dongjin Kim <tobetter@xxxxxxxxx> I like this patch series, I dropped my changes to support non-i2c based operation. On Fri, Aug 9, 2013 at 7:41 PM, Mark Brown <broonie@xxxxxxxxxx> wrote: > From: Mark Brown <broonie@xxxxxxxxxx> > > 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@xxxxxxxxxx> > Cc: devicetree@xxxxxxxxxxxxxxx > --- > Documentation/devicetree/bindings/usb/usb3503.txt | 3 +- > drivers/usb/misc/usb3503.c | 93 ++++++++++++++++++----- > 2 files changed, 78 insertions(+), 18 deletions(-) > > diff --git a/Documentation/devicetree/bindings/usb/usb3503.txt b/Documentation/devicetree/bindings/usb/usb3503.txt > index 44a03f3..a018da4 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 > > Required properties: > - compatible: Should be "smsc,usb3503" or "smsc,usb3503a". > -- reg: Specifies the i2c slave address, it should be 0x08. > > Optional properties: > +- reg: Specifies the i2c slave address, it is required and should be 0x08 > + if I2C is used. > - connect-gpios: Should specify GPIO for connect. > - disabled-ports: Should specify the ports unused. > '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 da45ed9..a31641e 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) > return 0; > } > > -static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) > +static int usb3503_connect(struct usb3503 *hub) > { > struct device *dev = hub->dev; > - int err = 0; > + int err; > > - switch (mode) { > - case USB3503_MODE_HUB: > - usb3503_reset(hub, 1); > + usb3503_reset(hub, 1); > > + if (hub->regmap) { > /* SP_ILOCK: set connect_n, config_n for config */ > err = regmap_write(hub->regmap, USB3503_SP_ILOCK, > - (USB3503_SPILOCK_CONNECT > + (USB3503_SPILOCK_CONNECT > | USB3503_SPILOCK_CONFIG)); > if (err < 0) { > dev_err(dev, "SP_ILOCK failed (%d)\n", err); > - goto err_hubmode; > + return err; > } > > /* PDS : Disable For Self Powered Operation */ > @@ -103,7 +102,7 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) > hub->port_off_mask); > if (err < 0) { > dev_err(dev, "PDS failed (%d)\n", err); > - goto err_hubmode; > + return err; > } > } > > @@ -113,7 +112,7 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) > USB3503_SELF_BUS_PWR); > if (err < 0) { > dev_err(dev, "CFG1 failed (%d)\n", err); > - goto err_hubmode; > + return err; > } > > /* 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) > | USB3503_SPILOCK_CONFIG), 0); > if (err < 0) { > dev_err(dev, "SP_ILOCK failed (%d)\n", err); > - goto err_hubmode; > + return err; > } > + } > > - if (gpio_is_valid(hub->gpio_connect)) > - gpio_set_value_cansleep(hub->gpio_connect, 1); > + if (gpio_is_valid(hub->gpio_connect)) > + gpio_set_value_cansleep(hub->gpio_connect, 1); > > - hub->mode = mode; > - dev_info(dev, "switched to HUB mode\n"); > + hub->mode = USB3503_MODE_HUB; > + dev_info(dev, "switched to HUB mode\n"); > + > + return 0; > +} > + > +static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) > +{ > + struct device *dev = hub->dev; > + int err = 0; > + > + switch (mode) { > + case USB3503_MODE_HUB: > + err = usb3503_connect(hub); > break; > > case USB3503_MODE_STANDBY: > @@ -145,7 +157,6 @@ static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) > break; > } > > -err_hubmode: > return err; > } > > @@ -198,6 +209,9 @@ static int usb3503_probe(struct usb3503 *hub) > hub->mode = mode; > } > > + if (hub->port_off_mask && !hub->regmap) > + dev_err(dev, "Ports disabled with no control interface\n"); > + > if (gpio_is_valid(hub->gpio_intn)) { > err = devm_gpio_request_one(dev, hub->gpio_intn, > GPIOF_OUT_INIT_HIGH, "usb3503 intn"); > @@ -263,6 +277,20 @@ static int usb3503_i2c_probe(struct i2c_client *i2c, > return usb3503_probe(hub); > } > > +static int usb3503_platform_probe(struct platform_device *pdev) > +{ > + struct usb3503 *hub; > + > + hub = devm_kzalloc(&pdev->dev, sizeof(struct usb3503), GFP_KERNEL); > + if (!hub) { > + dev_err(&pdev->dev, "private data alloc fail\n"); > + return -ENOMEM; > + } > + hub->dev = &pdev->dev; > + > + return usb3503_probe(hub); > +} > + > static const struct i2c_device_id usb3503_id[] = { > { USB3503_I2C_NAME, 0 }, > { } > @@ -278,7 +306,7 @@ static const struct of_device_id usb3503_of_match[] = { > MODULE_DEVICE_TABLE(of, usb3503_of_match); > #endif > > -static struct i2c_driver usb3503_driver = { > +static struct i2c_driver usb3503_i2c_driver = { > .driver = { > .name = USB3503_I2C_NAME, > .of_match_table = of_match_ptr(usb3503_of_match), > @@ -287,7 +315,38 @@ static struct i2c_driver usb3503_driver = { > .id_table = usb3503_id, > }; > > -module_i2c_driver(usb3503_driver); > +static struct platform_driver usb3503_platform_driver = { > + .driver = { > + .name = USB3503_I2C_NAME, > + .of_match_table = of_match_ptr(usb3503_of_match), > + .owner = THIS_MODULE, > + }, > + .probe = usb3503_platform_probe, > +}; > + > +static int __init usb3503_init(void) > +{ > + int err; > + > + err = i2c_register_driver(THIS_MODULE, &usb3503_i2c_driver); > + if (err != 0) > + pr_err("usb3503: Failed to register I2C driver: %d\n", err); > + > + err = platform_driver_register(&usb3503_platform_driver); > + if (err != 0) > + pr_err("usb3503: Failed to register platform driver: %d\n", > + err); > + > + return 0; > +} > +module_init(usb3503_init); > + > +static void __exit usb3503_exit(void) > +{ > + platform_driver_unregister(&usb3503_platform_driver); > + i2c_del_driver(&usb3503_i2c_driver); > +} > +module_exit(usb3503_exit); > > MODULE_AUTHOR("Dongjin Kim <tobetter@xxxxxxxxx>"); > MODULE_DESCRIPTION("USB3503 USB HUB driver"); > -- > 1.8.4.rc1 > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html