Re: [PATCH 1/3] usb: max3421-hcd: Add devicetree support to the driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux