RE: [PATCH v3 1/3] mfd: add support for Cypress CYUSBS234 USB Serial Bridge controller
From: Muthu Mani
Date: Fri Oct 10 2014 - 10:22:50 EST
> -----Original Message-----
> From: Lee Jones [mailto:lee.jones@xxxxxxxxxx]
> Sent: Thursday, October 09, 2014 1:10 PM
> To: Muthu Mani
> Cc: Samuel Ortiz; Wolfram Sang; Linus Walleij; Alexandre Courbot;
> gregkh@xxxxxxxxxxxxxxxxxxx; linux-i2c@xxxxxxxxxxxxxxx; linux-
> gpio@xxxxxxxxxxxxxxx; linux-usb@xxxxxxxxxxxxxxx; linux-
> kernel@xxxxxxxxxxxxxxx; Rajaram Regupathy; Johan Hovold
> Subject: Re: [PATCH v3 1/3] mfd: add support for Cypress CYUSBS234 USB
> Serial Bridge controller
>
> On Mon, 06 Oct 2014, Muthu Mani wrote:
>
> > Adds support for USB-I2C/GPIO interfaces of Cypress Semiconductor
> > CYUSBS234 USB-Serial Bridge controller.
> >
> > Details about the device can be found at:
> > http://www.cypress.com/?rID=84126
> >
> > Signed-off-by: Muthu Mani <muth@xxxxxxxxxxx>
> > Signed-off-by: Rajaram Regupathy <rera@xxxxxxxxxxx>
> > ---
> > Changes since v2:
> > * Used auto mfd id to support multiple devices
> > * Cleaned up the code
> >
> > Changes since v1:
> > * Identified different serial interface and loaded correct cell driver
> > * Formed a mfd id to support multiple devices
> > * Removed unused platform device
> >
> > drivers/mfd/Kconfig | 12 +++
> > drivers/mfd/Makefile | 1 +
> > drivers/mfd/cyusbs23x.c | 167
> ++++++++++++++++++++++++++++++++++++++++++
> > include/linux/mfd/cyusbs23x.h | 62 ++++++++++++++++
> > 4 files changed, 242 insertions(+)
> > create mode 100644 drivers/mfd/cyusbs23x.c
> > create mode 100644 include/linux/mfd/cyusbs23x.h
> >
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index de5abf2..a31e9e3 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -116,6 +116,18 @@ config MFD_ASIC3
> > This driver supports the ASIC3 multifunction chip found on many
> > PDAs (mainly iPAQ and HTC based ones)
> >
> > +config MFD_CYUSBS23X
> > + tristate "Cypress CYUSBS23x USB Serial Bridge controller"
>
> White space issue here.
Thanks for reviewing!
Sure, will fix other files as well.
>
> > + select MFD_CORE
> > + depends on USB
> > + default n
> > + help
> > + Say yes here if you want support for Cypress Semiconductor
> > + CYUSBS23x USB-Serial Bridge controller.
> > +
> > + This driver can also be built as a module. If so, the module will be
> > + called cyusbs23x.
> > +
> > config PMIC_DA903X
> > bool "Dialog Semiconductor DA9030/DA9034 PMIC Support"
> > depends on I2C=y
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index f001487..fc5bcd1 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -151,6 +151,7 @@ si476x-core-y := si476x-cmd.o si476x-prop.o si476x-
> i2c.o
> > obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
> >
> > obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
> > +obj-$(CONFIG_MFD_CYUSBS23X) += cyusbs23x.o
> > obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-
> usb-tll.o
> > obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o
> > obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
> > diff --git a/drivers/mfd/cyusbs23x.c b/drivers/mfd/cyusbs23x.c
> > new file mode 100644
> > index 0000000..c70ea40
> > --- /dev/null
> > +++ b/drivers/mfd/cyusbs23x.c
> > @@ -0,0 +1,167 @@
> > +/*
> > + * Cypress USB-Serial Bridge Controller USB adapter driver
> > + *
> > + * Copyright (c) 2014 Cypress Semiconductor Corporation.
> > + *
> > + * Author:
> > + * Muthu Mani <muth@xxxxxxxxxxx>
> > + *
> > + * Additional contributors include:
> > + * Rajaram Regupathy <rera@xxxxxxxxxxx>
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms of the GNU General Public License version 2 as
> published by
> > + * the Free Software Foundation.
> > + */
> > +
> > +/*
> > + * This is core MFD driver for Cypress Semiconductor CYUSBS234 USB-
> Serial
> > + * Bridge controller. CYUSBS234 offers a single channel serial interface
> > + * (I2C/SPI/UART). It can be configured to enable either of I2C, SPI, UART
> > + * interfaces. The GPIOs are also available to access.
> > + * Details about the device can be found at:
> > + * http://www.cypress.com/?rID=84126
> > + *
> > + * Separate cell drivers are available for I2C and GPIO. SPI and UART are
> not
> > + * supported yet. All GPIOs are exposed for get operation. However, only
> > + * unused GPIOs can be set.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/errno.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <linux/types.h>
> > +#include <linux/mutex.h>
> > +
>
> This '\n' is superfluous, please remove it.
>
> > +#include <linux/mfd/core.h>
> > +#include <linux/mfd/cyusbs23x.h>
> > +
> > +#include <linux/usb.h>
> > +
> > +static const struct usb_device_id cyusbs23x_usb_table[] = {
> > + { USB_DEVICE(0x04b4, 0x0004) }, /* Cypress Semiconductor */
> > + { } /* Terminating entry */
>
> This comment is not required, please remove it.
>
> > +};
> > +
> > +MODULE_DEVICE_TABLE(usb, cyusbs23x_usb_table);
> > +
> > +static const struct mfd_cell cyusbs23x_i2c_devs[] = {
> > + {
> > + .name = "cyusbs23x-i2c",
> > + },
> > + {
> > + .name = "cyusbs23x-gpio",
> > + },
> > +};
> > +
> > +static int update_ep_details(struct usb_interface *interface,
> > + struct cyusbs23x *cyusbs)
> > +{
> > + struct usb_host_interface *iface_desc;
> > + struct usb_endpoint_descriptor *ep;
> > + int i;
> > +
> > + iface_desc = interface->cur_altsetting;
> > +
> > + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
> > +
> > + ep = &iface_desc->endpoint[i].desc;
> > +
> > + if (!cyusbs->bulk_in_ep_num && usb_endpoint_is_bulk_in(ep))
> > + cyusbs->bulk_in_ep_num = ep->bEndpointAddress;
> > + if (!cyusbs->bulk_out_ep_num &&
> usb_endpoint_is_bulk_out(ep))
> > + cyusbs->bulk_out_ep_num = ep->bEndpointAddress;
> > + if (!cyusbs->intr_in_ep_num && usb_endpoint_is_int_in(ep))
> > + cyusbs->intr_in_ep_num = ep->bEndpointAddress;
> > + }
>
> All of the USB specific code in this driver will require a USB Ack.
>
> > + dev_dbg(&interface->dev, "%s intr_in=%d, bulk_in=%d,
> bulk_out=%d\n",
> > + __func__, cyusbs->intr_in_ep_num ,
> > + cyusbs->bulk_in_ep_num, cyusbs->bulk_out_ep_num);
> > +
> > + if (!cyusbs->bulk_in_ep_num || !cyusbs->bulk_out_ep_num ||
> > + !cyusbs->intr_in_ep_num)
> > + return -ENODEV;
> > +
> > + return 0;
> > +}
> > +
> > +static int cyusbs23x_probe(struct usb_interface *interface,
> > + const struct usb_device_id *id)
> > +{
> > + struct cyusbs23x *cyusbs;
> > + const struct mfd_cell *cyusbs23x_devs;
> > + int ret, ndevs = 0;
> > + u8 sub_class;
> > +
> > + cyusbs = kzalloc(sizeof(*cyusbs), GFP_KERNEL);
>
> Any reason for not using managed resources (devm_*)?
Ok, will use managed resources.
>
> > + if (cyusbs == NULL)
>
> if (!cyusbs)
>
> > + return -ENOMEM;
> > +
> > + cyusbs->usb_dev = usb_get_dev(interface_to_usbdev(interface));
>
> Can you do this last? Then you can remove the 'error' error path.
mfd_add_devices would utlimately invoke the cell drivers' probe before returning and cell drivers use usb_dev in their probe.
So, leaving it as such.
>
> > + cyusbs->usb_intf = interface;
> > + cyusbs->intf_num = interface->cur_altsetting-
> >desc.bInterfaceNumber;
>
> If you're already saving 'interface' there is no need to save this
> also, just extract it from 'cyusbs->usb_intf' when you need it.
>
> > + ret = update_ep_details(interface, cyusbs);
> > + if (ret < 0) {
>
> Can ret be > 0? If not, just do 'if (ret)'
>
> > + dev_err(&interface->dev, "invalid interface\n");
>
> If you put the error message in update_ep_details() can you print out
> a more specific error message and remove this line.
>
> > + goto error;
> > + }
> > +
> > + usb_set_intfdata(interface, cyusbs);
> > +
> > + /* Serial interfaces (I2C, SPI, UART) differ in interface subclass */
> > + sub_class = interface->cur_altsetting->desc.bInterfaceSubClass;
> > + switch (sub_class) {
>
> This is a waste of a variable and adds nothing to the code. Just
> switch() for 'interface->cur_altsetting->desc.bInterfaceSubClass'.
>
> > + case CY_USBS_SCB_I2C:
> > + dev_info(&interface->dev, "I2C interface found\n");
>
> Was it even lost?
>
> Would "using I2C interface" be better?
>
> > + cyusbs23x_devs = cyusbs23x_i2c_devs;
> > + ndevs = ARRAY_SIZE(cyusbs23x_i2c_devs);
> > + break;
>
> I assume there will be other interfaces supported at a later date? If
> not, this switch() is pretty over-the-top.
>
> > + default:
> > + dev_err(&interface->dev, "unsupported subclass\n");
> > + ret = -ENODEV;
> > + goto error;
> > + }
> > +
> > + ret = mfd_add_devices(&interface->dev, PLATFORM_DEVID_AUTO,
> > + cyusbs23x_devs, ndevs, NULL, 0, NULL);
> > + if (ret != 0) {
>
> if (ret)
>
> > + dev_err(&interface->dev, "Failed to add mfd devices to core\n");
>
> "Failed to register devices"
>
> > + goto error;
> > + }
> > +
> > + return 0;
> > +
> > +error:
> > + usb_put_dev(cyusbs->usb_dev);
> > + kfree(cyusbs);
> > +
> > + return ret;
> > +}
> > +
> > +static void cyusbs23x_disconnect(struct usb_interface *interface)
> > +{
> > + struct cyusbs23x *cyusbs = usb_get_intfdata(interface);
> > +
> > + mfd_remove_devices(&interface->dev);
> > + usb_put_dev(cyusbs->usb_dev);
> > + kfree(cyusbs);
>
> If you use managed resources, you can remove this line.
>
> > + dev_dbg(&interface->dev, "disconnected\n");
>
> Please remove this line.
>
> > +}
> > +
> > +static struct usb_driver cyusbs23x_usb_driver = {
> > + .name = "cyusbs23x",
> > + .probe = cyusbs23x_probe,
> > + .disconnect = cyusbs23x_disconnect,
> > + .id_table = cyusbs23x_usb_table,
> > +};
> > +
> > +module_usb_driver(cyusbs23x_usb_driver);
> > +
> > +MODULE_AUTHOR("Rajaram Regupathy <rera@xxxxxxxxxxx>");
> > +MODULE_AUTHOR("Muthu Mani <muth@xxxxxxxxxxx>");
> > +MODULE_DESCRIPTION("Cypress CYUSBS23x mfd core driver");
>
> s/mfd/MFD/
Is there a typo?
>
> > +MODULE_LICENSE("GPL v2");
> > diff --git a/include/linux/mfd/cyusbs23x.h
> b/include/linux/mfd/cyusbs23x.h
> > new file mode 100644
> > index 0000000..1580d98
> > --- /dev/null
> > +++ b/include/linux/mfd/cyusbs23x.h
> > @@ -0,0 +1,62 @@
> > +/*
> > + * Cypress USB-Serial Bridge Controller definitions
> > + *
> > + * Copyright (c) 2014 Cypress Semiconductor Corporation.
> > + *
> > + * Author:
> > + * Muthu Mani <muth@xxxxxxxxxxx>
> > + *
> > + * Additional contributors include:
> > + * Rajaram Regupathy <rera@xxxxxxxxxxx>
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms of the GNU General Public License version 2 as
> published by
> > + * the Free Software Foundation.
> > + */
> > +
> > +#ifndef __MFD_CYUSBS23X_H__
> > +#define __MFD_CYUSBS23X_H__
> > +
> > +#include <linux/types.h>
> > +#include <linux/usb.h>
> > +
> > +/* Structure to hold all device specific stuff */
> > +struct cyusbs23x {
> > + struct usb_device *usb_dev;
> > + struct usb_interface *usb_intf;
> > +
> > + u8 intf_num;
> > + u8 bulk_in_ep_num;
> > + u8 bulk_out_ep_num;
> > + u8 intr_in_ep_num;
> > +};
> > +
> > +enum cy_usbs_vendor_cmds {
> > + CY_I2C_GET_CONFIG_CMD = 0xC4,
> > + CY_I2C_SET_CONFIG_CMD = 0xC5,
> > + CY_I2C_WRITE_CMD = 0xC6,
> > + CY_I2C_READ_CMD = 0xC7,
> > + CY_I2C_GET_STATUS_CMD = 0xC8,
> > + CY_I2C_RESET_CMD = 0xC9,
> > + CY_GPIO_GET_CONFIG_CMD = 0xD8,
> > + CY_GPIO_SET_CONFIG_CMD = 0xD9,
> > + CY_GPIO_GET_VALUE_CMD = 0xDA,
> > + CY_GPIO_SET_VALUE_CMD = 0xDB,
> > +};
> > +
> > +/* Serial interfaces (I2C, SPI, UART) differ in interface subclass */
> > +enum cy_scb_modes {
> > + CY_USBS_SCB_DISABLED = 0,
> > + CY_USBS_SCB_UART = 1,
> > + CY_USBS_SCB_SPI = 2,
> > + CY_USBS_SCB_I2C = 3
>
> No need to number these.
>
> > +};
> > +
> > +/* SCB index shift */
> > +#define CY_SCB_INDEX_SHIFT 15
> > +
> > +#define CY_USBS_CTRL_XFER_TIMEOUT 2000
> > +#define CY_USBS_BULK_XFER_TIMEOUT 5000
> > +#define CY_USBS_INTR_XFER_TIMEOUT 5000
> > +
> > +#endif /* __MFD_CYUSBS23X_H__ */
>
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org â Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog
> This message and any attachments may contain Cypress (or its subsidiaries)
> confidential information. If it has been received in error, please advise the
> sender and immediately delete this message.
N§²æ¸yú²X¬¶ÇvØ)Þ{.nÇ·¥{±êX§¶¡Ü}©²ÆzÚj:+v¨¾«êZ+Êzf£¢·h§~Ûÿû®w¥¢¸?¨è&¢)ßfùy§m
á«a¶Úÿ0¶ìå