From 73b3fc3d74de4ccba5775476d685e062b7774e64 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 27 Jan 2014 02:14:14 -0300 Subject: [PATCH] [media] drx-j: get rid of drx_dap_fasi.c This file contains an abstract layer for the I2C transfer functions. Get rid of it, merging it at drxj. This will allow to remove another abstraction layer there, making the code easier to read, and removing the functions that just return -EIO. Acked-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drx39xyj/Makefile | 2 +- .../dvb-frontends/drx39xyj/drx_dap_fasi.c | 598 ------------------ drivers/media/dvb-frontends/drx39xyj/drxj.c | 548 ++++++++++++++++ 3 files changed, 549 insertions(+), 599 deletions(-) delete mode 100644 drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.c diff --git a/drivers/media/dvb-frontends/drx39xyj/Makefile b/drivers/media/dvb-frontends/drx39xyj/Makefile index 7f073d4c28ec..672e07774955 100644 --- a/drivers/media/dvb-frontends/drx39xyj/Makefile +++ b/drivers/media/dvb-frontends/drx39xyj/Makefile @@ -1,4 +1,4 @@ -drx39xyj-objs := drx39xxj_dummy.o drxj.o drx_dap_fasi.o +drx39xyj-objs := drxj.o obj-$(CONFIG_DVB_DRX39XYJ) += drx39xyj.o diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.c b/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.c deleted file mode 100644 index 3e456ba780eb..000000000000 --- a/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - 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 -#include - - -/*============================================================================*/ - -/*============================================================================*/ - -/* 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 */ -}; diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 1e202dafe335..94c3d6f0d5b8 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -1540,6 +1540,554 @@ bool is_handled_by_aud_tr_if(u32 addr) /*============================================================================*/ +/* 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, -- 2.20.1