diff mbox

[v3,1/3] mfd: add support for Cypress CYUSBS234 USB Serial Bridge controller

Message ID 1412606587-3323-1-git-send-email-muth@cypress.com
State Not Applicable, archived
Headers show

Commit Message

Muthu Mani Oct. 6, 2014, 2:43 p.m. UTC
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@cypress.com>
Signed-off-by: Rajaram Regupathy <rera@cypress.com>
---
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

Comments

Lee Jones Oct. 9, 2014, 7:40 a.m. UTC | #1
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@cypress.com>
> Signed-off-by: Rajaram Regupathy <rera@cypress.com>
> ---
> 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.

> +	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@cypress.com>
> + *
> + * Additional contributors include:
> + *   Rajaram Regupathy <rera@cypress.com>
> + *
> + * 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_*)?

> +	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.

> +	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@cypress.com>");
> +MODULE_AUTHOR("Muthu Mani <muth@cypress.com>");
> +MODULE_DESCRIPTION("Cypress CYUSBS23x mfd core driver");

s/mfd/MFD/

> +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@cypress.com>
> + *
> + * Additional contributors include:
> + *   Rajaram Regupathy <rera@cypress.com>
> + *
> + * 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__ */
Johan Hovold Oct. 9, 2014, 8:15 a.m. UTC | #2
On Thu, Oct 09, 2014 at 08:40:29AM +0100, Lee Jones wrote:
> On Mon, 06 Oct 2014, Muthu Mani wrote:

> > +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.

I'll review it once the incomplete gpio-driver issue has been resolved.

> > +	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;
> > +}

[...]

> > diff --git a/include/linux/mfd/cyusbs23x.h b/include/linux/mfd/cyusbs23x.h

> > +/* 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.

As it's not an arbitrary enumeration, I think they should be initialised
explicitly. They could be defined in the mfd driver though, as they only
appear to be needed during probe.

Johan
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lee Jones Oct. 9, 2014, 10:59 a.m. UTC | #3
On Thu, 09 Oct 2014, Johan Hovold wrote:

> On Thu, Oct 09, 2014 at 08:40:29AM +0100, Lee Jones wrote:
> > On Mon, 06 Oct 2014, Muthu Mani wrote:
> 
> > > +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.
> 
> I'll review it once the incomplete gpio-driver issue has been resolved.

Okay, great.

> > > +	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;
> > > +}
> 
> [...]
> 
> > > diff --git a/include/linux/mfd/cyusbs23x.h b/include/linux/mfd/cyusbs23x.h
> 
> > > +/* 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.
> 
> As it's not an arbitrary enumeration, I think they should be initialised
> explicitly.

No need.  You are protected by the C Standard:

6.7.2.2 Enumeration specifiers

"If the first enumerator has no =, the value of its enumeration
constant is 0. Each subsequent enumerator with no = defines its
enumeration constant as the value of the constant expression obtained
by adding 1 to the value of the previous enumeration constant."

There's nothing arbitrary about that.

> They could be defined in the mfd driver though, as they only
> appear to be needed during probe.
Johan Hovold Oct. 9, 2014, 12:58 p.m. UTC | #4
On Thu, Oct 09, 2014 at 11:59:50AM +0100, Lee Jones wrote:
> On Thu, 09 Oct 2014, Johan Hovold wrote:
> > On Thu, Oct 09, 2014 at 08:40:29AM +0100, Lee Jones wrote:
> > > On Mon, 06 Oct 2014, Muthu Mani wrote:

> > > > diff --git a/include/linux/mfd/cyusbs23x.h b/include/linux/mfd/cyusbs23x.h
> > 
> > > > +/* 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.
> > 
> > As it's not an arbitrary enumeration, I think they should be initialised
> > explicitly.
> 
> No need.  You are protected by the C Standard:
> 
> 6.7.2.2 Enumeration specifiers
> 
> "If the first enumerator has no =, the value of its enumeration
> constant is 0. Each subsequent enumerator with no = defines its
> enumeration constant as the value of the constant expression obtained
> by adding 1 to the value of the previous enumeration constant."
> 
> There's nothing arbitrary about that.

I obviously wasn't suggesting that the definition of an enum (and the
values of its constants) in c was arbitrary.

My point was that the values of the USB interface subclasses (defined
through the enum) are not arbitrary. In this case they just happen to be
zero-based and consecutive. You cannot reorder, or remove an unused
item, without breaking the driver. By initialising each constant
explicitly this would become apparent.

Using preprocessor defines could be an alternative if you really do not
like initialised enumeration constants.

> > They could be defined in the mfd driver though, as they only
> > appear to be needed during probe.

Johan
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Muthu Mani Oct. 10, 2014, 2:22 p.m. UTC | #5
PiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiBGcm9tOiBMZWUgSm9uZXMgW21haWx0bzps
ZWUuam9uZXNAbGluYXJvLm9yZ10NCj4gU2VudDogVGh1cnNkYXksIE9jdG9iZXIgMDksIDIwMTQg
MToxMCBQTQ0KPiBUbzogTXV0aHUgTWFuaQ0KPiBDYzogU2FtdWVsIE9ydGl6OyBXb2xmcmFtIFNh
bmc7IExpbnVzIFdhbGxlaWo7IEFsZXhhbmRyZSBDb3VyYm90Ow0KPiBncmVna2hAbGludXhmb3Vu
ZGF0aW9uLm9yZzsgbGludXgtaTJjQHZnZXIua2VybmVsLm9yZzsgbGludXgtDQo+IGdwaW9Admdl
ci5rZXJuZWwub3JnOyBsaW51eC11c2JAdmdlci5rZXJuZWwub3JnOyBsaW51eC0NCj4ga2VybmVs
QHZnZXIua2VybmVsLm9yZzsgUmFqYXJhbSBSZWd1cGF0aHk7IEpvaGFuIEhvdm9sZA0KPiBTdWJq
ZWN0OiBSZTogW1BBVENIIHYzIDEvM10gbWZkOiBhZGQgc3VwcG9ydCBmb3IgQ3lwcmVzcyBDWVVT
QlMyMzQgVVNCDQo+IFNlcmlhbCBCcmlkZ2UgY29udHJvbGxlcg0KPiANCj4gT24gTW9uLCAwNiBP
Y3QgMjAxNCwgTXV0aHUgTWFuaSB3cm90ZToNCj4gDQo+ID4gQWRkcyBzdXBwb3J0IGZvciBVU0It
STJDL0dQSU8gaW50ZXJmYWNlcyBvZiBDeXByZXNzIFNlbWljb25kdWN0b3INCj4gPiBDWVVTQlMy
MzQgVVNCLVNlcmlhbCBCcmlkZ2UgY29udHJvbGxlci4NCj4gPg0KPiA+IERldGFpbHMgYWJvdXQg
dGhlIGRldmljZSBjYW4gYmUgZm91bmQgYXQ6DQo+ID4gaHR0cDovL3d3dy5jeXByZXNzLmNvbS8/
cklEPTg0MTI2DQo+ID4NCj4gPiBTaWduZWQtb2ZmLWJ5OiBNdXRodSBNYW5pIDxtdXRoQGN5cHJl
c3MuY29tPg0KPiA+IFNpZ25lZC1vZmYtYnk6IFJhamFyYW0gUmVndXBhdGh5IDxyZXJhQGN5cHJl
c3MuY29tPg0KPiA+IC0tLQ0KPiA+IENoYW5nZXMgc2luY2UgdjI6DQo+ID4gKiBVc2VkIGF1dG8g
bWZkIGlkIHRvIHN1cHBvcnQgbXVsdGlwbGUgZGV2aWNlcw0KPiA+ICogQ2xlYW5lZCB1cCB0aGUg
Y29kZQ0KPiA+DQo+ID4gQ2hhbmdlcyBzaW5jZSB2MToNCj4gPiAqIElkZW50aWZpZWQgZGlmZmVy
ZW50IHNlcmlhbCBpbnRlcmZhY2UgYW5kIGxvYWRlZCBjb3JyZWN0IGNlbGwgZHJpdmVyDQo+ID4g
KiBGb3JtZWQgYSBtZmQgaWQgdG8gc3VwcG9ydCBtdWx0aXBsZSBkZXZpY2VzDQo+ID4gKiBSZW1v
dmVkIHVudXNlZCBwbGF0Zm9ybSBkZXZpY2UNCj4gPg0KPiA+ICBkcml2ZXJzL21mZC9LY29uZmln
ICAgICAgICAgICB8ICAxMiArKysNCj4gPiAgZHJpdmVycy9tZmQvTWFrZWZpbGUgICAgICAgICAg
fCAgIDEgKw0KPiA+ICBkcml2ZXJzL21mZC9jeXVzYnMyM3guYyAgICAgICB8IDE2Nw0KPiArKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysNCj4gPiAgaW5jbHVkZS9saW51
eC9tZmQvY3l1c2JzMjN4LmggfCAgNjIgKysrKysrKysrKysrKysrKw0KPiA+ICA0IGZpbGVzIGNo
YW5nZWQsIDI0MiBpbnNlcnRpb25zKCspDQo+ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJz
L21mZC9jeXVzYnMyM3guYw0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgaW5jbHVkZS9saW51eC9t
ZmQvY3l1c2JzMjN4LmgNCj4gPg0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL21mZC9LY29uZmln
IGIvZHJpdmVycy9tZmQvS2NvbmZpZw0KPiA+IGluZGV4IGRlNWFiZjIuLmEzMWU5ZTMgMTAwNjQ0
DQo+ID4gLS0tIGEvZHJpdmVycy9tZmQvS2NvbmZpZw0KPiA+ICsrKyBiL2RyaXZlcnMvbWZkL0tj
b25maWcNCj4gPiBAQCAtMTE2LDYgKzExNiwxOCBAQCBjb25maWcgTUZEX0FTSUMzDQo+ID4gICAg
ICAgICBUaGlzIGRyaXZlciBzdXBwb3J0cyB0aGUgQVNJQzMgbXVsdGlmdW5jdGlvbiBjaGlwIGZv
dW5kIG9uIG1hbnkNCj4gPiAgICAgICAgIFBEQXMgKG1haW5seSBpUEFRIGFuZCBIVEMgYmFzZWQg
b25lcykNCj4gPg0KPiA+ICtjb25maWcgTUZEX0NZVVNCUzIzWA0KPiA+ICsgICAgICAgIHRyaXN0
YXRlICJDeXByZXNzIENZVVNCUzIzeCBVU0IgU2VyaWFsIEJyaWRnZSBjb250cm9sbGVyIg0KPiAN
Cj4gV2hpdGUgc3BhY2UgaXNzdWUgaGVyZS4NCg0KVGhhbmtzIGZvciByZXZpZXdpbmchDQpTdXJl
LCB3aWxsIGZpeCBvdGhlciBmaWxlcyBhcyB3ZWxsLg0KDQo+IA0KPiA+ICsgICAgIHNlbGVjdCBN
RkRfQ09SRQ0KPiA+ICsgICAgIGRlcGVuZHMgb24gVVNCDQo+ID4gKyAgICAgZGVmYXVsdCBuDQo+
ID4gKyAgICAgaGVscA0KPiA+ICsgICAgICAgU2F5IHllcyBoZXJlIGlmIHlvdSB3YW50IHN1cHBv
cnQgZm9yIEN5cHJlc3MgU2VtaWNvbmR1Y3Rvcg0KPiA+ICsgICAgICAgQ1lVU0JTMjN4IFVTQi1T
ZXJpYWwgQnJpZGdlIGNvbnRyb2xsZXIuDQo+ID4gKw0KPiA+ICsgICAgICAgVGhpcyBkcml2ZXIg
Y2FuIGFsc28gYmUgYnVpbHQgYXMgYSBtb2R1bGUuIElmIHNvLCB0aGUgbW9kdWxlIHdpbGwgYmUN
Cj4gPiArICAgICAgIGNhbGxlZCBjeXVzYnMyM3guDQo+ID4gKw0KPiA+ICBjb25maWcgUE1JQ19E
QTkwM1gNCj4gPiAgICAgICBib29sICJEaWFsb2cgU2VtaWNvbmR1Y3RvciBEQTkwMzAvREE5MDM0
IFBNSUMgU3VwcG9ydCINCj4gPiAgICAgICBkZXBlbmRzIG9uIEkyQz15DQo+ID4gZGlmZiAtLWdp
dCBhL2RyaXZlcnMvbWZkL01ha2VmaWxlIGIvZHJpdmVycy9tZmQvTWFrZWZpbGUNCj4gPiBpbmRl
eCBmMDAxNDg3Li5mYzViY2QxIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbWZkL01ha2VmaWxl
DQo+ID4gKysrIGIvZHJpdmVycy9tZmQvTWFrZWZpbGUNCj4gPiBAQCAtMTUxLDYgKzE1MSw3IEBA
IHNpNDc2eC1jb3JlLXkgOj0gc2k0NzZ4LWNtZC5vIHNpNDc2eC1wcm9wLm8gc2k0NzZ4LQ0KPiBp
MmMubw0KPiA+ICBvYmotJChDT05GSUdfTUZEX1NJNDc2WF9DT1JFKSAgICAgICAgKz0gc2k0NzZ4
LWNvcmUubw0KPiA+DQo+ID4gIG9iai0kKENPTkZJR19NRkRfQ1M1NTM1KSAgICAgKz0gY3M1NTM1
LW1mZC5vDQo+ID4gK29iai0kKENPTkZJR19NRkRfQ1lVU0JTMjNYKSAgICAgKz0gY3l1c2JzMjN4
Lm8NCj4gPiAgb2JqLSQoQ09ORklHX01GRF9PTUFQX1VTQl9IT1NUKSAgICAgICs9IG9tYXAtdXNi
LWhvc3QubyBvbWFwLQ0KPiB1c2ItdGxsLm8NCj4gPiAgb2JqLSQoQ09ORklHX01GRF9QTTg5MjFf
Q09SRSkgICAgICAgICs9IHBtODkyMS1jb3JlLm8gc3NiaS5vDQo+ID4gIG9iai0kKENPTkZJR19U
UFM2NTkxMV9DT01QQVJBVE9SKSAgICArPSB0cHM2NTkxMS1jb21wYXJhdG9yLm8NCj4gPiBkaWZm
IC0tZ2l0IGEvZHJpdmVycy9tZmQvY3l1c2JzMjN4LmMgYi9kcml2ZXJzL21mZC9jeXVzYnMyM3gu
Yw0KPiA+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0DQo+ID4gaW5kZXggMDAwMDAwMC4uYzcwZWE0MA0K
PiA+IC0tLSAvZGV2L251bGwNCj4gPiArKysgYi9kcml2ZXJzL21mZC9jeXVzYnMyM3guYw0KPiA+
IEBAIC0wLDAgKzEsMTY3IEBADQo+ID4gKy8qDQo+ID4gKyAqIEN5cHJlc3MgVVNCLVNlcmlhbCBC
cmlkZ2UgQ29udHJvbGxlciBVU0IgYWRhcHRlciBkcml2ZXINCj4gPiArICoNCj4gPiArICogQ29w
eXJpZ2h0IChjKSAyMDE0IEN5cHJlc3MgU2VtaWNvbmR1Y3RvciBDb3Jwb3JhdGlvbi4NCj4gPiAr
ICoNCj4gPiArICogQXV0aG9yOg0KPiA+ICsgKiAgIE11dGh1IE1hbmkgPG11dGhAY3lwcmVzcy5j
b20+DQo+ID4gKyAqDQo+ID4gKyAqIEFkZGl0aW9uYWwgY29udHJpYnV0b3JzIGluY2x1ZGU6DQo+
ID4gKyAqICAgUmFqYXJhbSBSZWd1cGF0aHkgPHJlcmFAY3lwcmVzcy5jb20+DQo+ID4gKyAqDQo+
ID4gKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0
ZSBpdCBhbmQvb3IgbW9kaWZ5IGl0DQo+ID4gKyAqIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05V
IEdlbmVyYWwgUHVibGljIExpY2Vuc2UgdmVyc2lvbiAyIGFzDQo+IHB1Ymxpc2hlZCBieQ0KPiA+
ICsgKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLg0KPiA+ICsgKi8NCj4gPiArDQo+ID4g
Ky8qDQo+ID4gKyAqIFRoaXMgaXMgY29yZSBNRkQgZHJpdmVyIGZvciBDeXByZXNzIFNlbWljb25k
dWN0b3IgQ1lVU0JTMjM0IFVTQi0NCj4gU2VyaWFsDQo+ID4gKyAqIEJyaWRnZSBjb250cm9sbGVy
LiBDWVVTQlMyMzQgb2ZmZXJzIGEgc2luZ2xlIGNoYW5uZWwgc2VyaWFsIGludGVyZmFjZQ0KPiA+
ICsgKiAoSTJDL1NQSS9VQVJUKS4gSXQgY2FuIGJlIGNvbmZpZ3VyZWQgdG8gZW5hYmxlIGVpdGhl
ciBvZiBJMkMsIFNQSSwgVUFSVA0KPiA+ICsgKiBpbnRlcmZhY2VzLiBUaGUgR1BJT3MgYXJlIGFs
c28gYXZhaWxhYmxlIHRvIGFjY2Vzcy4NCj4gPiArICogRGV0YWlscyBhYm91dCB0aGUgZGV2aWNl
IGNhbiBiZSBmb3VuZCBhdDoNCj4gPiArICogICAgaHR0cDovL3d3dy5jeXByZXNzLmNvbS8/cklE
PTg0MTI2DQo+ID4gKyAqDQo+ID4gKyAqIFNlcGFyYXRlIGNlbGwgZHJpdmVycyBhcmUgYXZhaWxh
YmxlIGZvciBJMkMgYW5kIEdQSU8uIFNQSSBhbmQgVUFSVCBhcmUNCj4gbm90DQo+ID4gKyAqIHN1
cHBvcnRlZCB5ZXQuIEFsbCBHUElPcyBhcmUgZXhwb3NlZCBmb3IgZ2V0IG9wZXJhdGlvbi4gSG93
ZXZlciwgb25seQ0KPiA+ICsgKiB1bnVzZWQgR1BJT3MgY2FuIGJlIHNldC4NCj4gPiArICovDQo+
ID4gKw0KPiA+ICsjaW5jbHVkZSA8bGludXgva2VybmVsLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51
eC9lcnJuby5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+DQo+ID4gKyNpbmNsdWRl
IDxsaW51eC9zbGFiLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC90eXBlcy5oPg0KPiA+ICsjaW5j
bHVkZSA8bGludXgvbXV0ZXguaD4NCj4gPiArDQo+IA0KPiBUaGlzICdcbicgaXMgc3VwZXJmbHVv
dXMsIHBsZWFzZSByZW1vdmUgaXQuDQo+IA0KPiA+ICsjaW5jbHVkZSA8bGludXgvbWZkL2NvcmUu
aD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L21mZC9jeXVzYnMyM3guaD4NCj4gPiArDQo+ID4gKyNp
bmNsdWRlIDxsaW51eC91c2IuaD4NCj4gPiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgdXNi
X2RldmljZV9pZCBjeXVzYnMyM3hfdXNiX3RhYmxlW10gPSB7DQo+ID4gKyAgICAgeyBVU0JfREVW
SUNFKDB4MDRiNCwgMHgwMDA0KSB9LCAgIC8qIEN5cHJlc3MgU2VtaWNvbmR1Y3RvciAqLw0KPiA+
ICsgICAgIHsgfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBUZXJtaW5hdGluZyBl
bnRyeSAqLw0KPiANCj4gVGhpcyBjb21tZW50IGlzIG5vdCByZXF1aXJlZCwgcGxlYXNlIHJlbW92
ZSBpdC4NCj4gDQo+ID4gK307DQo+ID4gKw0KPiA+ICtNT0RVTEVfREVWSUNFX1RBQkxFKHVzYiwg
Y3l1c2JzMjN4X3VzYl90YWJsZSk7DQo+ID4gKw0KPiA+ICtzdGF0aWMgY29uc3Qgc3RydWN0IG1m
ZF9jZWxsIGN5dXNiczIzeF9pMmNfZGV2c1tdID0gew0KPiA+ICsgICAgIHsNCj4gPiArICAgICAg
ICAgICAgIC5uYW1lID0gImN5dXNiczIzeC1pMmMiLA0KPiA+ICsgICAgIH0sDQo+ID4gKyAgICAg
ew0KPiA+ICsgICAgICAgICAgICAgLm5hbWUgPSAiY3l1c2JzMjN4LWdwaW8iLA0KPiA+ICsgICAg
IH0sDQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IHVwZGF0ZV9lcF9kZXRhaWxzKHN0
cnVjdCB1c2JfaW50ZXJmYWNlICppbnRlcmZhY2UsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgc3RydWN0IGN5dXNiczIzeCAqY3l1c2JzKQ0KPiA+ICt7DQo+ID4gKyAgICAgc3Ry
dWN0IHVzYl9ob3N0X2ludGVyZmFjZSAqaWZhY2VfZGVzYzsNCj4gPiArICAgICBzdHJ1Y3QgdXNi
X2VuZHBvaW50X2Rlc2NyaXB0b3IgKmVwOw0KPiA+ICsgICAgIGludCBpOw0KPiA+ICsNCj4gPiAr
ICAgICBpZmFjZV9kZXNjID0gaW50ZXJmYWNlLT5jdXJfYWx0c2V0dGluZzsNCj4gPiArDQo+ID4g
KyAgICAgZm9yIChpID0gMDsgaSA8IGlmYWNlX2Rlc2MtPmRlc2MuYk51bUVuZHBvaW50czsgKytp
KSB7DQo+ID4gKw0KPiA+ICsgICAgICAgICAgICAgZXAgPSAmaWZhY2VfZGVzYy0+ZW5kcG9pbnRb
aV0uZGVzYzsNCj4gPiArDQo+ID4gKyAgICAgICAgICAgICBpZiAoIWN5dXNicy0+YnVsa19pbl9l
cF9udW0gJiYgdXNiX2VuZHBvaW50X2lzX2J1bGtfaW4oZXApKQ0KPiA+ICsgICAgICAgICAgICAg
ICAgICAgICBjeXVzYnMtPmJ1bGtfaW5fZXBfbnVtID0gZXAtPmJFbmRwb2ludEFkZHJlc3M7DQo+
ID4gKyAgICAgICAgICAgICBpZiAoIWN5dXNicy0+YnVsa19vdXRfZXBfbnVtICYmDQo+IHVzYl9l
bmRwb2ludF9pc19idWxrX291dChlcCkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIGN5dXNi
cy0+YnVsa19vdXRfZXBfbnVtID0gZXAtPmJFbmRwb2ludEFkZHJlc3M7DQo+ID4gKyAgICAgICAg
ICAgICBpZiAoIWN5dXNicy0+aW50cl9pbl9lcF9udW0gJiYgdXNiX2VuZHBvaW50X2lzX2ludF9p
bihlcCkpDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgIGN5dXNicy0+aW50cl9pbl9lcF9udW0g
PSBlcC0+YkVuZHBvaW50QWRkcmVzczsNCj4gPiArICAgICB9DQo+IA0KPiBBbGwgb2YgdGhlIFVT
QiBzcGVjaWZpYyBjb2RlIGluIHRoaXMgZHJpdmVyIHdpbGwgcmVxdWlyZSBhIFVTQiBBY2suDQo+
IA0KPiA+ICsgICAgIGRldl9kYmcoJmludGVyZmFjZS0+ZGV2LCAiJXMgaW50cl9pbj0lZCwgYnVs
a19pbj0lZCwNCj4gYnVsa19vdXQ9JWRcbiIsDQo+ID4gKyAgICAgICAgICAgICBfX2Z1bmNfXywg
Y3l1c2JzLT5pbnRyX2luX2VwX251bSAsDQo+ID4gKyAgICAgICAgICAgICBjeXVzYnMtPmJ1bGtf
aW5fZXBfbnVtLCBjeXVzYnMtPmJ1bGtfb3V0X2VwX251bSk7DQo+ID4gKw0KPiA+ICsgICAgIGlm
ICghY3l1c2JzLT5idWxrX2luX2VwX251bSB8fCAhY3l1c2JzLT5idWxrX291dF9lcF9udW0gfHwN
Cj4gPiArICAgICAgICAgICAgICFjeXVzYnMtPmludHJfaW5fZXBfbnVtKQ0KPiA+ICsgICAgICAg
ICAgICAgcmV0dXJuIC1FTk9ERVY7DQo+ID4gKw0KPiA+ICsgICAgIHJldHVybiAwOw0KPiA+ICt9
DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGN5dXNiczIzeF9wcm9iZShzdHJ1Y3QgdXNiX2ludGVy
ZmFjZSAqaW50ZXJmYWNlLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzdHJ1
Y3QgdXNiX2RldmljZV9pZCAqaWQpDQo+ID4gK3sNCj4gPiArICAgICBzdHJ1Y3QgY3l1c2JzMjN4
ICpjeXVzYnM7DQo+ID4gKyAgICAgY29uc3Qgc3RydWN0IG1mZF9jZWxsICpjeXVzYnMyM3hfZGV2
czsNCj4gPiArICAgICBpbnQgcmV0LCBuZGV2cyA9IDA7DQo+ID4gKyAgICAgdTggc3ViX2NsYXNz
Ow0KPiA+ICsNCj4gPiArICAgICBjeXVzYnMgPSBremFsbG9jKHNpemVvZigqY3l1c2JzKSwgR0ZQ
X0tFUk5FTCk7DQo+IA0KPiBBbnkgcmVhc29uIGZvciBub3QgdXNpbmcgbWFuYWdlZCByZXNvdXJj
ZXMgKGRldm1fKik/DQoNCk9rLCB3aWxsIHVzZSBtYW5hZ2VkIHJlc291cmNlcy4NCg0KPiANCj4g
PiArICAgICBpZiAoY3l1c2JzID09IE5VTEwpDQo+IA0KPiBpZiAoIWN5dXNicykNCj4gDQo+ID4g
KyAgICAgICAgICAgICByZXR1cm4gLUVOT01FTTsNCj4gPiArDQo+ID4gKyAgICAgY3l1c2JzLT51
c2JfZGV2ID0gdXNiX2dldF9kZXYoaW50ZXJmYWNlX3RvX3VzYmRldihpbnRlcmZhY2UpKTsNCj4g
DQo+IENhbiB5b3UgZG8gdGhpcyBsYXN0PyAgVGhlbiB5b3UgY2FuIHJlbW92ZSB0aGUgJ2Vycm9y
JyBlcnJvciBwYXRoLg0KDQptZmRfYWRkX2RldmljZXMgd291bGQgdXRsaW1hdGVseSBpbnZva2Ug
dGhlIGNlbGwgZHJpdmVycycgcHJvYmUgYmVmb3JlIHJldHVybmluZyBhbmQgY2VsbCBkcml2ZXJz
IHVzZSB1c2JfZGV2IGluIHRoZWlyIHByb2JlLg0KU28sIGxlYXZpbmcgaXQgYXMgc3VjaC4NCg0K
PiANCj4gPiArICAgICBjeXVzYnMtPnVzYl9pbnRmID0gaW50ZXJmYWNlOw0KPiA+ICsgICAgIGN5
dXNicy0+aW50Zl9udW0gPSBpbnRlcmZhY2UtPmN1cl9hbHRzZXR0aW5nLQ0KPiA+ZGVzYy5iSW50
ZXJmYWNlTnVtYmVyOw0KPiANCj4gSWYgeW91J3JlIGFscmVhZHkgc2F2aW5nICdpbnRlcmZhY2Un
IHRoZXJlIGlzIG5vIG5lZWQgdG8gc2F2ZSB0aGlzDQo+IGFsc28sIGp1c3QgZXh0cmFjdCBpdCBm
cm9tICdjeXVzYnMtPnVzYl9pbnRmJyB3aGVuIHlvdSBuZWVkIGl0Lg0KPiANCj4gPiArICAgICBy
ZXQgPSB1cGRhdGVfZXBfZGV0YWlscyhpbnRlcmZhY2UsIGN5dXNicyk7DQo+ID4gKyAgICAgaWYg
KHJldCA8IDApIHsNCj4gDQo+IENhbiByZXQgYmUgPiAwPyAgSWYgbm90LCBqdXN0IGRvICdpZiAo
cmV0KScNCj4gDQo+ID4gKyAgICAgICAgICAgICBkZXZfZXJyKCZpbnRlcmZhY2UtPmRldiwgImlu
dmFsaWQgaW50ZXJmYWNlXG4iKTsNCj4gDQo+IElmIHlvdSBwdXQgdGhlIGVycm9yIG1lc3NhZ2Ug
aW4gdXBkYXRlX2VwX2RldGFpbHMoKSBjYW4geW91IHByaW50IG91dA0KPiBhIG1vcmUgc3BlY2lm
aWMgZXJyb3IgbWVzc2FnZSBhbmQgcmVtb3ZlIHRoaXMgbGluZS4NCj4gDQo+ID4gKyAgICAgICAg
ICAgICBnb3RvIGVycm9yOw0KPiA+ICsgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgdXNiX3NldF9p
bnRmZGF0YShpbnRlcmZhY2UsIGN5dXNicyk7DQo+ID4gKw0KPiA+ICsgICAgIC8qIFNlcmlhbCBp
bnRlcmZhY2VzIChJMkMsIFNQSSwgVUFSVCkgZGlmZmVyIGluIGludGVyZmFjZSBzdWJjbGFzcyAq
Lw0KPiA+ICsgICAgIHN1Yl9jbGFzcyA9IGludGVyZmFjZS0+Y3VyX2FsdHNldHRpbmctPmRlc2Mu
YkludGVyZmFjZVN1YkNsYXNzOw0KPiA+ICsgICAgIHN3aXRjaCAoc3ViX2NsYXNzKSB7DQo+IA0K
PiBUaGlzIGlzIGEgd2FzdGUgb2YgYSB2YXJpYWJsZSBhbmQgYWRkcyBub3RoaW5nIHRvIHRoZSBj
b2RlLiAgSnVzdA0KPiBzd2l0Y2goKSBmb3IgJ2ludGVyZmFjZS0+Y3VyX2FsdHNldHRpbmctPmRl
c2MuYkludGVyZmFjZVN1YkNsYXNzJy4NCj4gDQo+ID4gKyAgICAgY2FzZSBDWV9VU0JTX1NDQl9J
MkM6DQo+ID4gKyAgICAgICAgICAgICBkZXZfaW5mbygmaW50ZXJmYWNlLT5kZXYsICJJMkMgaW50
ZXJmYWNlIGZvdW5kXG4iKTsNCj4gDQo+IFdhcyBpdCBldmVuIGxvc3Q/DQo+IA0KPiBXb3VsZCAi
dXNpbmcgSTJDIGludGVyZmFjZSIgYmUgYmV0dGVyPw0KPiANCj4gPiArICAgICAgICAgICAgIGN5
dXNiczIzeF9kZXZzID0gY3l1c2JzMjN4X2kyY19kZXZzOw0KPiA+ICsgICAgICAgICAgICAgbmRl
dnMgPSBBUlJBWV9TSVpFKGN5dXNiczIzeF9pMmNfZGV2cyk7DQo+ID4gKyAgICAgICAgICAgICBi
cmVhazsNCj4gDQo+IEkgYXNzdW1lIHRoZXJlIHdpbGwgYmUgb3RoZXIgaW50ZXJmYWNlcyBzdXBw
b3J0ZWQgYXQgYSBsYXRlciBkYXRlPyAgSWYNCj4gbm90LCB0aGlzIHN3aXRjaCgpIGlzIHByZXR0
eSBvdmVyLXRoZS10b3AuDQo+IA0KPiA+ICsgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAgICAgICAg
ICBkZXZfZXJyKCZpbnRlcmZhY2UtPmRldiwgInVuc3VwcG9ydGVkIHN1YmNsYXNzXG4iKTsNCj4g
PiArICAgICAgICAgICAgIHJldCA9IC1FTk9ERVY7DQo+ID4gKyAgICAgICAgICAgICBnb3RvIGVy
cm9yOw0KPiA+ICsgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgcmV0ID0gbWZkX2FkZF9kZXZpY2Vz
KCZpbnRlcmZhY2UtPmRldiwgUExBVEZPUk1fREVWSURfQVVUTywNCj4gPiArICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICBjeXVzYnMyM3hfZGV2cywgbmRldnMsIE5VTEwsIDAsIE5VTEwpOw0K
PiA+ICsgICAgIGlmIChyZXQgIT0gMCkgew0KPiANCj4gaWYgKHJldCkNCj4gDQo+ID4gKyAgICAg
ICAgICAgICBkZXZfZXJyKCZpbnRlcmZhY2UtPmRldiwgIkZhaWxlZCB0byBhZGQgbWZkIGRldmlj
ZXMgdG8gY29yZVxuIik7DQo+IA0KPiAiRmFpbGVkIHRvIHJlZ2lzdGVyIGRldmljZXMiDQo+IA0K
PiA+ICsgICAgICAgICAgICAgZ290byBlcnJvcjsNCj4gPiArICAgICB9DQo+ID4gKw0KPiA+ICsg
ICAgIHJldHVybiAwOw0KPiA+ICsNCj4gPiArZXJyb3I6DQo+ID4gKyAgICAgdXNiX3B1dF9kZXYo
Y3l1c2JzLT51c2JfZGV2KTsNCj4gPiArICAgICBrZnJlZShjeXVzYnMpOw0KPiA+ICsNCj4gPiAr
ICAgICByZXR1cm4gcmV0Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBjeXVzYnMy
M3hfZGlzY29ubmVjdChzdHJ1Y3QgdXNiX2ludGVyZmFjZSAqaW50ZXJmYWNlKQ0KPiA+ICt7DQo+
ID4gKyAgICAgc3RydWN0IGN5dXNiczIzeCAqY3l1c2JzID0gdXNiX2dldF9pbnRmZGF0YShpbnRl
cmZhY2UpOw0KPiA+ICsNCj4gPiArICAgICBtZmRfcmVtb3ZlX2RldmljZXMoJmludGVyZmFjZS0+
ZGV2KTsNCj4gPiArICAgICB1c2JfcHV0X2RldihjeXVzYnMtPnVzYl9kZXYpOw0KPiA+ICsgICAg
IGtmcmVlKGN5dXNicyk7DQo+IA0KPiBJZiB5b3UgdXNlIG1hbmFnZWQgcmVzb3VyY2VzLCB5b3Ug
Y2FuIHJlbW92ZSB0aGlzIGxpbmUuDQo+IA0KPiA+ICsgICAgIGRldl9kYmcoJmludGVyZmFjZS0+
ZGV2LCAiZGlzY29ubmVjdGVkXG4iKTsNCj4gDQo+IFBsZWFzZSByZW1vdmUgdGhpcyBsaW5lLg0K
PiANCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHN0cnVjdCB1c2JfZHJpdmVyIGN5dXNiczIz
eF91c2JfZHJpdmVyID0gew0KPiA+ICsgICAgIC5uYW1lICAgICAgICAgICA9ICJjeXVzYnMyM3gi
LA0KPiA+ICsgICAgIC5wcm9iZSAgICAgICAgICA9IGN5dXNiczIzeF9wcm9iZSwNCj4gPiArICAg
ICAuZGlzY29ubmVjdCAgICAgPSBjeXVzYnMyM3hfZGlzY29ubmVjdCwNCj4gPiArICAgICAuaWRf
dGFibGUgICAgICAgPSBjeXVzYnMyM3hfdXNiX3RhYmxlLA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiAr
bW9kdWxlX3VzYl9kcml2ZXIoY3l1c2JzMjN4X3VzYl9kcml2ZXIpOw0KPiA+ICsNCj4gPiArTU9E
VUxFX0FVVEhPUigiUmFqYXJhbSBSZWd1cGF0aHkgPHJlcmFAY3lwcmVzcy5jb20+Iik7DQo+ID4g
K01PRFVMRV9BVVRIT1IoIk11dGh1IE1hbmkgPG11dGhAY3lwcmVzcy5jb20+Iik7DQo+ID4gK01P
RFVMRV9ERVNDUklQVElPTigiQ3lwcmVzcyBDWVVTQlMyM3ggbWZkIGNvcmUgZHJpdmVyIik7DQo+
IA0KPiBzL21mZC9NRkQvDQoNCklzIHRoZXJlIGEgdHlwbz8NCg0KPiANCj4gPiArTU9EVUxFX0xJ
Q0VOU0UoIkdQTCB2MiIpOw0KPiA+IGRpZmYgLS1naXQgYS9pbmNsdWRlL2xpbnV4L21mZC9jeXVz
YnMyM3guaA0KPiBiL2luY2x1ZGUvbGludXgvbWZkL2N5dXNiczIzeC5oDQo+ID4gbmV3IGZpbGUg
bW9kZSAxMDA2NDQNCj4gPiBpbmRleCAwMDAwMDAwLi4xNTgwZDk4DQo+ID4gLS0tIC9kZXYvbnVs
bA0KPiA+ICsrKyBiL2luY2x1ZGUvbGludXgvbWZkL2N5dXNiczIzeC5oDQo+ID4gQEAgLTAsMCAr
MSw2MiBAQA0KPiA+ICsvKg0KPiA+ICsgKiBDeXByZXNzIFVTQi1TZXJpYWwgQnJpZGdlIENvbnRy
b2xsZXIgZGVmaW5pdGlvbnMNCj4gPiArICoNCj4gPiArICogQ29weXJpZ2h0IChjKSAyMDE0IEN5
cHJlc3MgU2VtaWNvbmR1Y3RvciBDb3Jwb3JhdGlvbi4NCj4gPiArICoNCj4gPiArICogQXV0aG9y
Og0KPiA+ICsgKiAgIE11dGh1IE1hbmkgPG11dGhAY3lwcmVzcy5jb20+DQo+ID4gKyAqDQo+ID4g
KyAqIEFkZGl0aW9uYWwgY29udHJpYnV0b3JzIGluY2x1ZGU6DQo+ID4gKyAqICAgUmFqYXJhbSBS
ZWd1cGF0aHkgPHJlcmFAY3lwcmVzcy5jb20+DQo+ID4gKyAqDQo+ID4gKyAqIFRoaXMgcHJvZ3Jh
bSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5
IGl0DQo+ID4gKyAqIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExp
Y2Vuc2UgdmVyc2lvbiAyIGFzDQo+IHB1Ymxpc2hlZCBieQ0KPiA+ICsgKiB0aGUgRnJlZSBTb2Z0
d2FyZSBGb3VuZGF0aW9uLg0KPiA+ICsgKi8NCj4gPiArDQo+ID4gKyNpZm5kZWYgX19NRkRfQ1lV
U0JTMjNYX0hfXw0KPiA+ICsjZGVmaW5lIF9fTUZEX0NZVVNCUzIzWF9IX18NCj4gPiArDQo+ID4g
KyNpbmNsdWRlIDxsaW51eC90eXBlcy5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvdXNiLmg+DQo+
ID4gKw0KPiA+ICsvKiBTdHJ1Y3R1cmUgdG8gaG9sZCBhbGwgZGV2aWNlIHNwZWNpZmljIHN0dWZm
ICovDQo+ID4gK3N0cnVjdCBjeXVzYnMyM3ggew0KPiA+ICsgICAgIHN0cnVjdCB1c2JfZGV2aWNl
ICp1c2JfZGV2Ow0KPiA+ICsgICAgIHN0cnVjdCB1c2JfaW50ZXJmYWNlICp1c2JfaW50ZjsNCj4g
PiArDQo+ID4gKyAgICAgdTggaW50Zl9udW07DQo+ID4gKyAgICAgdTggYnVsa19pbl9lcF9udW07
DQo+ID4gKyAgICAgdTggYnVsa19vdXRfZXBfbnVtOw0KPiA+ICsgICAgIHU4IGludHJfaW5fZXBf
bnVtOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArZW51bSBjeV91c2JzX3ZlbmRvcl9jbWRzIHsNCj4g
PiArICAgICBDWV9JMkNfR0VUX0NPTkZJR19DTUQgID0gMHhDNCwNCj4gPiArICAgICBDWV9JMkNf
U0VUX0NPTkZJR19DTUQgID0gMHhDNSwNCj4gPiArICAgICBDWV9JMkNfV1JJVEVfQ01EICAgICAg
ID0gMHhDNiwNCj4gPiArICAgICBDWV9JMkNfUkVBRF9DTUQgICAgICAgID0gMHhDNywNCj4gPiAr
ICAgICBDWV9JMkNfR0VUX1NUQVRVU19DTUQgID0gMHhDOCwNCj4gPiArICAgICBDWV9JMkNfUkVT
RVRfQ01EICAgICAgID0gMHhDOSwNCj4gPiArICAgICBDWV9HUElPX0dFVF9DT05GSUdfQ01EID0g
MHhEOCwNCj4gPiArICAgICBDWV9HUElPX1NFVF9DT05GSUdfQ01EID0gMHhEOSwNCj4gPiArICAg
ICBDWV9HUElPX0dFVF9WQUxVRV9DTUQgID0gMHhEQSwNCj4gPiArICAgICBDWV9HUElPX1NFVF9W
QUxVRV9DTUQgID0gMHhEQiwNCj4gPiArfTsNCj4gPiArDQo+ID4gKy8qIFNlcmlhbCBpbnRlcmZh
Y2VzIChJMkMsIFNQSSwgVUFSVCkgZGlmZmVyIGluIGludGVyZmFjZSBzdWJjbGFzcyAqLw0KPiA+
ICtlbnVtIGN5X3NjYl9tb2RlcyB7DQo+ID4gKyAgICAgQ1lfVVNCU19TQ0JfRElTQUJMRUQgPSAw
LA0KPiA+ICsgICAgIENZX1VTQlNfU0NCX1VBUlQgPSAxLA0KPiA+ICsgICAgIENZX1VTQlNfU0NC
X1NQSSA9IDIsDQo+ID4gKyAgICAgQ1lfVVNCU19TQ0JfSTJDID0gMw0KPiANCj4gTm8gbmVlZCB0
byBudW1iZXIgdGhlc2UuDQo+IA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArLyogU0NCIGluZGV4IHNo
aWZ0ICovDQo+ID4gKyNkZWZpbmUgQ1lfU0NCX0lOREVYX1NISUZUICAgICAgMTUNCj4gPiArDQo+
ID4gKyNkZWZpbmUgQ1lfVVNCU19DVFJMX1hGRVJfVElNRU9VVCAgICAyMDAwDQo+ID4gKyNkZWZp
bmUgQ1lfVVNCU19CVUxLX1hGRVJfVElNRU9VVCAgICA1MDAwDQo+ID4gKyNkZWZpbmUgQ1lfVVNC
U19JTlRSX1hGRVJfVElNRU9VVCAgICA1MDAwDQo+ID4gKw0KPiA+ICsjZW5kaWYgLyogX19NRkRf
Q1lVU0JTMjNYX0hfXyAqLw0KPiANCj4gLS0NCj4gTGVlIEpvbmVzDQo+IExpbmFybyBTVE1pY3Jv
ZWxlY3Ryb25pY3MgTGFuZGluZyBUZWFtIExlYWQNCj4gTGluYXJvLm9yZyDilIIgT3BlbiBzb3Vy
Y2Ugc29mdHdhcmUgZm9yIEFSTSBTb0NzDQo+IEZvbGxvdyBMaW5hcm86IEZhY2Vib29rIHwgVHdp
dHRlciB8IEJsb2cNCj4gVGhpcyBtZXNzYWdlIGFuZCBhbnkgYXR0YWNobWVudHMgbWF5IGNvbnRh
aW4gQ3lwcmVzcyAob3IgaXRzIHN1YnNpZGlhcmllcykNCj4gY29uZmlkZW50aWFsIGluZm9ybWF0
aW9uLiBJZiBpdCBoYXMgYmVlbiByZWNlaXZlZCBpbiBlcnJvciwgcGxlYXNlIGFkdmlzZSB0aGUN
Cj4gc2VuZGVyIGFuZCBpbW1lZGlhdGVseSBkZWxldGUgdGhpcyBtZXNzYWdlLg0K
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lee Jones Oct. 10, 2014, 4:17 p.m. UTC | #6
> > -----Original Message-----
> > From: Lee Jones [mailto:lee.jones@linaro.org]
> > Sent: Thursday, October 09, 2014 1:10 PM
> > To: Muthu Mani
> > Cc: Samuel Ortiz; Wolfram Sang; Linus Walleij; Alexandre Courbot;
> > gregkh@linuxfoundation.org; linux-i2c@vger.kernel.org; linux-
> > gpio@vger.kernel.org; linux-usb@vger.kernel.org; linux-
> > kernel@vger.kernel.org; Rajaram Regupathy; Johan Hovold
> > Subject: Re: [PATCH v3 1/3] mfd: add support for Cypress CYUSBS234 USB
> > Serial Bridge controller

Why is this in here?

> > > +     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.

Can you move it down to just about mfd_add_devices() then.  That way
can you at least return directly in the other error paths.

[...]

> > > +MODULE_AUTHOR("Rajaram Regupathy <rera@cypress.com>");
> > > +MODULE_AUTHOR("Muthu Mani <muth@cypress.com>");
> > > +MODULE_DESCRIPTION("Cypress CYUSBS23x mfd core driver");
> > 
> > s/mfd/MFD/
> 
> Is there a typo?

Yes mfd should be MFD, as I sed (spelt this way on purpose).
diff mbox

Patch

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"
+	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@cypress.com>
+ *
+ * Additional contributors include:
+ *   Rajaram Regupathy <rera@cypress.com>
+ *
+ * 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>
+
+#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 */
+};
+
+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;
+	}
+
+	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);
+	if (cyusbs == NULL)
+		return -ENOMEM;
+
+	cyusbs->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+	cyusbs->usb_intf = interface;
+	cyusbs->intf_num = interface->cur_altsetting->desc.bInterfaceNumber;
+
+	ret = update_ep_details(interface, cyusbs);
+	if (ret < 0) {
+		dev_err(&interface->dev, "invalid interface\n");
+		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) {
+	case CY_USBS_SCB_I2C:
+		dev_info(&interface->dev, "I2C interface found\n");
+		cyusbs23x_devs = cyusbs23x_i2c_devs;
+		ndevs = ARRAY_SIZE(cyusbs23x_i2c_devs);
+		break;
+	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) {
+		dev_err(&interface->dev, "Failed to add mfd devices to core\n");
+		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);
+
+	dev_dbg(&interface->dev, "disconnected\n");
+}
+
+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@cypress.com>");
+MODULE_AUTHOR("Muthu Mani <muth@cypress.com>");
+MODULE_DESCRIPTION("Cypress CYUSBS23x mfd core driver");
+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@cypress.com>
+ *
+ * Additional contributors include:
+ *   Rajaram Regupathy <rera@cypress.com>
+ *
+ * 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
+};
+
+/* 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__ */