+++ /dev/null
-/*
- Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of Trident Microsystems nor Hauppauge Computer Works
- nor the names of its contributors may be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
- DESCRIPTION:
- Part of DRX driver.
- Data access protocol: Fast Access Sequential Interface (fasi)
- Fast access, because of short addressing format (16 instead of 32 bits addr)
- Sequential, because of I2C.
- These functions know how the chip's memory and registers are to be accessed,
- but nothing more.
-
- These functions should not need adapting to a new platform.
-*/
-
-#include "drx_dap_fasi.h"
-#include "drx39xxj.h"
-
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-
-
-/*============================================================================*/
-
-/*============================================================================*/
-
-/* Functions not supported by protocol*/
-
-static int drxdap_fasi_write_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */
- u32 addr, /* address of register */
- u8 data, /* data to write */
- u32 flags)
-{ /* special device flags */
- return -EIO;
-}
-
-static int drxdap_fasi_read_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */
- u32 addr, /* address of register */
- u8 *data, /* buffer to receive data */
- u32 flags)
-{ /* special device flags */
- return -EIO;
-}
-
-static int drxdap_fasi_read_modify_write_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */
- u32 waddr, /* address of register */
- u32 raddr, /* address to read back from */
- u8 datain, /* data to send */
- u8 *dataout)
-{ /* data to receive back */
- return -EIO;
-}
-
-static int drxdap_fasi_read_modify_write_reg32(struct i2c_device_addr *dev_addr, /* address of I2C device */
- u32 waddr, /* address of register */
- u32 raddr, /* address to read back from */
- u32 datain, /* data to send */
- u32 *dataout)
-{ /* data to receive back */
- return -EIO;
-}
-
-
-int drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr,
- u16 w_count,
- u8 *wData,
- struct i2c_device_addr *r_dev_addr,
- u16 r_count, u8 *r_data)
-{
- struct drx39xxj_state *state;
- struct i2c_msg msg[2];
- unsigned int num_msgs;
-
- if (w_dev_addr == NULL) {
- /* Read only */
- state = r_dev_addr->user_data;
- msg[0].addr = r_dev_addr->i2c_addr >> 1;
- msg[0].flags = I2C_M_RD;
- msg[0].buf = r_data;
- msg[0].len = r_count;
- num_msgs = 1;
- } else if (r_dev_addr == NULL) {
- /* Write only */
- state = w_dev_addr->user_data;
- msg[0].addr = w_dev_addr->i2c_addr >> 1;
- msg[0].flags = 0;
- msg[0].buf = wData;
- msg[0].len = w_count;
- num_msgs = 1;
- } else {
- /* Both write and read */
- state = w_dev_addr->user_data;
- msg[0].addr = w_dev_addr->i2c_addr >> 1;
- msg[0].flags = 0;
- msg[0].buf = wData;
- msg[0].len = w_count;
- msg[1].addr = r_dev_addr->i2c_addr >> 1;
- msg[1].flags = I2C_M_RD;
- msg[1].buf = r_data;
- msg[1].len = r_count;
- num_msgs = 2;
- }
-
- if (state->i2c == NULL) {
- pr_err("i2c was zero, aborting\n");
- return 0;
- }
- if (i2c_transfer(state->i2c, msg, num_msgs) != num_msgs) {
- pr_warn("drx3933: I2C write/read failed\n");
- return -EREMOTEIO;
- }
-
- return 0;
-
-#ifdef DJH_DEBUG
- struct drx39xxj_state *state = w_dev_addr->user_data;
-
- struct i2c_msg msg[2] = {
- {.addr = w_dev_addr->i2c_addr,
- .flags = 0, .buf = wData, .len = w_count},
- {.addr = r_dev_addr->i2c_addr,
- .flags = I2C_M_RD, .buf = r_data, .len = r_count},
- };
-
- pr_dbg("drx3933 i2c operation addr=%x i2c=%p, wc=%x rc=%x\n",
- w_dev_addr->i2c_addr, state->i2c, w_count, r_count);
-
- if (i2c_transfer(state->i2c, msg, 2) != 2) {
- pr_warn("drx3933: I2C write/read failed\n");
- return -EREMOTEIO;
- }
-#endif
- return 0;
-}
-
-/*============================================================================*/
-
-/******************************
-*
-* int drxdap_fasi_read_block (
-* struct i2c_device_addr *dev_addr, -- address of I2C device
-* u32 addr, -- address of chip register/memory
-* u16 datasize, -- number of bytes to read
-* u8 *data, -- data to receive
-* u32 flags) -- special device flags
-*
-* Read block data from chip address. Because the chip is word oriented,
-* the number of bytes to read must be even.
-*
-* Make sure that the buffer to receive the data is large enough.
-*
-* Although this function expects an even number of bytes, it is still byte
-* oriented, and the data read back is NOT translated to the endianness of
-* the target platform.
-*
-* Output:
-* - 0 if reading was successful
-* in that case: data read is in *data.
-* - -EIO if anything went wrong
-*
-******************************/
-
-static int drxdap_fasi_read_block(struct i2c_device_addr *dev_addr,
- u32 addr,
- u16 datasize,
- u8 *data, u32 flags)
-{
- u8 buf[4];
- u16 bufx;
- int rc;
- u16 overhead_size = 0;
-
- /* Check parameters ******************************************************* */
- if (dev_addr == NULL)
- return -EINVAL;
-
- overhead_size = (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1) +
- (DRXDAP_FASI_LONG_FORMAT(addr) ? 4 : 2);
-
- if ((DRXDAP_FASI_OFFSET_TOO_LARGE(addr)) ||
- ((!(DRXDAPFASI_LONG_ADDR_ALLOWED)) &&
- DRXDAP_FASI_LONG_FORMAT(addr)) ||
- (overhead_size > (DRXDAP_MAX_WCHUNKSIZE)) ||
- ((datasize != 0) && (data == NULL)) || ((datasize & 1) == 1)) {
- return -EINVAL;
- }
-
- /* ReadModifyWrite & mode flag bits are not allowed */
- flags &= (~DRXDAP_FASI_RMW & ~DRXDAP_FASI_MODEFLAGS);
-#if DRXDAP_SINGLE_MASTER
- flags |= DRXDAP_FASI_SINGLE_MASTER;
-#endif
-
- /* Read block from I2C **************************************************** */
- do {
- u16 todo = (datasize < DRXDAP_MAX_RCHUNKSIZE ?
- datasize : DRXDAP_MAX_RCHUNKSIZE);
-
- bufx = 0;
-
- addr &= ~DRXDAP_FASI_FLAGS;
- addr |= flags;
-
-#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
- /* short format address preferred but long format otherwise */
- if (DRXDAP_FASI_LONG_FORMAT(addr)) {
-#endif
-#if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1)
- buf[bufx++] = (u8) (((addr << 1) & 0xFF) | 0x01);
- buf[bufx++] = (u8) ((addr >> 16) & 0xFF);
- buf[bufx++] = (u8) ((addr >> 24) & 0xFF);
- buf[bufx++] = (u8) ((addr >> 7) & 0xFF);
-#endif
-#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
- } else {
-#endif
-#if (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1)
- buf[bufx++] = (u8) ((addr << 1) & 0xFF);
- buf[bufx++] =
- (u8) (((addr >> 16) & 0x0F) |
- ((addr >> 18) & 0xF0));
-#endif
-#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
- }
-#endif
-
-#if DRXDAP_SINGLE_MASTER
- /*
- * In single master mode, split the read and write actions.
- * No special action is needed for write chunks here.
- */
- rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, 0, 0, 0);
- if (rc == 0)
- rc = drxbsp_i2c_write_read(0, 0, 0, dev_addr, todo, data);
-#else
- /* In multi master mode, do everything in one RW action */
- rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, dev_addr, todo,
- data);
-#endif
- data += todo;
- addr += (todo >> 1);
- datasize -= todo;
- } while (datasize && rc == 0);
-
- return rc;
-}
-
-
-/******************************
-*
-* int drxdap_fasi_read_reg16 (
-* struct i2c_device_addr *dev_addr, -- address of I2C device
-* u32 addr, -- address of chip register/memory
-* u16 *data, -- data to receive
-* u32 flags) -- special device flags
-*
-* Read one 16-bit register or memory location. The data received back is
-* converted back to the target platform's endianness.
-*
-* Output:
-* - 0 if reading was successful
-* in that case: read data is at *data
-* - -EIO if anything went wrong
-*
-******************************/
-
-static int drxdap_fasi_read_reg16(struct i2c_device_addr *dev_addr,
- u32 addr,
- u16 *data, u32 flags)
-{
- u8 buf[sizeof(*data)];
- int rc;
-
- if (!data)
- return -EINVAL;
-
- rc = drxdap_fasi_read_block(dev_addr, addr, sizeof(*data), buf, flags);
- *data = buf[0] + (((u16) buf[1]) << 8);
- return rc;
-}
-
-/******************************
-*
-* int drxdap_fasi_read_reg32 (
-* struct i2c_device_addr *dev_addr, -- address of I2C device
-* u32 addr, -- address of chip register/memory
-* u32 *data, -- data to receive
-* u32 flags) -- special device flags
-*
-* Read one 32-bit register or memory location. The data received back is
-* converted back to the target platform's endianness.
-*
-* Output:
-* - 0 if reading was successful
-* in that case: read data is at *data
-* - -EIO if anything went wrong
-*
-******************************/
-
-static int drxdap_fasi_read_reg32(struct i2c_device_addr *dev_addr,
- u32 addr,
- u32 *data, u32 flags)
-{
- u8 buf[sizeof(*data)];
- int rc;
-
- if (!data)
- return -EINVAL;
-
- rc = drxdap_fasi_read_block(dev_addr, addr, sizeof(*data), buf, flags);
- *data = (((u32) buf[0]) << 0) +
- (((u32) buf[1]) << 8) +
- (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24);
- return rc;
-}
-
-/******************************
-*
-* int drxdap_fasi_write_block (
-* struct i2c_device_addr *dev_addr, -- address of I2C device
-* u32 addr, -- address of chip register/memory
-* u16 datasize, -- number of bytes to read
-* u8 *data, -- data to receive
-* u32 flags) -- special device flags
-*
-* Write block data to chip address. Because the chip is word oriented,
-* the number of bytes to write must be even.
-*
-* Although this function expects an even number of bytes, it is still byte
-* oriented, and the data being written is NOT translated from the endianness of
-* the target platform.
-*
-* Output:
-* - 0 if writing was successful
-* - -EIO if anything went wrong
-*
-******************************/
-
-static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr,
- u32 addr,
- u16 datasize,
- u8 *data, u32 flags)
-{
- u8 buf[DRXDAP_MAX_WCHUNKSIZE];
- int st = -EIO;
- int first_err = 0;
- u16 overhead_size = 0;
- u16 block_size = 0;
-
- /* Check parameters ******************************************************* */
- if (dev_addr == NULL)
- return -EINVAL;
-
- overhead_size = (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1) +
- (DRXDAP_FASI_LONG_FORMAT(addr) ? 4 : 2);
-
- if ((DRXDAP_FASI_OFFSET_TOO_LARGE(addr)) ||
- ((!(DRXDAPFASI_LONG_ADDR_ALLOWED)) &&
- DRXDAP_FASI_LONG_FORMAT(addr)) ||
- (overhead_size > (DRXDAP_MAX_WCHUNKSIZE)) ||
- ((datasize != 0) && (data == NULL)) || ((datasize & 1) == 1))
- return -EINVAL;
-
- flags &= DRXDAP_FASI_FLAGS;
- flags &= ~DRXDAP_FASI_MODEFLAGS;
-#if DRXDAP_SINGLE_MASTER
- flags |= DRXDAP_FASI_SINGLE_MASTER;
-#endif
-
- /* Write block to I2C ***************************************************** */
- block_size = ((DRXDAP_MAX_WCHUNKSIZE) - overhead_size) & ~1;
- do {
- u16 todo = 0;
- u16 bufx = 0;
-
- /* Buffer device address */
- addr &= ~DRXDAP_FASI_FLAGS;
- addr |= flags;
-#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
- /* short format address preferred but long format otherwise */
- if (DRXDAP_FASI_LONG_FORMAT(addr)) {
-#endif
-#if ((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1)
- buf[bufx++] = (u8) (((addr << 1) & 0xFF) | 0x01);
- buf[bufx++] = (u8) ((addr >> 16) & 0xFF);
- buf[bufx++] = (u8) ((addr >> 24) & 0xFF);
- buf[bufx++] = (u8) ((addr >> 7) & 0xFF);
-#endif
-#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
- } else {
-#endif
-#if ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1)
- buf[bufx++] = (u8) ((addr << 1) & 0xFF);
- buf[bufx++] =
- (u8) (((addr >> 16) & 0x0F) |
- ((addr >> 18) & 0xF0));
-#endif
-#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
- }
-#endif
-
- /*
- In single master mode block_size can be 0. In such a case this I2C
- sequense will be visible: (1) write address {i2c addr,
- 4 bytes chip address} (2) write data {i2c addr, 4 bytes data }
- (3) write address (4) write data etc...
- Addres must be rewriten because HI is reset after data transport and
- expects an address.
- */
- todo = (block_size < datasize ? block_size : datasize);
- if (todo == 0) {
- u16 overhead_size_i2c_addr = 0;
- u16 data_block_size = 0;
-
- overhead_size_i2c_addr =
- (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1);
- data_block_size =
- (DRXDAP_MAX_WCHUNKSIZE - overhead_size_i2c_addr) & ~1;
-
- /* write device address */
- st = drxbsp_i2c_write_read(dev_addr,
- (u16) (bufx),
- buf,
- (struct i2c_device_addr *)(NULL),
- 0, (u8 *)(NULL));
-
- if ((st != 0) && (first_err == 0)) {
- /* at the end, return the first error encountered */
- first_err = st;
- }
- bufx = 0;
- todo =
- (data_block_size <
- datasize ? data_block_size : datasize);
- }
- memcpy(&buf[bufx], data, todo);
- /* write (address if can do and) data */
- st = drxbsp_i2c_write_read(dev_addr,
- (u16) (bufx + todo),
- buf,
- (struct i2c_device_addr *)(NULL),
- 0, (u8 *)(NULL));
-
- if ((st != 0) && (first_err == 0)) {
- /* at the end, return the first error encountered */
- first_err = st;
- }
- datasize -= todo;
- data += todo;
- addr += (todo >> 1);
- } while (datasize);
-
- return first_err;
-}
-
-/******************************
-*
-* int drxdap_fasi_write_reg16 (
-* struct i2c_device_addr *dev_addr, -- address of I2C device
-* u32 addr, -- address of chip register/memory
-* u16 data, -- data to send
-* u32 flags) -- special device flags
-*
-* Write one 16-bit register or memory location. The data being written is
-* converted from the target platform's endianness to little endian.
-*
-* Output:
-* - 0 if writing was successful
-* - -EIO if anything went wrong
-*
-******************************/
-
-static int drxdap_fasi_write_reg16(struct i2c_device_addr *dev_addr,
- u32 addr,
- u16 data, u32 flags)
-{
- u8 buf[sizeof(data)];
-
- buf[0] = (u8) ((data >> 0) & 0xFF);
- buf[1] = (u8) ((data >> 8) & 0xFF);
-
- return drxdap_fasi_write_block(dev_addr, addr, sizeof(data), buf, flags);
-}
-
-/******************************
-*
-* int drxdap_fasi_read_modify_write_reg16 (
-* struct i2c_device_addr *dev_addr, -- address of I2C device
-* u32 waddr, -- address of chip register/memory
-* u32 raddr, -- chip address to read back from
-* u16 wdata, -- data to send
-* u16 *rdata) -- data to receive back
-*
-* Write 16-bit data, then read back the original contents of that location.
-* Requires long addressing format to be allowed.
-*
-* Before sending data, the data is converted to little endian. The
-* data received back is converted back to the target platform's endianness.
-*
-* WARNING: This function is only guaranteed to work if there is one
-* master on the I2C bus.
-*
-* Output:
-* - 0 if reading was successful
-* in that case: read back data is at *rdata
-* - -EIO if anything went wrong
-*
-******************************/
-
-static int drxdap_fasi_read_modify_write_reg16(struct i2c_device_addr *dev_addr,
- u32 waddr,
- u32 raddr,
- u16 wdata, u16 *rdata)
-{
- int rc = -EIO;
-
-#if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1)
- if (rdata == NULL)
- return -EINVAL;
-
- rc = drxdap_fasi_write_reg16(dev_addr, waddr, wdata, DRXDAP_FASI_RMW);
- if (rc == 0)
- rc = drxdap_fasi_read_reg16(dev_addr, raddr, rdata, 0);
-#endif
-
- return rc;
-}
-
-/******************************
-*
-* int drxdap_fasi_write_reg32 (
-* struct i2c_device_addr *dev_addr, -- address of I2C device
-* u32 addr, -- address of chip register/memory
-* u32 data, -- data to send
-* u32 flags) -- special device flags
-*
-* Write one 32-bit register or memory location. The data being written is
-* converted from the target platform's endianness to little endian.
-*
-* Output:
-* - 0 if writing was successful
-* - -EIO if anything went wrong
-*
-******************************/
-
-static int drxdap_fasi_write_reg32(struct i2c_device_addr *dev_addr,
- u32 addr,
- u32 data, u32 flags)
-{
- u8 buf[sizeof(data)];
-
- buf[0] = (u8) ((data >> 0) & 0xFF);
- buf[1] = (u8) ((data >> 8) & 0xFF);
- buf[2] = (u8) ((data >> 16) & 0xFF);
- buf[3] = (u8) ((data >> 24) & 0xFF);
-
- return drxdap_fasi_write_block(dev_addr, addr, sizeof(data), buf, flags);
-}
-
-/* The structure containing the protocol interface */
-struct drx_access_func drx_dap_fasi_funct_g = {
- drxdap_fasi_write_block, /* Supported */
- drxdap_fasi_read_block, /* Supported */
- drxdap_fasi_write_reg8, /* Not supported */
- drxdap_fasi_read_reg8, /* Not supported */
- drxdap_fasi_read_modify_write_reg8, /* Not supported */
- drxdap_fasi_write_reg16, /* Supported */
- drxdap_fasi_read_reg16, /* Supported */
- drxdap_fasi_read_modify_write_reg16, /* Supported */
- drxdap_fasi_write_reg32, /* Supported */
- drxdap_fasi_read_reg32, /* Supported */
- drxdap_fasi_read_modify_write_reg32 /* Not supported */
-};
/*============================================================================*/
+/* Functions not supported by protocol*/
+
+static int drxdap_fasi_write_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register */
+ u8 data, /* data to write */
+ u32 flags)
+{ /* special device flags */
+ return -EIO;
+}
+
+static int drxdap_fasi_read_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 addr, /* address of register */
+ u8 *data, /* buffer to receive data */
+ u32 flags)
+{ /* special device flags */
+ return -EIO;
+}
+
+static int drxdap_fasi_read_modify_write_reg8(struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 waddr, /* address of register */
+ u32 raddr, /* address to read back from */
+ u8 datain, /* data to send */
+ u8 *dataout)
+{ /* data to receive back */
+ return -EIO;
+}
+
+static int drxdap_fasi_read_modify_write_reg32(struct i2c_device_addr *dev_addr, /* address of I2C device */
+ u32 waddr, /* address of register */
+ u32 raddr, /* address to read back from */
+ u32 datain, /* data to send */
+ u32 *dataout)
+{ /* data to receive back */
+ return -EIO;
+}
+
+
+int drxbsp_i2c_write_read(struct i2c_device_addr *w_dev_addr,
+ u16 w_count,
+ u8 *wData,
+ struct i2c_device_addr *r_dev_addr,
+ u16 r_count, u8 *r_data)
+{
+ struct drx39xxj_state *state;
+ struct i2c_msg msg[2];
+ unsigned int num_msgs;
+
+ if (w_dev_addr == NULL) {
+ /* Read only */
+ state = r_dev_addr->user_data;
+ msg[0].addr = r_dev_addr->i2c_addr >> 1;
+ msg[0].flags = I2C_M_RD;
+ msg[0].buf = r_data;
+ msg[0].len = r_count;
+ num_msgs = 1;
+ } else if (r_dev_addr == NULL) {
+ /* Write only */
+ state = w_dev_addr->user_data;
+ msg[0].addr = w_dev_addr->i2c_addr >> 1;
+ msg[0].flags = 0;
+ msg[0].buf = wData;
+ msg[0].len = w_count;
+ num_msgs = 1;
+ } else {
+ /* Both write and read */
+ state = w_dev_addr->user_data;
+ msg[0].addr = w_dev_addr->i2c_addr >> 1;
+ msg[0].flags = 0;
+ msg[0].buf = wData;
+ msg[0].len = w_count;
+ msg[1].addr = r_dev_addr->i2c_addr >> 1;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = r_data;
+ msg[1].len = r_count;
+ num_msgs = 2;
+ }
+
+ if (state->i2c == NULL) {
+ pr_err("i2c was zero, aborting\n");
+ return 0;
+ }
+ if (i2c_transfer(state->i2c, msg, num_msgs) != num_msgs) {
+ pr_warn("drx3933: I2C write/read failed\n");
+ return -EREMOTEIO;
+ }
+
+ return 0;
+
+#ifdef DJH_DEBUG
+ struct drx39xxj_state *state = w_dev_addr->user_data;
+
+ struct i2c_msg msg[2] = {
+ {.addr = w_dev_addr->i2c_addr,
+ .flags = 0, .buf = wData, .len = w_count},
+ {.addr = r_dev_addr->i2c_addr,
+ .flags = I2C_M_RD, .buf = r_data, .len = r_count},
+ };
+
+ pr_dbg("drx3933 i2c operation addr=%x i2c=%p, wc=%x rc=%x\n",
+ w_dev_addr->i2c_addr, state->i2c, w_count, r_count);
+
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ pr_warn("drx3933: I2C write/read failed\n");
+ return -EREMOTEIO;
+ }
+#endif
+ return 0;
+}
+
+/*============================================================================*/
+
+/******************************
+*
+* int drxdap_fasi_read_block (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u16 datasize, -- number of bytes to read
+* u8 *data, -- data to receive
+* u32 flags) -- special device flags
+*
+* Read block data from chip address. Because the chip is word oriented,
+* the number of bytes to read must be even.
+*
+* Make sure that the buffer to receive the data is large enough.
+*
+* Although this function expects an even number of bytes, it is still byte
+* oriented, and the data read back is NOT translated to the endianness of
+* the target platform.
+*
+* Output:
+* - 0 if reading was successful
+* in that case: data read is in *data.
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_read_block(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 datasize,
+ u8 *data, u32 flags)
+{
+ u8 buf[4];
+ u16 bufx;
+ int rc;
+ u16 overhead_size = 0;
+
+ /* Check parameters ******************************************************* */
+ if (dev_addr == NULL)
+ return -EINVAL;
+
+ overhead_size = (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1) +
+ (DRXDAP_FASI_LONG_FORMAT(addr) ? 4 : 2);
+
+ if ((DRXDAP_FASI_OFFSET_TOO_LARGE(addr)) ||
+ ((!(DRXDAPFASI_LONG_ADDR_ALLOWED)) &&
+ DRXDAP_FASI_LONG_FORMAT(addr)) ||
+ (overhead_size > (DRXDAP_MAX_WCHUNKSIZE)) ||
+ ((datasize != 0) && (data == NULL)) || ((datasize & 1) == 1)) {
+ return -EINVAL;
+ }
+
+ /* ReadModifyWrite & mode flag bits are not allowed */
+ flags &= (~DRXDAP_FASI_RMW & ~DRXDAP_FASI_MODEFLAGS);
+#if DRXDAP_SINGLE_MASTER
+ flags |= DRXDAP_FASI_SINGLE_MASTER;
+#endif
+
+ /* Read block from I2C **************************************************** */
+ do {
+ u16 todo = (datasize < DRXDAP_MAX_RCHUNKSIZE ?
+ datasize : DRXDAP_MAX_RCHUNKSIZE);
+
+ bufx = 0;
+
+ addr &= ~DRXDAP_FASI_FLAGS;
+ addr |= flags;
+
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
+ /* short format address preferred but long format otherwise */
+ if (DRXDAP_FASI_LONG_FORMAT(addr)) {
+#endif
+#if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1)
+ buf[bufx++] = (u8) (((addr << 1) & 0xFF) | 0x01);
+ buf[bufx++] = (u8) ((addr >> 16) & 0xFF);
+ buf[bufx++] = (u8) ((addr >> 24) & 0xFF);
+ buf[bufx++] = (u8) ((addr >> 7) & 0xFF);
+#endif
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
+ } else {
+#endif
+#if (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1)
+ buf[bufx++] = (u8) ((addr << 1) & 0xFF);
+ buf[bufx++] =
+ (u8) (((addr >> 16) & 0x0F) |
+ ((addr >> 18) & 0xF0));
+#endif
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED == 1) && (DRXDAPFASI_SHORT_ADDR_ALLOWED == 1))
+ }
+#endif
+
+#if DRXDAP_SINGLE_MASTER
+ /*
+ * In single master mode, split the read and write actions.
+ * No special action is needed for write chunks here.
+ */
+ rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, 0, 0, 0);
+ if (rc == 0)
+ rc = drxbsp_i2c_write_read(0, 0, 0, dev_addr, todo, data);
+#else
+ /* In multi master mode, do everything in one RW action */
+ rc = drxbsp_i2c_write_read(dev_addr, bufx, buf, dev_addr, todo,
+ data);
+#endif
+ data += todo;
+ addr += (todo >> 1);
+ datasize -= todo;
+ } while (datasize && rc == 0);
+
+ return rc;
+}
+
+
+/******************************
+*
+* int drxdap_fasi_read_reg16 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u16 *data, -- data to receive
+* u32 flags) -- special device flags
+*
+* Read one 16-bit register or memory location. The data received back is
+* converted back to the target platform's endianness.
+*
+* Output:
+* - 0 if reading was successful
+* in that case: read data is at *data
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_read_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 *data, u32 flags)
+{
+ u8 buf[sizeof(*data)];
+ int rc;
+
+ if (!data)
+ return -EINVAL;
+
+ rc = drxdap_fasi_read_block(dev_addr, addr, sizeof(*data), buf, flags);
+ *data = buf[0] + (((u16) buf[1]) << 8);
+ return rc;
+}
+
+/******************************
+*
+* int drxdap_fasi_read_reg32 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u32 *data, -- data to receive
+* u32 flags) -- special device flags
+*
+* Read one 32-bit register or memory location. The data received back is
+* converted back to the target platform's endianness.
+*
+* Output:
+* - 0 if reading was successful
+* in that case: read data is at *data
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_read_reg32(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u32 *data, u32 flags)
+{
+ u8 buf[sizeof(*data)];
+ int rc;
+
+ if (!data)
+ return -EINVAL;
+
+ rc = drxdap_fasi_read_block(dev_addr, addr, sizeof(*data), buf, flags);
+ *data = (((u32) buf[0]) << 0) +
+ (((u32) buf[1]) << 8) +
+ (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24);
+ return rc;
+}
+
+/******************************
+*
+* int drxdap_fasi_write_block (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u16 datasize, -- number of bytes to read
+* u8 *data, -- data to receive
+* u32 flags) -- special device flags
+*
+* Write block data to chip address. Because the chip is word oriented,
+* the number of bytes to write must be even.
+*
+* Although this function expects an even number of bytes, it is still byte
+* oriented, and the data being written is NOT translated from the endianness of
+* the target platform.
+*
+* Output:
+* - 0 if writing was successful
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 datasize,
+ u8 *data, u32 flags)
+{
+ u8 buf[DRXDAP_MAX_WCHUNKSIZE];
+ int st = -EIO;
+ int first_err = 0;
+ u16 overhead_size = 0;
+ u16 block_size = 0;
+
+ /* Check parameters ******************************************************* */
+ if (dev_addr == NULL)
+ return -EINVAL;
+
+ overhead_size = (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1) +
+ (DRXDAP_FASI_LONG_FORMAT(addr) ? 4 : 2);
+
+ if ((DRXDAP_FASI_OFFSET_TOO_LARGE(addr)) ||
+ ((!(DRXDAPFASI_LONG_ADDR_ALLOWED)) &&
+ DRXDAP_FASI_LONG_FORMAT(addr)) ||
+ (overhead_size > (DRXDAP_MAX_WCHUNKSIZE)) ||
+ ((datasize != 0) && (data == NULL)) || ((datasize & 1) == 1))
+ return -EINVAL;
+
+ flags &= DRXDAP_FASI_FLAGS;
+ flags &= ~DRXDAP_FASI_MODEFLAGS;
+#if DRXDAP_SINGLE_MASTER
+ flags |= DRXDAP_FASI_SINGLE_MASTER;
+#endif
+
+ /* Write block to I2C ***************************************************** */
+ block_size = ((DRXDAP_MAX_WCHUNKSIZE) - overhead_size) & ~1;
+ do {
+ u16 todo = 0;
+ u16 bufx = 0;
+
+ /* Buffer device address */
+ addr &= ~DRXDAP_FASI_FLAGS;
+ addr |= flags;
+#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
+ /* short format address preferred but long format otherwise */
+ if (DRXDAP_FASI_LONG_FORMAT(addr)) {
+#endif
+#if ((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1)
+ buf[bufx++] = (u8) (((addr << 1) & 0xFF) | 0x01);
+ buf[bufx++] = (u8) ((addr >> 16) & 0xFF);
+ buf[bufx++] = (u8) ((addr >> 24) & 0xFF);
+ buf[bufx++] = (u8) ((addr >> 7) & 0xFF);
+#endif
+#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
+ } else {
+#endif
+#if ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1)
+ buf[bufx++] = (u8) ((addr << 1) & 0xFF);
+ buf[bufx++] =
+ (u8) (((addr >> 16) & 0x0F) |
+ ((addr >> 18) & 0xF0));
+#endif
+#if (((DRXDAPFASI_LONG_ADDR_ALLOWED) == 1) && ((DRXDAPFASI_SHORT_ADDR_ALLOWED) == 1))
+ }
+#endif
+
+ /*
+ In single master mode block_size can be 0. In such a case this I2C
+ sequense will be visible: (1) write address {i2c addr,
+ 4 bytes chip address} (2) write data {i2c addr, 4 bytes data }
+ (3) write address (4) write data etc...
+ Addres must be rewriten because HI is reset after data transport and
+ expects an address.
+ */
+ todo = (block_size < datasize ? block_size : datasize);
+ if (todo == 0) {
+ u16 overhead_size_i2c_addr = 0;
+ u16 data_block_size = 0;
+
+ overhead_size_i2c_addr =
+ (IS_I2C_10BIT(dev_addr->i2c_addr) ? 2 : 1);
+ data_block_size =
+ (DRXDAP_MAX_WCHUNKSIZE - overhead_size_i2c_addr) & ~1;
+
+ /* write device address */
+ st = drxbsp_i2c_write_read(dev_addr,
+ (u16) (bufx),
+ buf,
+ (struct i2c_device_addr *)(NULL),
+ 0, (u8 *)(NULL));
+
+ if ((st != 0) && (first_err == 0)) {
+ /* at the end, return the first error encountered */
+ first_err = st;
+ }
+ bufx = 0;
+ todo =
+ (data_block_size <
+ datasize ? data_block_size : datasize);
+ }
+ memcpy(&buf[bufx], data, todo);
+ /* write (address if can do and) data */
+ st = drxbsp_i2c_write_read(dev_addr,
+ (u16) (bufx + todo),
+ buf,
+ (struct i2c_device_addr *)(NULL),
+ 0, (u8 *)(NULL));
+
+ if ((st != 0) && (first_err == 0)) {
+ /* at the end, return the first error encountered */
+ first_err = st;
+ }
+ datasize -= todo;
+ data += todo;
+ addr += (todo >> 1);
+ } while (datasize);
+
+ return first_err;
+}
+
+/******************************
+*
+* int drxdap_fasi_write_reg16 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u16 data, -- data to send
+* u32 flags) -- special device flags
+*
+* Write one 16-bit register or memory location. The data being written is
+* converted from the target platform's endianness to little endian.
+*
+* Output:
+* - 0 if writing was successful
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u16 data, u32 flags)
+{
+ u8 buf[sizeof(data)];
+
+ buf[0] = (u8) ((data >> 0) & 0xFF);
+ buf[1] = (u8) ((data >> 8) & 0xFF);
+
+ return drxdap_fasi_write_block(dev_addr, addr, sizeof(data), buf, flags);
+}
+
+/******************************
+*
+* int drxdap_fasi_read_modify_write_reg16 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 waddr, -- address of chip register/memory
+* u32 raddr, -- chip address to read back from
+* u16 wdata, -- data to send
+* u16 *rdata) -- data to receive back
+*
+* Write 16-bit data, then read back the original contents of that location.
+* Requires long addressing format to be allowed.
+*
+* Before sending data, the data is converted to little endian. The
+* data received back is converted back to the target platform's endianness.
+*
+* WARNING: This function is only guaranteed to work if there is one
+* master on the I2C bus.
+*
+* Output:
+* - 0 if reading was successful
+* in that case: read back data is at *rdata
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_read_modify_write_reg16(struct i2c_device_addr *dev_addr,
+ u32 waddr,
+ u32 raddr,
+ u16 wdata, u16 *rdata)
+{
+ int rc = -EIO;
+
+#if (DRXDAPFASI_LONG_ADDR_ALLOWED == 1)
+ if (rdata == NULL)
+ return -EINVAL;
+
+ rc = drxdap_fasi_write_reg16(dev_addr, waddr, wdata, DRXDAP_FASI_RMW);
+ if (rc == 0)
+ rc = drxdap_fasi_read_reg16(dev_addr, raddr, rdata, 0);
+#endif
+
+ return rc;
+}
+
+/******************************
+*
+* int drxdap_fasi_write_reg32 (
+* struct i2c_device_addr *dev_addr, -- address of I2C device
+* u32 addr, -- address of chip register/memory
+* u32 data, -- data to send
+* u32 flags) -- special device flags
+*
+* Write one 32-bit register or memory location. The data being written is
+* converted from the target platform's endianness to little endian.
+*
+* Output:
+* - 0 if writing was successful
+* - -EIO if anything went wrong
+*
+******************************/
+
+static int drxdap_fasi_write_reg32(struct i2c_device_addr *dev_addr,
+ u32 addr,
+ u32 data, u32 flags)
+{
+ u8 buf[sizeof(data)];
+
+ buf[0] = (u8) ((data >> 0) & 0xFF);
+ buf[1] = (u8) ((data >> 8) & 0xFF);
+ buf[2] = (u8) ((data >> 16) & 0xFF);
+ buf[3] = (u8) ((data >> 24) & 0xFF);
+
+ return drxdap_fasi_write_block(dev_addr, addr, sizeof(data), buf, flags);
+}
+
+/* The structure containing the protocol interface */
+struct drx_access_func drx_dap_fasi_funct_g = {
+ drxdap_fasi_write_block, /* Supported */
+ drxdap_fasi_read_block, /* Supported */
+ drxdap_fasi_write_reg8, /* Not supported */
+ drxdap_fasi_read_reg8, /* Not supported */
+ drxdap_fasi_read_modify_write_reg8, /* Not supported */
+ drxdap_fasi_write_reg16, /* Supported */
+ drxdap_fasi_read_reg16, /* Supported */
+ drxdap_fasi_read_modify_write_reg16, /* Supported */
+ drxdap_fasi_write_reg32, /* Supported */
+ drxdap_fasi_read_reg32, /* Supported */
+ drxdap_fasi_read_modify_write_reg32 /* Not supported */
+};
+
static int drxj_dap_read_block(struct i2c_device_addr *dev_addr,
u32 addr,
u16 datasize,