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,