All of lore.kernel.org
 help / color / mirror / Atom feed
From: Varka Bhadram <varkabhadram-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: Muthu Mani <muth-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>,
	Samuel Ortiz <sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>,
	Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>,
	Linus Walleij
	<linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Alexandre Courbot
	<gnurou-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org,
	Johan Hovold <johan-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Rajaram Regupathy <rera-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>
Subject: Re: [PATCH v5 2/3] i2c: add support for Cypress CYUSBS234 USB-I2C adapter
Date: Sun, 14 Dec 2014 07:54:49 +0530	[thread overview]
Message-ID: <548CF4F1.7070607@gmail.com> (raw)
In-Reply-To: <1418471264-31896-2-git-send-email-muth-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>


On Saturday 13 December 2014 05:17 PM, Muthu Mani wrote:
> Adds support for USB-I2C interface of Cypress Semiconductor
> CYUSBS234 USB-Serial Bridge controller.
>
> The read/write operation is setup using vendor command through control endpoint
> and actual data transfer happens through bulk in/out endpoints.
>
> Details about the device can be found at:
> http://www.cypress.com/?rID=84126
>
> Signed-off-by: Muthu Mani <muth-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Rajaram Regupathy <rera-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>
> ---
> Changes since v4:
> * used interface number from interface pointer instead of separate member var
>
> Changes since v3:
> * corrected typo
>
> Changes since v2:
> * Retrieved the i2c transfer status using interrupt in endpoint
> * Used kstrtol instead of manually parsing and scnprintf instead of sprintf
> * Given i2c adapter device for dev_xxx
> * cleaned up the code
>
> Changes since v1:
> * allocated memory on heap for usb transfer data
> * Used DEVICE_ATTR_xx and friends and attribute groups
> * Added the device files under i2c-adapter rather than platform device
>
>   drivers/i2c/busses/Kconfig         |  12 +
>   drivers/i2c/busses/Makefile        |   1 +
>   drivers/i2c/busses/i2c-cyusbs23x.c | 585 +++++++++++++++++++++++++++++++++++++
>   3 files changed, 598 insertions(+)
>   create mode 100644 drivers/i2c/busses/i2c-cyusbs23x.c
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index b4d135c..a9cd3e2 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -871,6 +871,18 @@ config I2C_RCAR
>
>   comment "External I2C/SMBus adapter drivers"
>
> +config I2C_CYUSBS23X
> +       tristate "CYUSBS23x I2C adapter"
> +       depends on MFD_CYUSBS23X
> +       help
> +         Say yes if you would like to access Cypress CYUSBS23x I2C device.
> +
> +         This driver enables the I2C interface of CYUSBS23x USB Serial Bridge
> +         controller.
> +
> +         This driver can also be built as a module. If so, the module will be
> +         called i2c-cyusbs23x.
> +
>   config I2C_DIOLAN_U2C
>          tristate "Diolan U2C-12 USB adapter"
>          depends on USB
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index cdac7f1..ad2b283 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -86,6 +86,7 @@ obj-$(CONFIG_I2C_XLR)         += i2c-xlr.o
>   obj-$(CONFIG_I2C_RCAR)         += i2c-rcar.o
>
>   # External I2C/SMBus adapter drivers
> +obj-$(CONFIG_I2C_CYUSBS23X)    += i2c-cyusbs23x.o
>   obj-$(CONFIG_I2C_DIOLAN_U2C)   += i2c-diolan-u2c.o
>   obj-$(CONFIG_I2C_DLN2)         += i2c-dln2.o
>   obj-$(CONFIG_I2C_PARPORT)      += i2c-parport.o
> diff --git a/drivers/i2c/busses/i2c-cyusbs23x.c b/drivers/i2c/busses/i2c-cyusbs23x.c
> new file mode 100644
> index 0000000..452c370
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-cyusbs23x.c
> @@ -0,0 +1,585 @@
> +/*
> + * I2C subdriver for Cypress CYUSBS234 USB-Serial Bridge controller.
> + * Details about the device can be found at:
> + *    http://www.cypress.com/?rID=84126
> + *
> + * Copyright (c) 2014 Cypress Semiconductor Corporation.
> + *
> + * Author:
> + *   Rajaram Regupathy <rera-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>
> + *
> + * Additional contributors include:
> + *   Muthu Mani <muth-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>
> + *
> + * 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.
> + */
> +
> +/*
> + * It exposes sysfs entries under the i2c adapter for getting the i2c transfer
> + * status, reset i2c read/write module, get/set nak and stop bits.
> + */
> +
> +#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/platform_device.h>
> +#include <linux/usb.h>
> +#include <linux/i2c.h>
> +#include <linux/mfd/cyusbs23x.h>
> +
> +#define CY_I2C_MODE_READ           0
> +#define CY_I2C_MODE_WRITE          1
> +
> +#define CY_I2C_XFER_STATUS_LEN     3
> +
> +struct cyusbs_i2c_config {
> +       /* Frequency of operation. Only valid values are 100KHz and 400KHz */
> +       u32 frequency;
> +       u8 slave_addr;        /* Slave address to be used when in slave mode */
> +       u8 is_msb_first;      /* Whether to transmit MSB first */
> +       /*
> +        * Whether block is configured as a master:
> +        * 1 - The block functions as I2C master;
> +        * 0 - The block functions as I2C slave
> +        */
> +       u8 is_master;
> +       u8 s_ignore;          /* Ignore general call in slave mode */
> +       /* Whether to stretch clock in case of no FIFO availability */
> +       u8 clock_stretch;
> +       /* Whether to loop back TX data to RX. Valid only for debug purposes */
> +       u8 is_loopback;
> +       u8 reserved[6];       /* Reserved for future use */
> +} __packed;
> +
> +struct cyusbs_i2c {
> +       struct i2c_adapter i2c_adapter;
> +       struct cyusbs_i2c_config *i2c_config;
> +       struct mutex lock;
> +
> +       bool is_stop_bit;     /* set the stop bit for i2c transfer */
> +       bool is_nak_bit;      /* set the nak bit for i2c transfer */
> +};
> +
> +#define to_cyusbs_i2c(a) container_of(a, struct cyusbs_i2c, i2c_adapter)
> +
> +static int cy_i2c_get_status(struct i2c_adapter *adapter, u8 *buf, u16 mode);
> +static int cy_i2c_reset(struct i2c_adapter *adapter, u16 mode);
> +
> +static ssize_t i2c_read_status_show(struct device *d,
> +                                   struct device_attribute *attr, char *buf)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +
> +       /* Updates buffer with 3 bytes status (hex data) */
> +       return cy_i2c_get_status(adapter, buf, CY_I2C_MODE_READ);
> +}
> +
> +static ssize_t i2c_write_status_show(struct device *d,
> +                                    struct device_attribute *attr, char *buf)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +
> +       /* Updates buffer with 3 bytes status (hex data) */
> +       return cy_i2c_get_status(adapter, buf, CY_I2C_MODE_WRITE);
> +}
> +
> +static ssize_t i2c_read_reset_store(struct device *d,
> +                                struct device_attribute *attr,
> +                                const char *buf, size_t count)
> +{
> +       int ret;
> +       long value;
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +
> +       ret = kstrtol(buf, 0, &value);
> +       if (ret)
> +               return ret;
> +
> +       if (value != 1)
> +               return -EINVAL;
> +
> +       ret = cy_i2c_reset(adapter, CY_I2C_MODE_READ);
> +       if (!ret)
> +               ret = count;
> +
> +       return ret;
> +}
> +
> +static ssize_t i2c_write_reset_store(struct device *d,
> +                                 struct device_attribute *attr,
> +                                 const char *buf, size_t count)
> +{
> +       int ret;
> +       long value;
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +
> +       ret = kstrtol(buf, 0, &value);
> +       if (ret)
> +               return ret;
> +
> +       if (value != 1)
> +               return -EINVAL;
> +
> +       ret = cy_i2c_reset(adapter, CY_I2C_MODE_WRITE);
> +       if (!ret)
> +               ret = count;
> +
> +       return ret;
> +}
> +
> +static ssize_t is_stop_bit_show(struct device *d,
> +                               struct device_attribute *attr, char *buf)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +
> +       return scnprintf(buf, 3, "%d\n", cy_i2c->is_stop_bit);
> +}
> +
> +static ssize_t is_stop_bit_store(struct device *d,
> +                                struct device_attribute *attr,
> +                                const char *buf, size_t count)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +       long value;
> +       int ret;
> +
> +       ret = kstrtol(buf, 0, &value);
> +       if (ret)
> +               return ret;
> +
> +       if (value != 0 && value != 1)
> +               return -EINVAL;
> +
> +       cy_i2c->is_stop_bit = (bool)value;
> +
> +       return count;
> +}
> +
> +static ssize_t is_nak_bit_show(struct device *d,
> +                              struct device_attribute *attr, char *buf)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +
> +       return scnprintf(buf, 3, "%d\n", cy_i2c->is_nak_bit);
> +}
> +
> +static ssize_t is_nak_bit_store(struct device *d,
> +                               struct device_attribute *attr,
> +                               const char *buf, size_t count)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +       long value;
> +       int ret;
> +
> +       ret = kstrtol(buf, 0, &value);
> +       if (ret)
> +               return ret;
> +
> +       if (value != 0 && value != 1)
> +               return -EINVAL;
> +
> +       cy_i2c->is_nak_bit = (bool)value;
> +
> +       return count;
> +}
> +
> +static DEVICE_ATTR_RO(i2c_read_status);
> +static DEVICE_ATTR_RO(i2c_write_status);
> +static DEVICE_ATTR_WO(i2c_read_reset);
> +static DEVICE_ATTR_WO(i2c_write_reset);
> +static DEVICE_ATTR_RW(is_stop_bit);
> +static DEVICE_ATTR_RW(is_nak_bit);
> +
> +static struct attribute *cyusbs_i2c_device_attrs[] = {
> +       &dev_attr_i2c_read_status.attr,
> +       &dev_attr_i2c_write_status.attr,
> +       &dev_attr_i2c_read_reset.attr,
> +       &dev_attr_i2c_write_reset.attr,
> +       &dev_attr_is_stop_bit.attr,
> +       &dev_attr_is_nak_bit.attr,
> +       NULL
> +};
> +
> +ATTRIBUTE_GROUPS(cyusbs_i2c_device);
> +
> +static int cy_i2c_get_status(struct i2c_adapter *adapter, u8 *buf, u16 mode)
> +{
> +       int ret;
> +       u16 wIndex, wValue, scb_index;
> +       u8 *data;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +       u8 ifnum = cyusbs->usb_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +       scb_index = ifnum & 0x01;
> +       wValue = ((scb_index << CY_SCB_INDEX_SHIFT) | mode);
> +       wIndex = 0;

One line space..

> +       data = kmalloc(CY_I2C_XFER_STATUS_LEN, GFP_KERNEL);
> +       if (data == NULL)
> +               return -ENOMEM;
> +

if(!data)
	return -ENOMEM;

> +       mutex_lock(&cy_i2c->lock);
> +       /* read the i2c transfer status */
> +       ret = usb_control_msg(cyusbs->usb_dev,
> +                       usb_rcvctrlpipe(cyusbs->usb_dev, 0),
> +                       CY_I2C_GET_STATUS_CMD,
> +                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
> +                       wValue, wIndex, data, CY_I2C_XFER_STATUS_LEN,
> +                       CY_USBS_CTRL_XFER_TIMEOUT);
> +       mutex_unlock(&cy_i2c->lock);
> +       if (ret != CY_I2C_XFER_STATUS_LEN) {
> +               dev_err(&adapter->dev, "%s: failed to get status: %d",
> +                       __func__, ret);
> +               ret = usb_translate_errors(ret);
> +               goto status_error;
> +       }
> +
> +       memcpy(buf, data, CY_I2C_XFER_STATUS_LEN);
> +       buf[CY_I2C_XFER_STATUS_LEN] = 0;
> +
> +       dev_dbg(&adapter->dev, "%s: %02x %02x %02x\n", __func__,
> +               buf[0], buf[1], buf[2]);
> +
> +status_error:
> +       kfree(data);
> +       return ret;
> +}
> +
> +static int cy_i2c_reset(struct i2c_adapter *adapter, u16 mode)
> +{
> +       int ret;
> +       u16 wIndex, wValue, scb_index;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +       u8 ifnum = cyusbs->usb_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +       scb_index = ifnum & 0x01;
> +       wValue = ((scb_index << CY_SCB_INDEX_SHIFT) | mode);
> +       wIndex = 0;
> +
> +       mutex_lock(&cy_i2c->lock);
> +       ret = usb_control_msg(cyusbs->usb_dev,
> +                       usb_sndctrlpipe(cyusbs->usb_dev, 0),
> +                       CY_I2C_RESET_CMD,
> +                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
> +                       wValue, wIndex, NULL, 0, CY_USBS_CTRL_XFER_TIMEOUT);
> +       mutex_unlock(&cy_i2c->lock);
> +       if (ret) {
> +               dev_err(&adapter->dev, "%s: failed to reset: %d",
> +                       __func__, ret);
> +               ret = usb_translate_errors(ret);
> +       }
> +
> +       return ret;
> +}
> +
> +static int cy_i2c_recv_status(struct i2c_adapter *adapter)
> +{
> +       int ret, actual_len;
> +       u8 *data;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +
> +       data = kmalloc(CY_I2C_XFER_STATUS_LEN, GFP_KERNEL);
> +       if (data == NULL)
> +               return -ENOMEM;
> +

if(!data)
	return -ENOMEM;

> +       /* read the i2c transfer status */
> +       ret = usb_interrupt_msg(cyusbs->usb_dev,
> +                       usb_rcvintpipe(cyusbs->usb_dev, cyusbs->intr_in_ep_num),
> +                       data, CY_I2C_XFER_STATUS_LEN, &actual_len,
> +                       CY_USBS_INTR_XFER_TIMEOUT);
> +       if (ret < 0) {
> +               dev_err(&adapter->dev,
> +                       "Failed to read from interrupt ep: %d\n", ret);
> +               ret = usb_translate_errors(ret);
> +               goto intr_ep_error;
> +       }
> +
> +       dev_dbg(&adapter->dev, "%s: %02x %02x %02x\n", __func__,
> +               data[0], data[1], data[2]);
> +
> +       if (data[0] & 0x1)
> +               ret = -ETIMEDOUT;
> +
> +intr_ep_error:
> +       kfree(data);
> +       return ret;
> +}
> +
> +static int cy_get_i2c_config(struct cyusbs23x *cyusbs,
> +                               struct cyusbs_i2c *cy_i2c)
> +{
> +       int ret;
> +       u16 scb_index;
> +       u8 ifnum = cyusbs->usb_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +       scb_index = (ifnum & 0x01) << CY_SCB_INDEX_SHIFT;
> +
> +       ret = usb_control_msg(cyusbs->usb_dev,
> +                       usb_rcvctrlpipe(cyusbs->usb_dev, 0),
> +                       CY_I2C_GET_CONFIG_CMD,
> +                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
> +                       scb_index, 0, cy_i2c->i2c_config,
> +                       sizeof(*cy_i2c->i2c_config), CY_USBS_CTRL_XFER_TIMEOUT);
> +       if (ret != sizeof(*cy_i2c->i2c_config)) {
> +               dev_err(&cyusbs->usb_intf->dev, "%s: %d\n",
> +                       __func__, ret);
> +               ret = usb_translate_errors(ret);
> +               goto config_error;
> +       }
> +
> +       dev_dbg(&cyusbs->usb_intf->dev,
> +               "%s: freq=%d, slave_addr=0x%02x, msb_first=%d, master=%d, ignore=%d, clock_stretch=%d, loopback=%d\n",
> +               __func__, cy_i2c->i2c_config->frequency,
> +               cy_i2c->i2c_config->slave_addr,
> +               cy_i2c->i2c_config->is_msb_first,
> +               cy_i2c->i2c_config->is_master,
> +               cy_i2c->i2c_config->s_ignore,
> +               cy_i2c->i2c_config->clock_stretch,
> +               cy_i2c->i2c_config->is_loopback);
> +
> +config_error:
> +       return ret;
> +}
> +
> +static int cy_i2c_set_data_config(struct cyusbs23x *cyusbs,
> +                                 struct cyusbs_i2c *cy_i2c, u16 slave_addr,
> +                                 u16 length, u8 command)
> +{
> +       int ret;
> +       u16 wIndex, wValue, scb_index;
> +       u8 ifnum = cyusbs->usb_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +       scb_index = (ifnum & 0x01) << CY_SCB_INDEX_SHIFT;
> +       slave_addr = (slave_addr & 0x7F);
> +       wValue = scb_index | cy_i2c->is_stop_bit | cy_i2c->is_nak_bit << 1;
> +       wValue |= (slave_addr << 8);
> +       wIndex = length;
> +
> +       dev_dbg(&cy_i2c->i2c_adapter.dev,
> +               "%s, cmd=0x%x, val=0x%x, idx=0x%x\n",
> +               __func__, command, wValue, wIndex);
> +
> +       ret = usb_control_msg(cyusbs->usb_dev,
> +               usb_sndctrlpipe(cyusbs->usb_dev, 0),
> +               command, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
> +               wValue, wIndex, NULL, 0, CY_USBS_CTRL_XFER_TIMEOUT);
> +
> +       return ret;
> +}
> +
> +static int cy_i2c_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
> +{
> +       int ret;
> +       int actual_read_len = 0;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +
> +       dev_dbg(&adapter->dev, "%s\n", __func__);
> +
> +       ret = usb_bulk_msg(cyusbs->usb_dev,
> +               usb_rcvbulkpipe(cyusbs->usb_dev, cyusbs->bulk_in_ep_num),
> +               msgs[0].buf,
> +               msgs[0].len,
> +               &actual_read_len, CY_USBS_BULK_XFER_TIMEOUT);
> +       if (ret)
> +               dev_err(&adapter->dev,
> +                       "read %d/%d returned %d\n",
> +                       actual_read_len, msgs[0].len, ret);
> +
> +       ret = cy_i2c_recv_status(adapter);
> +
> +       return ret;
> +}
> +
> +static int cy_i2c_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
> +{
> +       int ret;
> +       int actual_write_len = 0;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +
> +       dev_dbg(&adapter->dev, "%s\n", __func__);
> +
> +       ret = usb_bulk_msg(cyusbs->usb_dev,
> +               usb_sndbulkpipe(cyusbs->usb_dev, cyusbs->bulk_out_ep_num),
> +               msgs[0].buf,
> +               msgs[0].len,
> +               &actual_write_len, CY_USBS_BULK_XFER_TIMEOUT);
> +       if (ret)
> +               dev_err(&adapter->dev,
> +                       "write %d/%d returned %d\n",
> +                       actual_write_len, msgs[0].len, ret);
> +
> +       ret = cy_i2c_recv_status(adapter);
> +
> +       return ret;
> +}
> +
> +static int cy_i2c_xfer(struct i2c_adapter *adapter,
> +                      struct i2c_msg *msgs, int num)
> +{
> +       int ret = 0;
> +       struct cyusbs_i2c *cy_i2c;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +
> +       dev_dbg(&adapter->dev, "%s\n", __func__);
> +
> +       if (num > 1) {
> +               dev_err(&adapter->dev, "i2c_msg number is > 1\n");
> +               return -EIO;
> +       }
> +
> +       cy_i2c = to_cyusbs_i2c(adapter);
> +
> +       mutex_lock(&cy_i2c->lock);
> +       if (msgs[0].flags & I2C_M_RD) {
> +               dev_dbg(&adapter->dev,
> +                       "I2C read requested for addr 0x%02x, data length %d\n",
> +                       msgs[0].addr, msgs[0].len);
> +
> +               ret = cy_i2c_set_data_config(cyusbs, cy_i2c, msgs[0].addr,
> +                               msgs[0].len, CY_I2C_READ_CMD);
> +               if (ret < 0) {
> +                       dev_err(&adapter->dev,
> +                               "Set Config (read) failed with %d\n", ret);
> +                       goto io_error;
> +               }
> +
> +               ret = cy_i2c_read(adapter, msgs);
> +               if (ret) {
> +                       dev_err(&adapter->dev,
> +                               "Read failed with error code %d\n", ret);
> +                       goto io_error;
> +               }
> +       } else {
> +               dev_dbg(&adapter->dev,
> +                       "I2C write requested for addr 0x%02x, data length %d\n",
> +                       msgs[0].addr, msgs[0].len);
> +
> +               ret = cy_i2c_set_data_config(cyusbs, cy_i2c, msgs[0].addr,
> +                               msgs[0].len, CY_I2C_WRITE_CMD);
> +               if (ret < 0) {
> +                       dev_err(&adapter->dev,
> +                       "Set Config (write) failed with %d\n", ret);
> +                       goto io_error;
> +               }
> +
> +               ret = cy_i2c_write(adapter, msgs);
> +               if (ret) {
> +                       dev_err(&adapter->dev,
> +                               "Write failed with error code %d\n", ret);
> +                       goto io_error;
> +               }
> +       }
> +       mutex_unlock(&cy_i2c->lock);
> +       return ret;
> +
> +io_error:
> +       mutex_unlock(&cy_i2c->lock);
> +       return ret;
> +}
> +
> +static u32 cy_i2c_func(struct i2c_adapter *adapter)
> +{
> +       return I2C_FUNC_I2C;
> +}
> +
> +static const struct i2c_algorithm i2c_cyusbs23x_algorithm = {
> +       .master_xfer    = cy_i2c_xfer,
> +       .functionality  = cy_i2c_func,
> +};
> +
> +static int cyusbs23x_i2c_probe(struct platform_device *pdev)
> +{
> +       struct cyusbs23x *cyusbs;
> +       struct cyusbs_i2c *cy_i2c;
> +       int ret = 0;
> +
> +       dev_dbg(&pdev->dev, "%s\n", __func__);
> +
> +       cyusbs = dev_get_drvdata(pdev->dev.parent);
> +
> +       cy_i2c = devm_kzalloc(&pdev->dev, sizeof(*cy_i2c), GFP_KERNEL);
> +       if (cy_i2c == NULL)
> +               return -ENOMEM;
> +

dto...

> +       cy_i2c->i2c_config = devm_kzalloc(&pdev->dev,
> +                                       sizeof(struct cyusbs_i2c_config),
> +                                       GFP_KERNEL);
> +       if (cy_i2c->i2c_config == NULL)
> +               return -ENOMEM;
> +

dto...

-- 
Thanks and Regards,
Varka Bhadram.

WARNING: multiple messages have this Message-ID (diff)
From: Varka Bhadram <varkabhadram@gmail.com>
To: Muthu Mani <muth@cypress.com>,
	Samuel Ortiz <sameo@linux.intel.com>,
	Lee Jones <lee.jones@linaro.org>,
	Wolfram Sang <wsa@the-dreams.de>,
	Linus Walleij <linus.walleij@linaro.org>,
	Alexandre Courbot <gnurou@gmail.com>,
	gregkh@linuxfoundation.org, Johan Hovold <johan@kernel.org>
Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-i2c@vger.kernel.org, linux-gpio@vger.kernel.org,
	Rajaram Regupathy <rera@cypress.com>
Subject: Re: [PATCH v5 2/3] i2c: add support for Cypress CYUSBS234 USB-I2C adapter
Date: Sun, 14 Dec 2014 07:54:49 +0530	[thread overview]
Message-ID: <548CF4F1.7070607@gmail.com> (raw)
In-Reply-To: <1418471264-31896-2-git-send-email-muth@cypress.com>


On Saturday 13 December 2014 05:17 PM, Muthu Mani wrote:
> Adds support for USB-I2C interface of Cypress Semiconductor
> CYUSBS234 USB-Serial Bridge controller.
>
> The read/write operation is setup using vendor command through control endpoint
> and actual data transfer happens through bulk in/out endpoints.
>
> 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 v4:
> * used interface number from interface pointer instead of separate member var
>
> Changes since v3:
> * corrected typo
>
> Changes since v2:
> * Retrieved the i2c transfer status using interrupt in endpoint
> * Used kstrtol instead of manually parsing and scnprintf instead of sprintf
> * Given i2c adapter device for dev_xxx
> * cleaned up the code
>
> Changes since v1:
> * allocated memory on heap for usb transfer data
> * Used DEVICE_ATTR_xx and friends and attribute groups
> * Added the device files under i2c-adapter rather than platform device
>
>   drivers/i2c/busses/Kconfig         |  12 +
>   drivers/i2c/busses/Makefile        |   1 +
>   drivers/i2c/busses/i2c-cyusbs23x.c | 585 +++++++++++++++++++++++++++++++++++++
>   3 files changed, 598 insertions(+)
>   create mode 100644 drivers/i2c/busses/i2c-cyusbs23x.c
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index b4d135c..a9cd3e2 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -871,6 +871,18 @@ config I2C_RCAR
>
>   comment "External I2C/SMBus adapter drivers"
>
> +config I2C_CYUSBS23X
> +       tristate "CYUSBS23x I2C adapter"
> +       depends on MFD_CYUSBS23X
> +       help
> +         Say yes if you would like to access Cypress CYUSBS23x I2C device.
> +
> +         This driver enables the I2C interface of CYUSBS23x USB Serial Bridge
> +         controller.
> +
> +         This driver can also be built as a module. If so, the module will be
> +         called i2c-cyusbs23x.
> +
>   config I2C_DIOLAN_U2C
>          tristate "Diolan U2C-12 USB adapter"
>          depends on USB
> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
> index cdac7f1..ad2b283 100644
> --- a/drivers/i2c/busses/Makefile
> +++ b/drivers/i2c/busses/Makefile
> @@ -86,6 +86,7 @@ obj-$(CONFIG_I2C_XLR)         += i2c-xlr.o
>   obj-$(CONFIG_I2C_RCAR)         += i2c-rcar.o
>
>   # External I2C/SMBus adapter drivers
> +obj-$(CONFIG_I2C_CYUSBS23X)    += i2c-cyusbs23x.o
>   obj-$(CONFIG_I2C_DIOLAN_U2C)   += i2c-diolan-u2c.o
>   obj-$(CONFIG_I2C_DLN2)         += i2c-dln2.o
>   obj-$(CONFIG_I2C_PARPORT)      += i2c-parport.o
> diff --git a/drivers/i2c/busses/i2c-cyusbs23x.c b/drivers/i2c/busses/i2c-cyusbs23x.c
> new file mode 100644
> index 0000000..452c370
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-cyusbs23x.c
> @@ -0,0 +1,585 @@
> +/*
> + * I2C subdriver for Cypress CYUSBS234 USB-Serial Bridge controller.
> + * Details about the device can be found at:
> + *    http://www.cypress.com/?rID=84126
> + *
> + * Copyright (c) 2014 Cypress Semiconductor Corporation.
> + *
> + * Author:
> + *   Rajaram Regupathy <rera@cypress.com>
> + *
> + * Additional contributors include:
> + *   Muthu Mani <muth@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.
> + */
> +
> +/*
> + * It exposes sysfs entries under the i2c adapter for getting the i2c transfer
> + * status, reset i2c read/write module, get/set nak and stop bits.
> + */
> +
> +#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/platform_device.h>
> +#include <linux/usb.h>
> +#include <linux/i2c.h>
> +#include <linux/mfd/cyusbs23x.h>
> +
> +#define CY_I2C_MODE_READ           0
> +#define CY_I2C_MODE_WRITE          1
> +
> +#define CY_I2C_XFER_STATUS_LEN     3
> +
> +struct cyusbs_i2c_config {
> +       /* Frequency of operation. Only valid values are 100KHz and 400KHz */
> +       u32 frequency;
> +       u8 slave_addr;        /* Slave address to be used when in slave mode */
> +       u8 is_msb_first;      /* Whether to transmit MSB first */
> +       /*
> +        * Whether block is configured as a master:
> +        * 1 - The block functions as I2C master;
> +        * 0 - The block functions as I2C slave
> +        */
> +       u8 is_master;
> +       u8 s_ignore;          /* Ignore general call in slave mode */
> +       /* Whether to stretch clock in case of no FIFO availability */
> +       u8 clock_stretch;
> +       /* Whether to loop back TX data to RX. Valid only for debug purposes */
> +       u8 is_loopback;
> +       u8 reserved[6];       /* Reserved for future use */
> +} __packed;
> +
> +struct cyusbs_i2c {
> +       struct i2c_adapter i2c_adapter;
> +       struct cyusbs_i2c_config *i2c_config;
> +       struct mutex lock;
> +
> +       bool is_stop_bit;     /* set the stop bit for i2c transfer */
> +       bool is_nak_bit;      /* set the nak bit for i2c transfer */
> +};
> +
> +#define to_cyusbs_i2c(a) container_of(a, struct cyusbs_i2c, i2c_adapter)
> +
> +static int cy_i2c_get_status(struct i2c_adapter *adapter, u8 *buf, u16 mode);
> +static int cy_i2c_reset(struct i2c_adapter *adapter, u16 mode);
> +
> +static ssize_t i2c_read_status_show(struct device *d,
> +                                   struct device_attribute *attr, char *buf)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +
> +       /* Updates buffer with 3 bytes status (hex data) */
> +       return cy_i2c_get_status(adapter, buf, CY_I2C_MODE_READ);
> +}
> +
> +static ssize_t i2c_write_status_show(struct device *d,
> +                                    struct device_attribute *attr, char *buf)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +
> +       /* Updates buffer with 3 bytes status (hex data) */
> +       return cy_i2c_get_status(adapter, buf, CY_I2C_MODE_WRITE);
> +}
> +
> +static ssize_t i2c_read_reset_store(struct device *d,
> +                                struct device_attribute *attr,
> +                                const char *buf, size_t count)
> +{
> +       int ret;
> +       long value;
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +
> +       ret = kstrtol(buf, 0, &value);
> +       if (ret)
> +               return ret;
> +
> +       if (value != 1)
> +               return -EINVAL;
> +
> +       ret = cy_i2c_reset(adapter, CY_I2C_MODE_READ);
> +       if (!ret)
> +               ret = count;
> +
> +       return ret;
> +}
> +
> +static ssize_t i2c_write_reset_store(struct device *d,
> +                                 struct device_attribute *attr,
> +                                 const char *buf, size_t count)
> +{
> +       int ret;
> +       long value;
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +
> +       ret = kstrtol(buf, 0, &value);
> +       if (ret)
> +               return ret;
> +
> +       if (value != 1)
> +               return -EINVAL;
> +
> +       ret = cy_i2c_reset(adapter, CY_I2C_MODE_WRITE);
> +       if (!ret)
> +               ret = count;
> +
> +       return ret;
> +}
> +
> +static ssize_t is_stop_bit_show(struct device *d,
> +                               struct device_attribute *attr, char *buf)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +
> +       return scnprintf(buf, 3, "%d\n", cy_i2c->is_stop_bit);
> +}
> +
> +static ssize_t is_stop_bit_store(struct device *d,
> +                                struct device_attribute *attr,
> +                                const char *buf, size_t count)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +       long value;
> +       int ret;
> +
> +       ret = kstrtol(buf, 0, &value);
> +       if (ret)
> +               return ret;
> +
> +       if (value != 0 && value != 1)
> +               return -EINVAL;
> +
> +       cy_i2c->is_stop_bit = (bool)value;
> +
> +       return count;
> +}
> +
> +static ssize_t is_nak_bit_show(struct device *d,
> +                              struct device_attribute *attr, char *buf)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +
> +       return scnprintf(buf, 3, "%d\n", cy_i2c->is_nak_bit);
> +}
> +
> +static ssize_t is_nak_bit_store(struct device *d,
> +                               struct device_attribute *attr,
> +                               const char *buf, size_t count)
> +{
> +       struct i2c_adapter *adapter = to_i2c_adapter(d);
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +       long value;
> +       int ret;
> +
> +       ret = kstrtol(buf, 0, &value);
> +       if (ret)
> +               return ret;
> +
> +       if (value != 0 && value != 1)
> +               return -EINVAL;
> +
> +       cy_i2c->is_nak_bit = (bool)value;
> +
> +       return count;
> +}
> +
> +static DEVICE_ATTR_RO(i2c_read_status);
> +static DEVICE_ATTR_RO(i2c_write_status);
> +static DEVICE_ATTR_WO(i2c_read_reset);
> +static DEVICE_ATTR_WO(i2c_write_reset);
> +static DEVICE_ATTR_RW(is_stop_bit);
> +static DEVICE_ATTR_RW(is_nak_bit);
> +
> +static struct attribute *cyusbs_i2c_device_attrs[] = {
> +       &dev_attr_i2c_read_status.attr,
> +       &dev_attr_i2c_write_status.attr,
> +       &dev_attr_i2c_read_reset.attr,
> +       &dev_attr_i2c_write_reset.attr,
> +       &dev_attr_is_stop_bit.attr,
> +       &dev_attr_is_nak_bit.attr,
> +       NULL
> +};
> +
> +ATTRIBUTE_GROUPS(cyusbs_i2c_device);
> +
> +static int cy_i2c_get_status(struct i2c_adapter *adapter, u8 *buf, u16 mode)
> +{
> +       int ret;
> +       u16 wIndex, wValue, scb_index;
> +       u8 *data;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +       u8 ifnum = cyusbs->usb_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +       scb_index = ifnum & 0x01;
> +       wValue = ((scb_index << CY_SCB_INDEX_SHIFT) | mode);
> +       wIndex = 0;

One line space..

> +       data = kmalloc(CY_I2C_XFER_STATUS_LEN, GFP_KERNEL);
> +       if (data == NULL)
> +               return -ENOMEM;
> +

if(!data)
	return -ENOMEM;

> +       mutex_lock(&cy_i2c->lock);
> +       /* read the i2c transfer status */
> +       ret = usb_control_msg(cyusbs->usb_dev,
> +                       usb_rcvctrlpipe(cyusbs->usb_dev, 0),
> +                       CY_I2C_GET_STATUS_CMD,
> +                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
> +                       wValue, wIndex, data, CY_I2C_XFER_STATUS_LEN,
> +                       CY_USBS_CTRL_XFER_TIMEOUT);
> +       mutex_unlock(&cy_i2c->lock);
> +       if (ret != CY_I2C_XFER_STATUS_LEN) {
> +               dev_err(&adapter->dev, "%s: failed to get status: %d",
> +                       __func__, ret);
> +               ret = usb_translate_errors(ret);
> +               goto status_error;
> +       }
> +
> +       memcpy(buf, data, CY_I2C_XFER_STATUS_LEN);
> +       buf[CY_I2C_XFER_STATUS_LEN] = 0;
> +
> +       dev_dbg(&adapter->dev, "%s: %02x %02x %02x\n", __func__,
> +               buf[0], buf[1], buf[2]);
> +
> +status_error:
> +       kfree(data);
> +       return ret;
> +}
> +
> +static int cy_i2c_reset(struct i2c_adapter *adapter, u16 mode)
> +{
> +       int ret;
> +       u16 wIndex, wValue, scb_index;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +       struct cyusbs_i2c *cy_i2c = to_cyusbs_i2c(adapter);
> +       u8 ifnum = cyusbs->usb_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +       scb_index = ifnum & 0x01;
> +       wValue = ((scb_index << CY_SCB_INDEX_SHIFT) | mode);
> +       wIndex = 0;
> +
> +       mutex_lock(&cy_i2c->lock);
> +       ret = usb_control_msg(cyusbs->usb_dev,
> +                       usb_sndctrlpipe(cyusbs->usb_dev, 0),
> +                       CY_I2C_RESET_CMD,
> +                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
> +                       wValue, wIndex, NULL, 0, CY_USBS_CTRL_XFER_TIMEOUT);
> +       mutex_unlock(&cy_i2c->lock);
> +       if (ret) {
> +               dev_err(&adapter->dev, "%s: failed to reset: %d",
> +                       __func__, ret);
> +               ret = usb_translate_errors(ret);
> +       }
> +
> +       return ret;
> +}
> +
> +static int cy_i2c_recv_status(struct i2c_adapter *adapter)
> +{
> +       int ret, actual_len;
> +       u8 *data;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +
> +       data = kmalloc(CY_I2C_XFER_STATUS_LEN, GFP_KERNEL);
> +       if (data == NULL)
> +               return -ENOMEM;
> +

if(!data)
	return -ENOMEM;

> +       /* read the i2c transfer status */
> +       ret = usb_interrupt_msg(cyusbs->usb_dev,
> +                       usb_rcvintpipe(cyusbs->usb_dev, cyusbs->intr_in_ep_num),
> +                       data, CY_I2C_XFER_STATUS_LEN, &actual_len,
> +                       CY_USBS_INTR_XFER_TIMEOUT);
> +       if (ret < 0) {
> +               dev_err(&adapter->dev,
> +                       "Failed to read from interrupt ep: %d\n", ret);
> +               ret = usb_translate_errors(ret);
> +               goto intr_ep_error;
> +       }
> +
> +       dev_dbg(&adapter->dev, "%s: %02x %02x %02x\n", __func__,
> +               data[0], data[1], data[2]);
> +
> +       if (data[0] & 0x1)
> +               ret = -ETIMEDOUT;
> +
> +intr_ep_error:
> +       kfree(data);
> +       return ret;
> +}
> +
> +static int cy_get_i2c_config(struct cyusbs23x *cyusbs,
> +                               struct cyusbs_i2c *cy_i2c)
> +{
> +       int ret;
> +       u16 scb_index;
> +       u8 ifnum = cyusbs->usb_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +       scb_index = (ifnum & 0x01) << CY_SCB_INDEX_SHIFT;
> +
> +       ret = usb_control_msg(cyusbs->usb_dev,
> +                       usb_rcvctrlpipe(cyusbs->usb_dev, 0),
> +                       CY_I2C_GET_CONFIG_CMD,
> +                       USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
> +                       scb_index, 0, cy_i2c->i2c_config,
> +                       sizeof(*cy_i2c->i2c_config), CY_USBS_CTRL_XFER_TIMEOUT);
> +       if (ret != sizeof(*cy_i2c->i2c_config)) {
> +               dev_err(&cyusbs->usb_intf->dev, "%s: %d\n",
> +                       __func__, ret);
> +               ret = usb_translate_errors(ret);
> +               goto config_error;
> +       }
> +
> +       dev_dbg(&cyusbs->usb_intf->dev,
> +               "%s: freq=%d, slave_addr=0x%02x, msb_first=%d, master=%d, ignore=%d, clock_stretch=%d, loopback=%d\n",
> +               __func__, cy_i2c->i2c_config->frequency,
> +               cy_i2c->i2c_config->slave_addr,
> +               cy_i2c->i2c_config->is_msb_first,
> +               cy_i2c->i2c_config->is_master,
> +               cy_i2c->i2c_config->s_ignore,
> +               cy_i2c->i2c_config->clock_stretch,
> +               cy_i2c->i2c_config->is_loopback);
> +
> +config_error:
> +       return ret;
> +}
> +
> +static int cy_i2c_set_data_config(struct cyusbs23x *cyusbs,
> +                                 struct cyusbs_i2c *cy_i2c, u16 slave_addr,
> +                                 u16 length, u8 command)
> +{
> +       int ret;
> +       u16 wIndex, wValue, scb_index;
> +       u8 ifnum = cyusbs->usb_intf->cur_altsetting->desc.bInterfaceNumber;
> +
> +       scb_index = (ifnum & 0x01) << CY_SCB_INDEX_SHIFT;
> +       slave_addr = (slave_addr & 0x7F);
> +       wValue = scb_index | cy_i2c->is_stop_bit | cy_i2c->is_nak_bit << 1;
> +       wValue |= (slave_addr << 8);
> +       wIndex = length;
> +
> +       dev_dbg(&cy_i2c->i2c_adapter.dev,
> +               "%s, cmd=0x%x, val=0x%x, idx=0x%x\n",
> +               __func__, command, wValue, wIndex);
> +
> +       ret = usb_control_msg(cyusbs->usb_dev,
> +               usb_sndctrlpipe(cyusbs->usb_dev, 0),
> +               command, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
> +               wValue, wIndex, NULL, 0, CY_USBS_CTRL_XFER_TIMEOUT);
> +
> +       return ret;
> +}
> +
> +static int cy_i2c_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
> +{
> +       int ret;
> +       int actual_read_len = 0;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +
> +       dev_dbg(&adapter->dev, "%s\n", __func__);
> +
> +       ret = usb_bulk_msg(cyusbs->usb_dev,
> +               usb_rcvbulkpipe(cyusbs->usb_dev, cyusbs->bulk_in_ep_num),
> +               msgs[0].buf,
> +               msgs[0].len,
> +               &actual_read_len, CY_USBS_BULK_XFER_TIMEOUT);
> +       if (ret)
> +               dev_err(&adapter->dev,
> +                       "read %d/%d returned %d\n",
> +                       actual_read_len, msgs[0].len, ret);
> +
> +       ret = cy_i2c_recv_status(adapter);
> +
> +       return ret;
> +}
> +
> +static int cy_i2c_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
> +{
> +       int ret;
> +       int actual_write_len = 0;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +
> +       dev_dbg(&adapter->dev, "%s\n", __func__);
> +
> +       ret = usb_bulk_msg(cyusbs->usb_dev,
> +               usb_sndbulkpipe(cyusbs->usb_dev, cyusbs->bulk_out_ep_num),
> +               msgs[0].buf,
> +               msgs[0].len,
> +               &actual_write_len, CY_USBS_BULK_XFER_TIMEOUT);
> +       if (ret)
> +               dev_err(&adapter->dev,
> +                       "write %d/%d returned %d\n",
> +                       actual_write_len, msgs[0].len, ret);
> +
> +       ret = cy_i2c_recv_status(adapter);
> +
> +       return ret;
> +}
> +
> +static int cy_i2c_xfer(struct i2c_adapter *adapter,
> +                      struct i2c_msg *msgs, int num)
> +{
> +       int ret = 0;
> +       struct cyusbs_i2c *cy_i2c;
> +       struct cyusbs23x *cyusbs = (struct cyusbs23x *)adapter->algo_data;
> +
> +       dev_dbg(&adapter->dev, "%s\n", __func__);
> +
> +       if (num > 1) {
> +               dev_err(&adapter->dev, "i2c_msg number is > 1\n");
> +               return -EIO;
> +       }
> +
> +       cy_i2c = to_cyusbs_i2c(adapter);
> +
> +       mutex_lock(&cy_i2c->lock);
> +       if (msgs[0].flags & I2C_M_RD) {
> +               dev_dbg(&adapter->dev,
> +                       "I2C read requested for addr 0x%02x, data length %d\n",
> +                       msgs[0].addr, msgs[0].len);
> +
> +               ret = cy_i2c_set_data_config(cyusbs, cy_i2c, msgs[0].addr,
> +                               msgs[0].len, CY_I2C_READ_CMD);
> +               if (ret < 0) {
> +                       dev_err(&adapter->dev,
> +                               "Set Config (read) failed with %d\n", ret);
> +                       goto io_error;
> +               }
> +
> +               ret = cy_i2c_read(adapter, msgs);
> +               if (ret) {
> +                       dev_err(&adapter->dev,
> +                               "Read failed with error code %d\n", ret);
> +                       goto io_error;
> +               }
> +       } else {
> +               dev_dbg(&adapter->dev,
> +                       "I2C write requested for addr 0x%02x, data length %d\n",
> +                       msgs[0].addr, msgs[0].len);
> +
> +               ret = cy_i2c_set_data_config(cyusbs, cy_i2c, msgs[0].addr,
> +                               msgs[0].len, CY_I2C_WRITE_CMD);
> +               if (ret < 0) {
> +                       dev_err(&adapter->dev,
> +                       "Set Config (write) failed with %d\n", ret);
> +                       goto io_error;
> +               }
> +
> +               ret = cy_i2c_write(adapter, msgs);
> +               if (ret) {
> +                       dev_err(&adapter->dev,
> +                               "Write failed with error code %d\n", ret);
> +                       goto io_error;
> +               }
> +       }
> +       mutex_unlock(&cy_i2c->lock);
> +       return ret;
> +
> +io_error:
> +       mutex_unlock(&cy_i2c->lock);
> +       return ret;
> +}
> +
> +static u32 cy_i2c_func(struct i2c_adapter *adapter)
> +{
> +       return I2C_FUNC_I2C;
> +}
> +
> +static const struct i2c_algorithm i2c_cyusbs23x_algorithm = {
> +       .master_xfer    = cy_i2c_xfer,
> +       .functionality  = cy_i2c_func,
> +};
> +
> +static int cyusbs23x_i2c_probe(struct platform_device *pdev)
> +{
> +       struct cyusbs23x *cyusbs;
> +       struct cyusbs_i2c *cy_i2c;
> +       int ret = 0;
> +
> +       dev_dbg(&pdev->dev, "%s\n", __func__);
> +
> +       cyusbs = dev_get_drvdata(pdev->dev.parent);
> +
> +       cy_i2c = devm_kzalloc(&pdev->dev, sizeof(*cy_i2c), GFP_KERNEL);
> +       if (cy_i2c == NULL)
> +               return -ENOMEM;
> +

dto...

> +       cy_i2c->i2c_config = devm_kzalloc(&pdev->dev,
> +                                       sizeof(struct cyusbs_i2c_config),
> +                                       GFP_KERNEL);
> +       if (cy_i2c->i2c_config == NULL)
> +               return -ENOMEM;
> +

dto...

-- 
Thanks and Regards,
Varka Bhadram.


  parent reply	other threads:[~2014-12-14  2:24 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-13 11:47 [PATCH v5 1/3] mfd: add support for Cypress CYUSBS234 USB Serial Bridge controller Muthu Mani
2014-12-13 11:47 ` Muthu Mani
2014-12-13 11:47 ` [PATCH v5 3/3] gpio: add support for Cypress CYUSBS234 USB-GPIO adapter Muthu Mani
2014-12-13 11:47   ` Muthu Mani
     [not found]   ` <1418471264-31896-3-git-send-email-muth-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>
2014-12-14  2:13     ` Varka Bhadram
2014-12-14  2:13       ` Varka Bhadram
     [not found] ` <1418471264-31896-1-git-send-email-muth-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>
2014-12-13 11:47   ` [PATCH v5 2/3] i2c: add support for Cypress CYUSBS234 USB-I2C adapter Muthu Mani
2014-12-13 11:47     ` Muthu Mani
     [not found]     ` <1418471264-31896-2-git-send-email-muth-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org>
2014-12-14  2:24       ` Varka Bhadram [this message]
2014-12-14  2:24         ` Varka Bhadram
2014-12-15 10:07   ` [PATCH v5 1/3] mfd: add support for Cypress CYUSBS234 USB Serial Bridge controller Johan Hovold
2014-12-15 10:07     ` Johan Hovold

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=548CF4F1.7070607@gmail.com \
    --to=varkabhadram-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
    --cc=gnurou-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org \
    --cc=johan-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=muth-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org \
    --cc=rera-+wT8y+m8/X5BDgjK7y7TUQ@public.gmane.org \
    --cc=sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org \
    --cc=wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.