On Fri, May 26, 2017 at 02:28:24PM +0300, Alexander Amelkin wrote: > NOTE: > Please don't use the plain text here as a patch because it most probably is > corrupted by my webmail client. > Attached is a copy of the following text guaranteed to have correct > tabs/spaces. > ------------------------- Huh? > > Before this patch the max3421-hcd driver could only use > statically linked platform data to initialize its parameters. > This prevented it from being used on systems using device > tree. > > The data taken from the device tree is put into dev->platform_data > when CONFIG_OF is enabled and the device is an OpenFirmware node. > > The driver's 'compatible' string is 'maxim,max3421' > > Binding documentation is also added with this patch. Please split binding to a separate patch. > > Signed-off-by: Alexander Amelkin <alexander@xxxxxxxxxxxxxx> > --- > .../devicetree/bindings/usb/maxim,max3421-hcd.txt | 19 +++++ Drop the "-hcd" > drivers/usb/host/max3421-hcd.c | 96 > ++++++++++++++++++++-- > 2 files changed, 110 insertions(+), 5 deletions(-) > create mode 100644 > Documentation/devicetree/bindings/usb/maxim,max3421-hcd.txt > > diff --git a/Documentation/devicetree/bindings/usb/maxim,max3421-hcd.txt > b/Documentation/devicetree/bindings/usb/maxim,max3421-hcd.txt > new file mode 100644 > index 0000000..a8b9faa > --- /dev/null > +++ b/Documentation/devicetree/bindings/usb/maxim,max3421-hcd.txt > @@ -0,0 +1,19 @@ > +* SPI-based USB host controller Maxim Integrated max3421e > + > +Required properties: > +- compatible: must be "maxim,max3421" > +- reg: chip select number to which the max3421 chip is connected > + (depends on master SPI controller) > +- spi-max-frequency: the operational frequency, must not exceed <26000000> > +- interrupt-parent: phandle of the associated GPIO controller to which the > INT line Some line wrapping problems... While typically an interrupt to a board level device is a GPIO, that's outside the scope of this binding. For this binding, it is just an interrupt line. > + of max3421e chip is connected > +- interrupts: specification of the GPIO pin (in terms of the > `interrupt-parent`) > + to which INT line of max3421e chip is connected. > + The driver configures MAX3421E for active low level triggered interrupts. > + Configure your 'interrupt-parent' gpio controller accordingly. This is wrong. The flags cell tells how to configure the interrupt. > +- vbus: <GPOUTx ACTIVE_LEVEL> > + GPOUTx is the number (1-8) of GPOUT pin of max3421e used to drive Vbus. > + ACTIVE_LEVEL is 1 or 0. Just "vbus" could be a lot of things. Perhaps "maxim,vbus-en-pin". > + > +Don't forget to add pinctrl properties if you need some GPIO pins > reconfigured > +for use as INT. See binding information for the pinctrl nodes. List the properties as optional. > diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c > index 369869a..f600052 100644 > --- a/drivers/usb/host/max3421-hcd.c > +++ b/drivers/usb/host/max3421-hcd.c > @@ -61,6 +61,12 @@ > #include <linux/usb.h> > #include <linux/usb/hcd.h> > > +#if defined(CONFIG_OF) > +#include <linux/of_device.h> Probably should be of.h instead. > + > +#define MAX3421_GPOUT_COUNT 8 > +#endif Don't need an ifdef here. > + > #include <linux/platform_data/max3421-hcd.h> > > #define DRIVER_DESC "MAX3421 USB Host-Controller Driver" > @@ -1699,6 +1705,10 @@ max3421_hub_control(struct usb_hcd *hcd, u16 > type_req, u16 value, u16 index, > spin_lock_irqsave(&max3421_hcd->lock, flags); > > pdata = spi->dev.platform_data; > + if (!pdata) { > + dev_err(&spi->dev, "Device platform data is missing\n"); > + return -EFAULT; > + } > > switch (type_req) { > case ClearHubFeature: > @@ -1831,20 +1841,80 @@ static struct hc_driver max3421_hcd_desc = { > .bus_resume = max3421_bus_resume, > }; > > +#if defined(CONFIG_OF) > +static struct max3421_hcd_platform_data max3421_data; > + > +static const struct of_device_id max3421_dt_ids[] = { > + { .compatible = "maxim,max3421", .data = &max3421_data, }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, max3421_dt_ids); > +#endif > + > static int > max3421_probe(struct spi_device *spi) > { > struct max3421_hcd *max3421_hcd; > struct usb_hcd *hcd = NULL; > int retval = -ENOMEM; > +#if defined(CONFIG_OF) > + struct max3421_hcd_platform_data *pdata = NULL; > +#endif > > if (spi_setup(spi) < 0) { > dev_err(&spi->dev, "Unable to setup SPI bus"); > return -EFAULT; > } > > - hcd = usb_create_hcd(&max3421_hcd_desc, &spi->dev, > - dev_name(&spi->dev)); > + if (!spi->irq) { > + dev_err(&spi->dev, "Failed to get SPI IRQ for node '%s'\n", > spi->dev.of_node->full_name); > + return -EFAULT; > + } > + > +#if defined(CONFIG_OF) > + if (spi->dev.of_node) { if (IS_ENABLED(CONFIG_OF) && spi->dev.of_node) > + /* A temporary alias structure */ > + union { > + uint32_t value[2]; > + struct { > + uint32_t gpout; > + uint32_t active_level; > + }; > + } vbus; > + > + if(!(pdata = devm_kzalloc(&spi->dev, sizeof(*pdata), GFP_KERNEL))) { > + dev_err(&spi->dev, "failed to allocate memory for private > data\n"); > + retval = -ENOMEM; > + goto error; > + } > + spi->dev.platform_data = pdata; > + > + if ((retval = of_property_read_u32_array(spi->dev.of_node, "vbus", > vbus.value, 2))) { > + dev_err(&spi->dev, "device tree node property 'vbus' is > missing\n"); > + goto error; > + } > + pdata->vbus_gpout = vbus.gpout; > + pdata->vbus_active_level = vbus.active_level; > + } > + else > +#endif > + pdata = spi->dev.platform_data; > + if (!pdata) { > + dev_err(&spi->dev, "driver configuration data is not provided\n"); > + retval = -EFAULT; > + goto error; > + } > + if (pdata->vbus_active_level > 1) { > + dev_err(&spi->dev, "vbus active level value %d is out of range > (0/1)\n", pdata->vbus_active_level); > + retval = -EINVAL; > + goto error; > + } > + if (pdata->vbus_gpout < 1 || pdata->vbus_gpout > MAX3421_GPOUT_COUNT) { > + dev_err(&spi->dev, "vbus gpout value %d is out of range (1..8)\n", > pdata->vbus_gpout); > + retval = -EINVAL; > + goto error; > + } > + hcd = usb_create_hcd(&max3421_hcd_desc, &spi->dev, dev_name(&spi->dev)); > if (!hcd) { > dev_err(&spi->dev, "failed to create HCD structure\n"); > goto error; > @@ -1892,6 +1962,12 @@ max3421_probe(struct spi_device *spi) > kthread_stop(max3421_hcd->spi_thread); > usb_put_hcd(hcd); > } > +#if defined(CONFIG_OF) > + if (pdata && spi->dev.platform_data == pdata) { IS_ENABLED... > + devm_kfree(&spi->dev, pdata); > + spi->dev.platform_data = NULL; > + } > +#endif > return retval; > } > > @@ -1908,14 +1984,12 @@ max3421_remove(struct spi_device *spi) > if (hcd->self.controller == &spi->dev) > break; > } > + Spurious change. > if (!max3421_hcd) { > dev_err(&spi->dev, "no MAX3421 HCD found for SPI device %p\n", > spi); > return -ENODEV; > } > - > - usb_remove_hcd(hcd); > - > spin_lock_irqsave(&max3421_hcd->lock, flags); > > kthread_stop(max3421_hcd->spi_thread); > @@ -1923,8 +1997,19 @@ max3421_remove(struct spi_device *spi) > > spin_unlock_irqrestore(&max3421_hcd->lock, flags); > > +#if defined(CONFIG_OF) > + if (spi->dev.platform_data) { > + dev_dbg(&spi->dev, "Freeing platform data structure\n"); > + devm_kfree(&spi->dev, spi->dev.platform_data); > + spi->dev.platform_data = NULL; > + } > +#endif > + > free_irq(spi->irq, hcd); > > + usb_remove_hcd(hcd); > + > + One blank line. > usb_put_hcd(hcd); > return 0; > } > @@ -1934,6 +2019,7 @@ static struct spi_driver max3421_driver = { > .remove = max3421_remove, > .driver = { > .name = "max3421-hcd", > + .of_match_table = of_match_ptr(max3421_dt_ids), > }, > }; > > -- > 2.7.4 > From 0eb4464398c8b0a336aa0305724b4b84ef2be097 Mon Sep 17 00:00:00 2001 > From: Alexander Amelkin <amelkin@xxxxxxxxxx> > Date: Tue, 28 Mar 2017 20:59:06 +0300 > Subject: [PATCH 1/3] usb: max3421-hcd: Add devicetree support to the driver > > Before this patch the max3421-hcd driver could only use > statically linked platform data to initialize its parameters. > This prevented it from being used on systems using device > tree. > > The data taken from the device tree is put into dev->platform_data > when CONFIG_OF is enabled and the device is an OpenFirmware node. > > The driver's 'compatible' string is 'maxim,max3421' > > Binding documentation is also added with this patch. > > Signed-off-by: Alexander Amelkin <alexander@xxxxxxxxxxxxxx> > --- > .../devicetree/bindings/usb/maxim,max3421-hcd.txt | 19 +++++ > drivers/usb/host/max3421-hcd.c | 96 ++++++++++++++++++++-- > 2 files changed, 110 insertions(+), 5 deletions(-) > create mode 100644 Documentation/devicetree/bindings/usb/maxim,max3421-hcd.txt > > diff --git a/Documentation/devicetree/bindings/usb/maxim,max3421-hcd.txt b/Documentation/devicetree/bindings/usb/maxim,max3421-hcd.txt > new file mode 100644 > index 0000000..a8b9faa > --- /dev/null > +++ b/Documentation/devicetree/bindings/usb/maxim,max3421-hcd.txt > @@ -0,0 +1,19 @@ > +* SPI-based USB host controller Maxim Integrated max3421e > + > +Required properties: > +- compatible: must be "maxim,max3421" > +- reg: chip select number to which the max3421 chip is connected > + (depends on master SPI controller) > +- spi-max-frequency: the operational frequency, must not exceed <26000000> > +- interrupt-parent: phandle of the associated GPIO controller to which the INT line > + of max3421e chip is connected > +- interrupts: specification of the GPIO pin (in terms of the `interrupt-parent`) > + to which INT line of max3421e chip is connected. > + The driver configures MAX3421E for active low level triggered interrupts. > + Configure your 'interrupt-parent' gpio controller accordingly. > +- vbus: <GPOUTx ACTIVE_LEVEL> > + GPOUTx is the number (1-8) of GPOUT pin of max3421e used to drive Vbus. > + ACTIVE_LEVEL is 1 or 0. > + > +Don't forget to add pinctrl properties if you need some GPIO pins reconfigured > +for use as INT. See binding information for the pinctrl nodes. > diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c > index 369869a..f600052 100644 > --- a/drivers/usb/host/max3421-hcd.c > +++ b/drivers/usb/host/max3421-hcd.c > @@ -61,6 +61,12 @@ > #include <linux/usb.h> > #include <linux/usb/hcd.h> > > +#if defined(CONFIG_OF) > +#include <linux/of_device.h> > + > +#define MAX3421_GPOUT_COUNT 8 > +#endif > + > #include <linux/platform_data/max3421-hcd.h> > > #define DRIVER_DESC "MAX3421 USB Host-Controller Driver" > @@ -1699,6 +1705,10 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index, > spin_lock_irqsave(&max3421_hcd->lock, flags); > > pdata = spi->dev.platform_data; > + if (!pdata) { > + dev_err(&spi->dev, "Device platform data is missing\n"); > + return -EFAULT; > + } > > switch (type_req) { > case ClearHubFeature: > @@ -1831,20 +1841,80 @@ static struct hc_driver max3421_hcd_desc = { > .bus_resume = max3421_bus_resume, > }; > > +#if defined(CONFIG_OF) > +static struct max3421_hcd_platform_data max3421_data; > + > +static const struct of_device_id max3421_dt_ids[] = { > + { .compatible = "maxim,max3421", .data = &max3421_data, }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, max3421_dt_ids); > +#endif > + > static int > max3421_probe(struct spi_device *spi) > { > struct max3421_hcd *max3421_hcd; > struct usb_hcd *hcd = NULL; > int retval = -ENOMEM; > +#if defined(CONFIG_OF) > + struct max3421_hcd_platform_data *pdata = NULL; > +#endif > > if (spi_setup(spi) < 0) { > dev_err(&spi->dev, "Unable to setup SPI bus"); > return -EFAULT; > } > > - hcd = usb_create_hcd(&max3421_hcd_desc, &spi->dev, > - dev_name(&spi->dev)); > + if (!spi->irq) { > + dev_err(&spi->dev, "Failed to get SPI IRQ for node '%s'\n", spi->dev.of_node->full_name); > + return -EFAULT; > + } > + > +#if defined(CONFIG_OF) > + if (spi->dev.of_node) { > + /* A temporary alias structure */ > + union { > + uint32_t value[2]; > + struct { > + uint32_t gpout; > + uint32_t active_level; > + }; > + } vbus; > + > + if(!(pdata = devm_kzalloc(&spi->dev, sizeof(*pdata), GFP_KERNEL))) { > + dev_err(&spi->dev, "failed to allocate memory for private data\n"); > + retval = -ENOMEM; > + goto error; > + } > + spi->dev.platform_data = pdata; > + > + if ((retval = of_property_read_u32_array(spi->dev.of_node, "vbus", vbus.value, 2))) { > + dev_err(&spi->dev, "device tree node property 'vbus' is missing\n"); > + goto error; > + } > + pdata->vbus_gpout = vbus.gpout; > + pdata->vbus_active_level = vbus.active_level; > + } > + else > +#endif > + pdata = spi->dev.platform_data; > + if (!pdata) { > + dev_err(&spi->dev, "driver configuration data is not provided\n"); > + retval = -EFAULT; > + goto error; > + } > + if (pdata->vbus_active_level > 1) { > + dev_err(&spi->dev, "vbus active level value %d is out of range (0/1)\n", pdata->vbus_active_level); > + retval = -EINVAL; > + goto error; > + } > + if (pdata->vbus_gpout < 1 || pdata->vbus_gpout > MAX3421_GPOUT_COUNT) { > + dev_err(&spi->dev, "vbus gpout value %d is out of range (1..8)\n", pdata->vbus_gpout); > + retval = -EINVAL; > + goto error; > + } > + hcd = usb_create_hcd(&max3421_hcd_desc, &spi->dev, dev_name(&spi->dev)); > if (!hcd) { > dev_err(&spi->dev, "failed to create HCD structure\n"); > goto error; > @@ -1892,6 +1962,12 @@ max3421_probe(struct spi_device *spi) > kthread_stop(max3421_hcd->spi_thread); > usb_put_hcd(hcd); > } > +#if defined(CONFIG_OF) > + if (pdata && spi->dev.platform_data == pdata) { > + devm_kfree(&spi->dev, pdata); > + spi->dev.platform_data = NULL; > + } > +#endif > return retval; > } > > @@ -1908,14 +1984,12 @@ max3421_remove(struct spi_device *spi) > if (hcd->self.controller == &spi->dev) > break; > } > + > if (!max3421_hcd) { > dev_err(&spi->dev, "no MAX3421 HCD found for SPI device %p\n", > spi); > return -ENODEV; > } > - > - usb_remove_hcd(hcd); > - > spin_lock_irqsave(&max3421_hcd->lock, flags); > > kthread_stop(max3421_hcd->spi_thread); > @@ -1923,8 +1997,19 @@ max3421_remove(struct spi_device *spi) > > spin_unlock_irqrestore(&max3421_hcd->lock, flags); > > +#if defined(CONFIG_OF) > + if (spi->dev.platform_data) { > + dev_dbg(&spi->dev, "Freeing platform data structure\n"); > + devm_kfree(&spi->dev, spi->dev.platform_data); > + spi->dev.platform_data = NULL; > + } > +#endif > + > free_irq(spi->irq, hcd); > > + usb_remove_hcd(hcd); > + > + > usb_put_hcd(hcd); > return 0; > } > @@ -1934,6 +2019,7 @@ static struct spi_driver max3421_driver = { > .remove = max3421_remove, > .driver = { > .name = "max3421-hcd", > + .of_match_table = of_match_ptr(max3421_dt_ids), > }, > }; > > -- > 2.7.4 > -- 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