From: Michael Bringmann <michael.bringm...@lsi.com> Accept more data extracted from DTB block to configure an I2C bus, instead of using hard-coded addresses in code. Revise module to configure only those busses actually configured. Remove unneeded code, and compress header files.
Signed-off-by: Michael Bringmann <michael.bringm...@lsi.com> --- drivers/i2c/busses/ai2c/ai2c_bus.h | 93 +------ drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c | 24 +- drivers/i2c/busses/ai2c/ai2c_dev.h | 165 ++++++++++-- drivers/i2c/busses/ai2c/ai2c_dev_clock.c | 4 +- drivers/i2c/busses/ai2c/ai2c_dev_clock_ext.h | 2 +- drivers/i2c/busses/ai2c/ai2c_mod.c | 149 ++++++----- drivers/i2c/busses/ai2c/ai2c_plat.c | 379 +++++++++++---------------- drivers/i2c/busses/ai2c/ai2c_plat.h | 75 +++++- drivers/i2c/busses/ai2c/ai2c_sal.c | 15 +- drivers/i2c/busses/ai2c/ai2c_sal.h | 351 ++++++++++++++++++++++++- drivers/i2c/busses/ai2c/ai2c_types.h | 54 +++- 11 files changed, 850 insertions(+), 461 deletions(-) diff --git a/drivers/i2c/busses/ai2c/ai2c_bus.h b/drivers/i2c/busses/ai2c/ai2c_bus.h index 97c9fe5..8861ae5 100644 --- a/drivers/i2c/busses/ai2c/ai2c_bus.h +++ b/drivers/i2c/busses/ai2c/ai2c_bus.h @@ -52,8 +52,8 @@ */ #define AI2C_I2CPROT_MAX_BUF_SIZE 8 -#define AI2C_I2C_CHECK_COUNT 0xFFFFF /* Max number of tries at looking for an I/O success */ +#define AI2C_I2C_CHECK_COUNT 0xFFFFF /***************************** * ACP3400 * @@ -92,61 +92,6 @@ #define DEV_10BIT_AUTO(ioc) TENBIT_SETENABLED(ioc) -/* - * Application-specific (BUS) timing constants, types, etc. - */ - -#define CFG_CLK_CONFIG_SCL_LOW (1000) /* (MCC-0x143.0x0.0x1c) - bits 9:0 (MCC LPD) */ -#define CFG_CLK_CONFIG_SCL_HIGH (1000) /* (MCC-0x143.0x0.0x1c) - bits 25:16 (MCC HPD) */ -#define CFG_START_SETUP_PERIOD (940) /* (MSTSHC-0x143.0x0.0x20) - bits 9:0 (MSTSHC SETDU) */ -#define CFG_START_HOLD_PERIOD (800) /* (MSTSHC-0x143.0x0.0x20) - bits 25:16 (MSTSHC HLDDU) */ -#define CFG_STOP_SETUP_PERIOD (800) /* (MSPSHC-0x143.0x0.0x24) - bits 9:0 (MSPSHC SETDU) */ -#define CFG_STOP_HOLD_PERIOD (0) /* (MSPSHC-0x143.0x0.0x24) - bits 25:16 (MSPSHC HLDDU) */ -#define CFG_DATA_SETUP_PERIOD (50) /* (MDSHC-0x143.0x0.0x28) - bits 9:0 (MDSHC SETDU) */ -#define CFG_DATA_HOLD_PERIOD (0) /* (MSPSHC-0x143.0x0.0x28) - bits 25:16 (MDSHC HLDDU) */ - -/*! @def AI2C_I2C_IOCONFIG_READ_DEFAULT - * @brief Easy default initialization for ai2c_i2c_config_acp3400_t.readTiming. - */ -#define AI2C_I2C_IOCONFIG_READ_DEFAULT \ -{ \ - CFG_CLK_CONFIG_SCL_HIGH, \ - CFG_CLK_CONFIG_SCL_LOW, \ - CFG_START_SETUP_PERIOD, \ - CFG_START_HOLD_PERIOD, \ - CFG_STOP_SETUP_PERIOD, \ - CFG_STOP_HOLD_PERIOD, \ - CFG_DATA_SETUP_PERIOD, \ - CFG_DATA_HOLD_PERIOD, \ -} - -/*! @def AI2C_I2C_IOCONFIG_WRITE_DEFAULT - * @brief Easy default initialization for ai2c_i2c_config_acp3400_t.writeTiming. - */ -#define AI2C_I2C_IOCONFIG_WRITE_DEFAULT \ -{ \ - CFG_CLK_CONFIG_SCL_HIGH, \ - CFG_CLK_CONFIG_SCL_LOW, \ - CFG_START_SETUP_PERIOD, \ - CFG_START_HOLD_PERIOD, \ - CFG_STOP_SETUP_PERIOD, \ - CFG_STOP_HOLD_PERIOD, \ - CFG_DATA_SETUP_PERIOD, \ - CFG_DATA_HOLD_PERIOD, \ -} - -#define AI2C_I2C_IOCONFIG_WAITPOSTWRITE_DEFAULT (5000) /* 5ms for each */ -#define AI2C_I2C_IOCONFIG_WAITPOSTREAD_DEFAULT (0) /* 0ms for each */ - - /***************************************************************************** * Type definitions * *****************************************************************************/ @@ -216,42 +161,6 @@ struct ai2c_i2c_access { void *extra; }; - /********************************************* - * ACP3400-like I2C Devices Definitions, etc. - ********************************************/ - -/*! @struct ai2c_i2c_ioconfig - @brief Timing Control Configuration for I2C registers -*/ -struct ai2c_i2c_ioconfig { - u32 clkPulseWidthHigh:10; - /*!< Number of pclk durations that equal - * high period of SCL*/ - u32 clkPulseWidthLow:10; - /*!< Number of pclk durations that equal - * low period of SCL */ - u32 startSetupTime:10; - /*!< Number of pclk durations that equal - * setup condition on SDA */ - u32 startHoldTime:10; - /*!< Number of pclk durations that equal - * hold condition on SDA */ - u32 stopSetupTime:10; - /*!< Number of pclk durations that equal - * stop condition on SDA */ - u32 stopHoldTime:10; - /*!< Number of pclk durations that equal - * setup condition on SDA */ - u32 dataSetupTime:10; - /*!< Number of pclk durations that equal - * setup condition on SDA for data changing*/ - u32 dataHoldTime:10; - /*!< Number of pclk durations that equal - * hold condition on SDA for data changing*/ -}; - - -extern struct ai2c_i2c_access ai2c_acp3400_cfg; /********************************************* * AXM5500-like I2C Devices Definitions, etc. diff --git a/drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c b/drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c index 4066125..01c1a38 100644 --- a/drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c +++ b/drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c @@ -22,7 +22,8 @@ /* #define EXTRA_DEBUG */ -#include "ai2c_plat_pvt.h" +#include "ai2c_bus.h" +#include "ai2c_plat.h" #include "ai2c_dev_clock_ext.h" #include "regs/ai2c_i2c_regs.h" #include "regs/ai2c_axi_timer_regs.h" @@ -75,12 +76,14 @@ static int ai2c_bus_init_axm5500(struct ai2c_priv *priv, AI2C_LOG(AI2C_MSG_DEBUG, - "bus_init_axm5500: 0x%04x.0x%04x.0x%x = 0x%08x (0x%08x)\n", + "bus_init_axm5500: 0x%04x.0x%04x.0x%x = 0x%08x " + "(0x%08x)\n", AI2C_NODE_ID(inRegionId), AI2C_TARGET_ID(inRegionId), AI2C_REG_I2C_X7_UDID_W7, v0, AI2C_REG_I2C_X7_UDID_W7_DEFAULT); AI2C_LOG(AI2C_MSG_DEBUG, - "bus_init_axm5500: 0x%04x.0x%04x.0x%x = 0x%08x (0x%08x)\n", + "bus_init_axm5500: 0x%04x.0x%04x.0x%x = 0x%08x " + "(0x%08x)\n", AI2C_NODE_ID(inRegionId), AI2C_TARGET_ID(inRegionId), AI2C_REG_I2C_X7_UDID_W4, v1, AI2C_REG_I2C_X7_UDID_W4_DEFAULT); @@ -140,7 +143,7 @@ static int ai2c_bus_init_axm5500(struct ai2c_priv *priv, AI2C_CALL(ai2c_dev_write32(priv, inRegionId, AI2C_REG_I2C_X7_WAIT_TIMER_CONTROL, 0x00008989)); -AI2C_RETURN_LABEL +ai2c_return: AI2C_LOG(AI2C_MSG_EXIT, "bus_init_axm5500: exit (%d)\n", ai2cStatus); @@ -315,7 +318,7 @@ static int ai2c_bus_block_read8_axm5500_internal( buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); -AI2C_RETURN_LABEL +ai2c_return: AI2C_LOG(AI2C_MSG_EXIT, "read8_i: exit; st=%d; rcvd=%d\n", ai2cStatus, (*actCount)); @@ -323,7 +326,7 @@ AI2C_RETURN_LABEL return ai2cStatus; } -static int ai2c_bus_block_read8_axm5500( +int ai2c_bus_block_read8_axm5500( struct ai2c_priv *priv, u32 regionId, struct i2c_adapter *adap, @@ -367,7 +370,7 @@ static int ai2c_bus_block_read8_axm5500( bytesRead += actCount; } -AI2C_RETURN_LABEL +ai2c_return: AI2C_LOG(AI2C_MSG_EXIT, "read8: exit; st=%d l=%d\n", ai2cStatus, actCount); @@ -542,7 +545,7 @@ static int ai2c_bus_block_write8_axm5500_internal( (*actCount) = (numInFifo & 0xFF); -AI2C_RETURN_LABEL +ai2c_return: AI2C_LOG(AI2C_MSG_EXIT, "write8_i: exit; st=%d; num of bytes sent is %d (%d)\n", @@ -605,7 +608,8 @@ static int ai2c_bus_block_write8_axm5500( goto ai2c_return; AI2C_LOG(AI2C_MSG_DEBUG, - "write8: tbm %d l %d aw %d c %d cu %d[%x,%x,%x,%x,%x,%x,%x,%x]\n", + "write8: tbm %d l %d aw %d c %d cu %d" + "[%x,%x,%x,%x,%x,%x,%x,%x]\n", lTenBitMode, thisXfr, actWid, count, countUsed, inOutTxd[0], inOutTxd[1], inOutTxd[2], inOutTxd[3], inOutTxd[4], inOutTxd[5], inOutTxd[6], inOutTxd[7]); @@ -614,7 +618,7 @@ static int ai2c_bus_block_write8_axm5500( countRem -= actWid; } -AI2C_RETURN_LABEL +ai2c_return: AI2C_LOG(AI2C_MSG_EXIT, "write8: exit; st=%d\n", ai2cStatus); diff --git a/drivers/i2c/busses/ai2c/ai2c_dev.h b/drivers/i2c/busses/ai2c/ai2c_dev.h index fe9493b..8cbc03b 100644 --- a/drivers/i2c/busses/ai2c/ai2c_dev.h +++ b/drivers/i2c/busses/ai2c/ai2c_dev.h @@ -20,34 +20,27 @@ * MA 02111-1307 USA */ -/*! @file AI2C_dev.h - * @brief Exported Device-level APIs. - * @addtogroup _device_APIs Device Level APIs - * Device-level APIs work with flat memory in each device, specifying - * addresses or ranges of addresses. The object-level APIs call these - * device-level APIs, and the host program can also call the device-level - * APIs directly. - * - * @{ - */ - #ifndef __AI2C_DEV_H__ #define __AI2C_DEV_H__ -/* - * AI2C_dev.h - * - * This is the external header file for the AI2C device driver. - * This provides the function prototypes and associated definitions - * needed for the user application to access the device APIs. - * - */ - -/* - * Includes - */ #include "ai2c_types.h" +#include "ai2c_sal.h" +#include "regs/ai2c_regions.h" + + +/* BEGIN: Important forward type references */ + +struct ai2c_region_io; +struct ai2c_priv; + +/* END: Important forward type references */ + + +/* --- Linux References --- */ +#ifndef AI2C_MOD_NAME +#define AI2C_MOD_NAME "ai2c" +#endif /* --- Maximum version string length --- */ @@ -106,4 +99,130 @@ struct ai2c_access_map { { 0, 0, AI2C_DEV_ACCESS_NONE } \ } + +/* --- Internal Types & Definitions --- */ + +#define AI2C_DEV_ACCESS_NONE (0x00) +#define AI2C_DEV_ACCESS_READ (0x01) +#define AI2C_DEV_ACCESS_WRITE (0x02) +#define AI2C_DEV_ACCESS_RW (0x03) +#define AI2C_DEV_ACCESS_BIG_ENDIAN (0x04) +#define AI2C_DEV_ACCESS_LITTLE_ENDIAN (0x08) + + +#define AI2C_DEV_SIZE_1KB (1024*1) +#define AI2C_DEV_SIZE_4KB (1024*4) +#define AI2C_DEV_SIZE_128KB (1024*128) +#define AI2C_DEV_SIZE_256KB (1024*256) +#define AI2C_DEV_SIZE_2MB (1024*1024*2) +#define AI2C_DEV_SIZE_16MB (1024*1024*16) +#define AI2C_DEV_SIZE_128MB (1024*1024*128) +#define AI2C_DEV_SIZE_1GB (1024*1024*1024) +#define AI2C_DEV_SIZE_NO_SIZE (0) + + +/* read/write fn prototypes for region map function pointers */ + +typedef int (*_ai2c_dev_read_fn_t) ( + struct ai2c_priv *priv, + struct ai2c_region_io *region, + u64 offset, + u32 *buffer, + u32 count, + u32 flags, + u32 cmdType, + u32 xferWidth); + +typedef int (*_ai2c_dev_write_fn_t) ( + struct ai2c_priv *priv, + struct ai2c_region_io *region, + u64 offset, + u32 *buffer, + u32 count, + u32 flags, + u32 cmdType, + u32 xferWidth); + +/* + * Structure definition(s) for the region map. + * See above for typedef ai2c_region_io_t. + */ +struct ai2c_region_io { + u32 regionId; + struct ai2c_access_map *accessMap; + _ai2c_dev_read_fn_t readFn; + _ai2c_dev_write_fn_t writeFn; + u32 pageId; +}; + +/* + * Sometimes it would be better to define a range of similar regions + * with a single entry in the region map, especially, for regions + * that are logical or virtual entities that involve interpretation, + * calculated addresses based upon the regionId, or some other + * transformation. The alternate region map such definitions. + */ +struct ai2c_region_iorng { + u32 startRegionId; + u32 endRegionId; + struct ai2c_access_map *accessMap; + _ai2c_dev_read_fn_t readFn; + _ai2c_dev_write_fn_t writeFn; + u32 pageId; +}; + + +/* + * Basic i/o methods + */ + +#ifdef DEBUG_EDEV_IO +#define AI2C_WRITE_LOG(ctx, dev, pageId, offset, value) \ + AI2C_MSG(AI2C_MSG_DEBUG_IO, \ + "%s: pageId=0x%x offset=0x%x addr=0x%x value=0x%02x\n", \ + ctx, pageId, offset, AI2C_DEV_BUS_ADDR(dev, pageId, offset), value) +#else +#define AI2C_WRITE_LOG(ctx, dev, pageId, offset, value) +#endif + +#define AI2C_DEV_BUS_READ8(dev, pageId, offset) \ + AI2C_BUS_READ8(AI2C_DEV_BUS_ADDR(dev, pageId, offset),\ + AI2C_DEV_PAGE_ENDIANNESS(pageId)) + +#define AI2C_DEV_BUS_READ16(dev, pageId, offset) \ + AI2C_BUS_READ16(AI2C_DEV_BUS_ADDR(dev, pageId, offset),\ + AI2C_DEV_PAGE_ENDIANNESS(pageId)) + +#define AI2C_DEV_BUS_READ32(dev, pageId, offset) \ + AI2C_BUS_READ32(AI2C_DEV_BUS_ADDR(dev, pageId, offset),\ + AI2C_DEV_PAGE_ENDIANNESS(pageId)) + +#define AI2C_DEV_BUS_WRITE8(dev, pageId, offset, value) \ + do { \ + AI2C_WRITE_LOG("edev_bus_write8", dev, pageId, offset, value); \ + AI2C_BUS_WRITE8( \ + AI2C_DEV_BUS_ADDR(dev, pageId, offset), value); \ + if (AI2C_DEV_PAGE_FLAGS(pageId) == AI2C_IO_SYNC) { \ + u32 ___val___; \ + ___val___ = AI2C_BUS_READ32(AI2C_DEV_BUS_ADDR(dev, \ + AI2C_DEV_PAGE_PCIE0_PEI, AI2C_PEI_CONFIG), \ + AI2C_DEV_ACCESS_LITTLE_ENDIAN); \ + } \ + } while (0); + +#define AI2C_DEV_BUS_WRITE16(dev, pageId, offset, value) \ + do { \ + AI2C_WRITE_LOG("edev_bus_write16", \ + dev, pageId, offset, value); \ + AI2C_BUS_WRITE16( \ + AI2C_DEV_BUS_ADDR(dev, pageId, offset), value); \ + if (AI2C_DEV_PAGE_FLAGS(pageId) == AI2C_IO_SYNC) { \ + u32 ___val___; \ + ___val___ = AI2C_BUS_READ32(AI2C_DEV_BUS_ADDR(dev, \ + AI2C_DEV_PAGE_PCIE0_PEI, AI2C_PEI_CONFIG), \ + AI2C_DEV_ACCESS_LITTLE_ENDIAN); \ + } \ + } while (0); + + #endif /* __AI2C_DEV_H__ */ diff --git a/drivers/i2c/busses/ai2c/ai2c_dev_clock.c b/drivers/i2c/busses/ai2c/ai2c_dev_clock.c index 8530231..a84774a 100644 --- a/drivers/i2c/busses/ai2c/ai2c_dev_clock.c +++ b/drivers/i2c/busses/ai2c/ai2c_dev_clock.c @@ -20,7 +20,7 @@ * MA 02111-1307 USA */ -#include "ai2c_plat_pvt.h" +#include "ai2c_plat.h" #include "ai2c_dev_clock_ext.h" /* @@ -488,7 +488,7 @@ int ai2c_dev_clock_mhz( (*clockMhz) = SYSCLK; -AI2C_RETURN_LABEL +ai2c_return: return ai2cStatus; } diff --git a/drivers/i2c/busses/ai2c/ai2c_dev_clock_ext.h b/drivers/i2c/busses/ai2c/ai2c_dev_clock_ext.h index 6e50aa5..d036eb2 100644 --- a/drivers/i2c/busses/ai2c/ai2c_dev_clock_ext.h +++ b/drivers/i2c/busses/ai2c/ai2c_dev_clock_ext.h @@ -27,7 +27,7 @@ #ifndef _AI2C_DEV_CLOCK_EXT_H_ #define _AI2C_DEV_CLOCK_EXT_H_ -#include "ai2c_dev_pvt.h" +#include "ai2c_dev.h" /************************************************************************** * Support Functions APIs * diff --git a/drivers/i2c/busses/ai2c/ai2c_mod.c b/drivers/i2c/busses/ai2c/ai2c_mod.c index de2167a..2882668 100644 --- a/drivers/i2c/busses/ai2c/ai2c_mod.c +++ b/drivers/i2c/busses/ai2c/ai2c_mod.c @@ -52,7 +52,7 @@ #define CONFIG_I2C */ -#include "ai2c_plat_pvt.h" +#include "ai2c_bus.h" #include "regs/ai2c_cfg_node_reg_defines.h" #include "regs/ai2c_cfg_node_regs.h" #include "asm/lsi/acp_ncr.h" @@ -102,7 +102,7 @@ static struct ai2c_priv *ai2cState; struct local_state { struct i2c_adapter adapter; - struct i2c_client *client; + struct i2c_client *client; }; static struct local_state *ai2cModState; @@ -114,7 +114,7 @@ static struct local_state *ai2cModState; static int ai2c_master_xfer( struct i2c_adapter *adap, struct i2c_msg msgs[], - int num) + int num) { u32 regionId = (u32) i2c_get_adapdata(adap); struct ai2c_priv *priv = ai2cState; @@ -135,8 +135,8 @@ static int ai2c_master_xfer( strcat(buf, "mstRead:"); #endif /* DATA_STREAM_DEBUG */ - err = priv->pages[i].api->rdFn(priv, regionId, - adap, &msgs[i], stop); + err = priv->busCfg->api->rdFn(priv, regionId, + adap, &msgs[i], stop); #ifdef DATA_STREAM_DEBUG for (j = 0; j < msgs[i].len; j++) { @@ -162,12 +162,12 @@ static int ai2c_master_xfer( printk(KERN_INFO "%s\n", buf); #endif /* DATA_STREAM_DEBUG */ - err = priv->pages[i].api->wrFn(priv, regionId, - adap, &msgs[i], stop); + err = priv->busCfg->api->wrFn(priv, regionId, + adap, &msgs[i], stop); } } -AI2C_RETURN_LABEL +ai2c_return: AI2C_LOG(AI2C_MSG_EXIT, ">>>Exit ai2c_master_xfer %d\n", err); return err; } @@ -189,82 +189,99 @@ static const struct i2c_algorithm ai2c_algorithm = { * Device Probe/Setup *****************************************************************************/ -#ifdef AI2C_PLATFORM_BUILD static int __devinit ai2c_probe(struct platform_device *pdev) -#else -static int __devinit ai2c_init(void) -#endif { - int ai2cStatus = AI2C_ST_SUCCESS; - struct ai2c_priv *priv = NULL; - int i; + int ai2cStatus = AI2C_ST_SUCCESS; + struct ai2c_priv *priv = NULL; + struct axxia_i2c_bus_platform_data *pdata; + u32 busNdx; + u32 rid; /* Initialization of externals, initial state */ AI2C_MSG_TRACE_LEVEL = (AI2C_MSG_INFO | AI2C_MSG_ERROR); ai2c_chip_ver = -1; - ai2cState = NULL; AI2C_LOG(AI2C_MSG_ENTRY, ">>>Enter ai2c_probe/init\n"); - AI2C_CALL(ai2c_memSetup(&priv)); - ai2cState = priv; + /* Global state across all of the same kind of platforms */ + if (ai2cState == NULL) { + AI2C_CALL(ai2c_stateSetup(&priv)); + ai2cState = priv; + } else { + priv = ai2cState; + } - /* Hook up bus driver(s) and devices to tree */ - ai2cModState = - ai2c_malloc(priv->numActiveBusses * sizeof(struct local_state)); - if (!ai2cModState) { - ai2cStatus = -ENOMEM; - goto exit_release; + /* State memory for each instance of the platform */ + if (ai2cModState == NULL) { + ai2cModState = + ai2c_malloc(priv->numActiveBusses * + sizeof(struct local_state)); + if (!ai2cModState) { + ai2cStatus = -ENOMEM; + goto exit_release; + } + memset(ai2cModState, 0, + priv->numActiveBusses * sizeof(struct local_state)); } - memset(ai2cModState, 0, - priv->numActiveBusses * sizeof(struct local_state)); - for (i = 0; i < priv->numActiveBusses; i++) { - u32 rid; + /* Associate this platform with the correct bus entry */ + AI2C_CALL(ai2c_memSetup(pdev, priv)); + pdata = (struct axxia_i2c_bus_platform_data *) pdev->dev.platform_data; + busNdx = pdata->index; - if (priv->pages[i].busName == NULL) - continue; + /* Hook up bus driver(s) and devices to tree */ + if ((busNdx > (priv->numActiveBusses-1)) || + (priv->pages[busNdx].busName == NULL)) { + printk(KERN_ERR + "Invalid description for adding I2C adapter [%d]\n", + busNdx); + goto exit_release; + } + if (ai2cModState[busNdx].adapter.algo != NULL) { + printk(KERN_ERR + "Duplicate I2C bus %d description found\n", busNdx); + goto exit_release; + } - rid = ai2c_page_to_region(priv, priv->pages[i].pageId); - i2c_set_adapdata(&ai2cModState[i].adapter, (void *)rid); + rid = ai2c_page_to_region(priv, priv->pages[busNdx].pageId); + i2c_set_adapdata(&ai2cModState[busNdx].adapter, (void *)rid); - snprintf(ai2cModState[i].adapter.name, - sizeof(ai2cModState[i].adapter.name), - "%s", ai2cState->pages[i].busName); - ai2cModState[i].adapter.algo = &ai2c_algorithm; - ai2cModState[i].adapter.owner = THIS_MODULE; - ai2cModState[i].adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - ai2cModState[i].adapter.retries = 3; + snprintf(ai2cModState[busNdx].adapter.name, + sizeof(ai2cModState[busNdx].adapter.name), + "%s", ai2cState->pages[busNdx].busName); + ai2cModState[busNdx].adapter.algo = &ai2c_algorithm; + ai2cModState[busNdx].adapter.owner = THIS_MODULE; + ai2cModState[busNdx].adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + ai2cModState[busNdx].adapter.retries = 3; /* Retry up to 3 times on lost * arbitration */ -#ifdef AI2C_PLATFORM_BUILD - ai2cModState[i].adapter.dev.parent = &pdev->dev; -#else - ai2cModState[i].adapter.dev.parent = NULL; -#endif - ai2cModState[i].adapter.dev.of_node = NULL; - - /* Add I2C adapter to I2C tree */ - ai2cStatus = i2c_add_adapter(&ai2cModState[i].adapter); - if (ai2cStatus) { - printk(KERN_ERR "Failed to add I2C adapter [%d]\n", i); - goto exit_release; - } - - /* Any detailed bus-specific initialization */ - ai2cStatus = priv->pages[i].api->initFn(priv, rid); - if (ai2cStatus) - goto exit_release; + ai2cModState[busNdx].adapter.dev.parent = &pdev->dev; + ai2cModState[busNdx].adapter.dev.of_node = NULL; + + /* Add I2C adapter to I2C tree */ + if (priv->pages[busNdx].bus_nr != (~0)) { + ai2cModState[busNdx].adapter.nr = priv->pages[busNdx].bus_nr; + ai2cStatus = + i2c_add_numbered_adapter(&ai2cModState[busNdx].adapter); + } else { + ai2cStatus = i2c_add_adapter(&ai2cModState[busNdx].adapter); + } + if (ai2cStatus) { + printk(KERN_ERR "Failed to add I2C adapter [%d]\n", busNdx); + goto exit_release; } -#ifdef AI2C_PLATFORM_BUILD + /* Any detailed bus-specific initialization */ + ai2cStatus = priv->busCfg->api->initFn(priv, rid); + if (ai2cStatus) + goto exit_release; + platform_set_drvdata(pdev, priv); -#endif AI2C_LOG(AI2C_MSG_EXIT, ">>>Exit ai2c_probe/init %d\n", 0); return 0; -AI2C_RETURN_LABEL +ai2c_return: if (ai2cStatus != -ENOMEM) ai2cStatus = -ENOSYS; @@ -275,11 +292,7 @@ exit_release: return ai2cStatus; } -#ifdef AI2C_PLATFORM_BUILD static int __devexit ai2c_remove(struct platform_device *dev) -#else -static void __devexit ai2c_exit(void) -#endif { int i; @@ -302,21 +315,15 @@ static void __devexit ai2c_exit(void) ai2c_memDestroy(ai2cState); } -#ifdef AI2C_PLATFORM_BUILD platform_set_drvdata(dev, NULL); -#endif AI2C_LOG(AI2C_MSG_EXIT, ">>>Exit ai2c_remove/exit %d\n", 0); -#ifdef AI2C_PLATFORM_BUILD return 0; -#endif } /* ------------------------------------------------------------------------- */ -#ifdef AI2C_PLATFORM_BUILD - #define ai2c_suspend NULL #define ai2c_resume NULL @@ -344,8 +351,6 @@ static void __exit ai2c_exit(void) platform_driver_unregister(&ai2c_driver); } -#endif /* AI2C_PLATFORM_BUILD */ - module_init(ai2c_init); module_exit(ai2c_exit); diff --git a/drivers/i2c/busses/ai2c/ai2c_plat.c b/drivers/i2c/busses/ai2c/ai2c_plat.c index c1f5837..b9c2bf4 100644 --- a/drivers/i2c/busses/ai2c/ai2c_plat.c +++ b/drivers/i2c/busses/ai2c/ai2c_plat.c @@ -50,7 +50,7 @@ #define AI2C_CHIP_VER=<verNum> */ -#include "ai2c_plat_pvt.h" +#include "ai2c_bus.h" #include "regs/ai2c_cfg_node_reg_defines.h" #include "regs/ai2c_cfg_node_regs.h" #include "asm/lsi/acp_ncr.h" @@ -64,199 +64,56 @@ * * IMPORTANT: ALL BUS GROUPINGS MUST BE MAINTAINED */ -/* Note: This table now contains the length of the block for wrap checking - * and such (when implemented). Note that each table is arranged in - * order of the "AI2C_DEV_PAGE_xxx" enumeration. - */ -static struct ai2c_dev_page ai2c_dev_page_34xx[AI2C_DEV_PAGE_END_MARKER] = { - /* Begin: I2C_0 */ - { - AI2C_DEV_PAGE_I2C_0, "AXXIA_I2C", 0x02000403000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_acp3400_cfg - }, - { - AI2C_DEV_PAGE_END_MARKER, NULL, 0x00000000000ULL, 0, 0, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_END_MARKER, NULL, 0x00000000000ULL, 0, 0, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_END_MARKER, NULL, 0x00000000000ULL, 0, 0, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_GPIO_0, NULL, 0x02000400000ULL, /*aka APB1/GPIO0*/ - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_RESET_CTRL, NULL, 0x02000003800ULL, - AI2C_DEV_SIZE_1KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, +static struct ai2c_dev_page_s ai2c_dev_page[AI2C_DEV_PAGE_END_MARKER] = { { - AI2C_DEV_PAGE_TIMER, NULL, 0x02000408000ULL, + AI2C_DEV_PAGE_I2C_0, "AXXIA_I2C0", 0, 0x00000000000ULL, AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL + AI2C_PAGE_FLAGS_I2CBUS, NULL, }, { - AI2C_DEV_PAGE_GPREG, NULL, 0x0200040C000ULL, + AI2C_DEV_PAGE_I2C_1, "AXXIA_I2C1", 0, 0x00000000000ULL, AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL + AI2C_PAGE_FLAGS_I2CBUS, NULL, }, - /* End: I2C_0 */ -}; - -static struct ai2c_dev_page ai2c_dev_page_25xx[AI2C_DEV_PAGE_END_MARKER] = { - /* Begin: I2C_0, I2C_1 */ { - AI2C_DEV_PAGE_I2C_0, "AXXIA_I2C0", 0x02000427000ULL, + AI2C_DEV_PAGE_I2C_2, "AXXIA_I2C2", 0, 0x00000000000ULL, AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_acp3400_cfg + AI2C_PAGE_FLAGS_I2CBUS, NULL, }, { - AI2C_DEV_PAGE_I2C_1, "AXXIA_I2C1", 0x02000428000ULL, + AI2C_DEV_PAGE_I2C_3, "AXXIA_SMB", 0, 0x00000000000ULL, AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_acp3400_cfg}, - { - AI2C_DEV_PAGE_END_MARKER, NULL, 0x00000000000ULL, 0, 0, - AI2C_PAGE_FLAGS_NONE, NULL + AI2C_PAGE_FLAGS_I2CBUS, NULL, }, { - AI2C_DEV_PAGE_END_MARKER, NULL, 0x00000000000ULL, 0, 0, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_GPIO_0, NULL, 0x02000420000ULL,/*aka APB1/GPIO0*/ - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL + AI2C_DEV_PAGE_END_MARKER, NULL, 0, 0x00000000000ULL, 0, 0, + AI2C_PAGE_FLAGS_NONE, NULL, }, { - AI2C_DEV_PAGE_RESET_CTRL, NULL, 0x02000005c00ULL, - AI2C_DEV_SIZE_1KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL + AI2C_DEV_PAGE_END_MARKER, NULL, 0, 0x00000000000ULL, 0, 0, + AI2C_PAGE_FLAGS_NONE, NULL, }, { - AI2C_DEV_PAGE_TIMER, NULL, 0x02000429000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL + AI2C_DEV_PAGE_END_MARKER, NULL, 0, 0x00000000000ULL, 0, 0, + AI2C_PAGE_FLAGS_NONE, NULL, }, { - AI2C_DEV_PAGE_GPREG, NULL, 0x02000400000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL + AI2C_DEV_PAGE_END_MARKER, NULL, 0, 0x00000000000ULL, 0, 0, + AI2C_PAGE_FLAGS_NONE, NULL, }, - /* End: I2C_0, I2C_1 */ }; -static struct ai2c_dev_page ai2c_dev_page_55xx[AI2C_DEV_PAGE_END_MARKER] = { - /* Begin: I2C_0, I2C_1, I2C_2, I2C_3 (SMB) */ - { - AI2C_DEV_PAGE_I2C_0, "AXXIA_I2C0", 0x02010084000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_axm5500_cfg - }, - { - AI2C_DEV_PAGE_I2C_1, "AXXIA_I2C1", 0x02010085000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_axm5500_cfg - }, - { - AI2C_DEV_PAGE_I2C_2, "AXXIA_I2C2", 0x02010086000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_axm5500_cfg - }, - { - AI2C_DEV_PAGE_I2C_3, "AXXIA_SMB", 0x02010087000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_axm5500_cfg - }, - { - AI2C_DEV_PAGE_GPIO_0, NULL, 0x02010092000ULL, /*aka APB1/GPIO1*/ - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_RESET_CTRL, NULL, 0x02022060000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_TIMER, NULL, 0x02010091000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_GPREG, NULL, 0x02010094000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - /* End: I2C_1 */ +static struct ai2c_dev_chip_entry_s ai2c_chip_id[] = { + { AI2C_CHIP_ACP55xx, "AXM55xx", 4, &ai2c_axm5500_cfg, }, + { AI2C_CHIP_ACP35xx, "AXM35xx", 3, &ai2c_axm5500_cfg, }, }; -static struct ai2c_dev_page ai2c_dev_page_35xx[AI2C_DEV_PAGE_END_MARKER] = { - /* Begin: I2C_0 */ - { - AI2C_DEV_PAGE_I2C_0, "AXXIA_I2C0", 0x02000426000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_axm5500_cfg - }, - { - AI2C_DEV_PAGE_I2C_1, "AXXIA_I2C1", 0x02000427000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_axm5500_cfg - }, - { - AI2C_DEV_PAGE_I2C_2, "AXXIA_I2C2", 0x02000428000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_I2CBUS, &ai2c_axm5500_cfg - }, - { - AI2C_DEV_PAGE_END_MARKER, NULL, 0x00000000000ULL, 0, 0, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_GPIO_0, NULL, 0x02000420000ULL, /*aka APB1/GPIO0*/ - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_RESET_CTRL, NULL, 0x02000003800ULL, - AI2C_DEV_SIZE_1KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_TIMER, NULL, 0x02000429000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - { - AI2C_DEV_PAGE_GPREG, NULL, 0x02000400000ULL, - AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN, - AI2C_PAGE_FLAGS_NONE, NULL - }, - /* End: I2C_0 */ -}; - -static struct ai2c_dev_page_entry ai2c_dev_page_index[] = { - { AI2C_CHIP_ACP34xx, "ACP34xx", FALSE, ai2c_dev_page_34xx, 2, }, - { AI2C_CHIP_ACP32xx, "ACP32xx", FALSE, ai2c_dev_page_34xx, 2, }, - { AI2C_CHIP_ACP25xx, "ACP25xx", FALSE, ai2c_dev_page_25xx, 2, }, - { AI2C_CHIP_ACP55xx, "AXM55xx", TRUE, ai2c_dev_page_55xx, 4, }, - { AI2C_CHIP_ACP35xx, "AXM35xx", TRUE, ai2c_dev_page_35xx, 3, }, -}; - -static int ai2c_dev_page_index_cnt = sizeof(ai2c_dev_page_index) / - sizeof(struct ai2c_dev_page_entry); +static u32 ai2c_chip_id_count = sizeof(ai2c_chip_id)/ + sizeof(struct ai2c_dev_chip_entry_s); /* Region Map - * Note: Must be same number of entries (and in same order) in the - * arrays of type 'ai2c_dev_page_entry_t' above. Note that - * each table is arranged in order of the "AI2C_DEV_PAGE_xxx" - * enumeration. + * Note: Must be same number of entries (and in same order) as + * the "AI2C_DEV_PAGE_xxx" enumeration. */ static struct ai2c_access_map ai2cDummyRegionMap[] = AI2C_DUMMY_REGION_MAP_INIT; @@ -385,7 +242,8 @@ int ai2c_dev_direct_read( for (i = 0; i < count; i++, busAddr += 4, offset += 4) { buffer[i] = AI2C_BUS_READ32(busAddr, endianness); AI2C_MSG(AI2C_MSG_IOR, - "direct_read: region=%x offset = %llx busAddr=%lx v=%x\n", + "direct_read: region=%x offset = %llx " + "busAddr=%lx v=%x\n", region->regionId, offset, busAddr, buffer[i]); } break; @@ -457,7 +315,8 @@ int ai2c_dev_direct_write( for (i = 0; i < count; i++, busAddr += 4, offset += 4) { AI2C_BUS_WRITE32(busAddr, buffer[i], endianness); AI2C_MSG(AI2C_MSG_IOW, - "direct_write: region=%x offset=%llx busAddr=%lx v=%x\n", + "direct_write: region=%x offset=%llx " + "busAddr=%lx v=%x\n", region->regionId, offset, busAddr, buffer[i]); } break; @@ -468,7 +327,8 @@ int ai2c_dev_direct_write( for (i = 0; i < count; i++, busAddr += 2) { AI2C_BUS_WRITE16(busAddr, buf16[i], endianness); AI2C_MSG(AI2C_MSG_IOW, - "direct_write: region=%x offset=%llx busAddr=%lx v=%x\n", + "direct_write: region=%x offset=%llx " + "busAddr=%lx v=%x\n", region->regionId, offset, busAddr, buf16[i]); } @@ -480,7 +340,8 @@ int ai2c_dev_direct_write( for (i = 0; i < count; i++, busAddr++) { AI2C_BUS_WRITE8(busAddr, buf8[i]); AI2C_MSG(AI2C_MSG_IOW, - "direct_write: region=%x offset=%llx busAddr=%lx v=%x\n", + "direct_write: region=%x offset=%llx " + "busAddr=%lx v=%x\n", region->regionId, offset, busAddr, buf8[i]); } @@ -622,9 +483,10 @@ int ai2c_dev_dcr_write( static int ai2c_getChipType(struct ai2c_priv *priv) { - int ai2cStatus = AI2C_ST_SUCCESS; + int ai2cStatus = AI2C_ST_SUCCESS; + u32 i; #ifdef CONFIG_LSI_UBOOTENV - ai2c_bool_t has_ECID = TRUE; + ai2c_bool_t has_ECID = TRUE; u32 rev_reg; u32 pt_reg; ai2c_cfg_node_node_cfg_r_t node_cfg; @@ -707,20 +569,32 @@ static int ai2c_getChipType(struct ai2c_priv *priv) } #endif - AI2C_LOG(AI2C_MSG_INFO, "AI2C %d.%d.%d %s\n", + for (i = 0; i < ai2c_chip_id_count; i++) { + if (ai2c_chip_id[i].chipType == priv->hw_rev.chipType) { + priv->busCfg = &ai2c_chip_id[i]; + priv->numActiveBusses = ai2c_chip_id[i].numActiveBusses; + } + } + if (priv->busCfg == NULL) { + ai2cStatus = -ENXIO; + goto ai2c_return; + } + + AI2C_LOG(AI2C_MSG_INFO, "%s %d.%d.%d %s\n", + priv->busCfg->chipName, priv->hw_rev.chipType, priv->hw_rev.chipVersion, priv->hw_rev.packageType, (priv->hw_rev.isFpga) ? "FPGA" : "ASIC"); -AI2C_RETURN_LABEL +ai2c_return: return ai2cStatus; } -int ai2c_memSetup(struct ai2c_priv **outPriv) +int ai2c_stateSetup( + struct ai2c_priv **outPriv) { - int ai2cStatus = AI2C_ST_SUCCESS; + int ai2cStatus = AI2C_ST_SUCCESS; struct ai2c_priv *priv = NULL; - int i; /* Now for the private memory for this module. */ priv = ai2c_malloc(sizeof(struct ai2c_priv)); @@ -737,71 +611,115 @@ int ai2c_memSetup(struct ai2c_priv **outPriv) if (ai2cStatus != AI2C_ST_SUCCESS) goto ai2c_return; - /* What is the page mapping scheme for this platform? */ - for (i = 0; i < ai2c_dev_page_index_cnt; i++) { +ai2c_return: + if (ai2cStatus != AI2C_ST_SUCCESS) + (*outPriv) = NULL; + else + (*outPriv) = priv; + + return ai2cStatus; +} - if (ai2c_dev_page_index[i].chipType == priv->hw_rev.chipType) { - priv->pages = ai2c_dev_page_index[i].pages; - priv->busCfg = &ai2c_dev_page_index[i]; - priv->numActiveBusses = - ai2c_dev_page_index[i].numActiveBusses; - } - } - if (priv->pages == NULL) { +int ai2c_memSetup( + struct platform_device *pdev, + struct ai2c_priv *priv) +{ + int ai2cStatus = AI2C_ST_SUCCESS; + struct axxia_i2c_bus_platform_data *pdata; + u32 busNdx; + int i; + + /* Where is the current I2C device found on this platform? */ + pdata = (struct axxia_i2c_bus_platform_data *) pdev->dev.platform_data; + if (pdata == NULL) { AI2C_LOG(AI2C_MSG_ERROR, - "Can't select memory cfg for chip ver %d\n", - priv->hw_rev.chipType); + "Can't find platform-specific data!\n"); + ai2cStatus = -ENXIO; + goto ai2c_return; + } + busNdx = pdata->index; + + priv->pages = ai2c_dev_page; + + if (busNdx > (priv->numActiveBusses-1)) { + AI2C_LOG(AI2C_MSG_ERROR, "Invalid I2C bus index (%d)\n", + busNdx); ai2cStatus = -ENXIO; goto ai2c_return; } + priv->pages[busNdx].busName = &pdata->name[0]; + priv->pages[busNdx].bus_nr = pdata->bus_nr; + priv->pages[busNdx].busAddr = pdata->dev_space.start; + priv->pages[busNdx].size = + pdata->dev_space.end - pdata->dev_space.start + 1; + priv->pages[busNdx].pdata = pdata; + + AI2C_LOG(AI2C_MSG_DEBUG, + "[%d] ba=0x%010llx (%llx, %llx) sz=0x%x\n", + busNdx, + priv->pages[busNdx].busAddr, + pdata->dev_space.start, pdata->dev_space.end, + priv->pages[busNdx].size); + + /* + * Interrupt for this bus is in priv->pdata[i].int_space.start + */ + + /* * Program Address Map driver tables - * Set up the base offsets for SRIO RAB and GRIO access via paged - * PLB access. */ - priv->pageAddr = - ai2c_malloc(AI2C_DEV_PAGE_END_MARKER * sizeof(u32)); if (priv->pageAddr == NULL) { - AI2C_LOG(AI2C_MSG_ERROR, - "Could not allocate AI2C pageAddr memory!\n"); - ai2cStatus = -ENOMEM; - goto ai2c_return; + priv->pageAddr = + ai2c_malloc(AI2C_DEV_PAGE_END_MARKER * sizeof(u32)); + if (priv->pageAddr == NULL) { + AI2C_LOG(AI2C_MSG_ERROR, + "Could not allocate AI2C pageAddr memory!\n"); + ai2cStatus = -ENOMEM; + goto ai2c_return; + } + memset(priv->pageAddr, 0, + AI2C_DEV_PAGE_END_MARKER * sizeof(u32)); } - memset(priv->pageAddr, 0, - AI2C_DEV_PAGE_END_MARKER * sizeof(u32)); + for (i = 0; i < AI2C_DEV_PAGE_END_MARKER; i++) { - if (priv->pages[i].pageId != AI2C_DEV_PAGE_END_MARKER) { - priv->pageAddr[i] = - (u32) ioremap(priv->pages[i].busAddr, - priv->pages[i].size); - if (priv->pageAddr[i] == 0) { - AI2C_LOG(AI2C_MSG_ERROR, - "Could not ioremap AI2C pageAddr memory %d!\n", - i); - ai2cStatus = -ENOMEM; - goto ai2c_return; - - } else { - - AI2C_LOG(AI2C_MSG_DEBUG, - "Map page %d (%08x) / %llx for %x => %x\n", - priv->pages[i].pageId, - ai2c_page_to_region(priv, - priv->pages[i].pageId), - (unsigned long long) - priv->pages[i].busAddr, - priv->pages[i].size, - priv->pageAddr[i]); - } + if (priv->pageAddr[i] || + (priv->pages[i].busAddr == 0) || + (priv->pages[i].size == 0) || + (priv->pages[i].pageId == AI2C_DEV_PAGE_END_MARKER)) + continue; + + priv->pageAddr[i] = + (u32) ioremap(priv->pages[i].busAddr, + priv->pages[i].size); + if (priv->pageAddr[i] == 0) { + AI2C_LOG(AI2C_MSG_ERROR, + "Could not ioremap AI2C pageAddr memory %d!\n", + i); + AI2C_LOG(AI2C_MSG_DEBUG, + "ba=0x%010llx sz=0x%x\n", + priv->pages[i].busAddr, + priv->pages[i].size); + ai2cStatus = -ENOMEM; + goto ai2c_return; + } else { + AI2C_LOG(AI2C_MSG_DEBUG, + "Map page %d (%08x) / %llx for %x => %x\n", + priv->pages[i].pageId, + ai2c_page_to_region(priv, + priv->pages[i].pageId), + (unsigned long long) priv->pages[i].busAddr, + priv->pages[i].size, + priv->pageAddr[i]); } } AI2C_SPINLOCK_INIT(&priv->regLock); AI2C_SPINLOCK_INIT(&priv->ioLock); -AI2C_RETURN_LABEL +ai2c_return: if (ai2cStatus != AI2C_ST_SUCCESS) { if (priv) { @@ -809,14 +727,13 @@ AI2C_RETURN_LABEL for (i = 0; i < AI2C_DEV_PAGE_END_MARKER; i++) if (priv->pageAddr[i] != 0) iounmap( - (void __iomem *)priv->pageAddr[i]); + (void __iomem *) + priv->pageAddr[i]); ai2c_free(priv->pageAddr); } ai2c_free(priv); } - (*outPriv) = NULL; - } else - (*outPriv) = priv; + } return ai2cStatus; } @@ -824,13 +741,13 @@ AI2C_RETURN_LABEL int ai2c_memDestroy(struct ai2c_priv *inPriv) { int ai2cStatus = AI2C_ST_SUCCESS; - int i; + int i; if (inPriv) { if (inPriv->pageAddr) { for (i = 0; i < AI2C_DEV_PAGE_END_MARKER; i++) if (inPriv->pageAddr[i] != 0) - iounmap((void __iomem *)inPriv->pageAddr[i]); + iounmap((void *)inPriv->pageAddr[i]); ai2c_free(inPriv->pageAddr); } diff --git a/drivers/i2c/busses/ai2c/ai2c_plat.h b/drivers/i2c/busses/ai2c/ai2c_plat.h index faad41b..54e6c5b 100644 --- a/drivers/i2c/busses/ai2c/ai2c_plat.h +++ b/drivers/i2c/busses/ai2c/ai2c_plat.h @@ -24,10 +24,12 @@ #define _AI2C_LINUX_H_ #include <linux/i2c.h> -#include <asm/io.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/i2c-axxia.h> #include "ai2c_sal.h" -#include "ai2c_dev_pvt.h" +#include "ai2c_dev.h" /************************************************************************** * Constants * @@ -170,22 +172,22 @@ enum { #define AI2C_PAGE_FLAGS_NONE (0x00000000) #define AI2C_PAGE_FLAGS_I2CBUS (0x00000001) -struct ai2c_dev_page { +struct ai2c_dev_page_s { int pageId; char *busName; + u32 bus_nr; u64 busAddr; /* 38-bit PCI address */ u32 size; u32 endianness; u32 flags; - struct ai2c_i2c_access *api; + struct axxia_i2c_bus_platform_data *pdata; }; -struct ai2c_dev_page_entry { +struct ai2c_dev_chip_entry_s { u32 chipType; char *chipName; - bool supportDsFns; - struct ai2c_dev_page *pages; u32 numActiveBusses; + struct ai2c_i2c_access *api; }; @@ -200,12 +202,11 @@ struct ai2c_priv { struct ai2c_rev_id hw_rev; /* Static configuration describing selected ACP I2C bus region */ - struct ai2c_dev_page_entry *busCfg; - /* Per module default config */ - u32 numActiveBusses; + struct ai2c_dev_chip_entry_s *busCfg; /* Memory Mapping/Management constructs */ - struct ai2c_dev_page *pages; + u32 numActiveBusses; + struct ai2c_dev_page_s *pages; /* Per module memory pages */ /* Memory indexing support to reach selected ACP regions */ @@ -279,5 +280,57 @@ int ai2c_dev_dcr_write( u32 cmdType, u32 xferWidth); +/***************************************************************************** +* Externally Visible Function Prototypes * +*****************************************************************************/ + +/*! @fn u32 ai2c_page_to_region(struct ai2c_priv *priv, + * u32 pageId); + * @brief Map a memory page handle to a regionId handle. + @param[in] inPriv Created device state structure + @param[in] inPageId Original page id to be mapped + @Returns mapped value + */ +extern u32 ai2c_page_to_region(struct ai2c_priv *priv, u32 pageId); + +/*! @fn u32 *ai2c_region_lookup(struct ai2c_priv *priv, + * u32 regionId); + * @brief Map a memory region handle to a region description structure. + @param[in] inPriv Created device state structure + @param[in] inRegionId Original region id to be mapped + @Returns mapped value + */ +extern struct ai2c_region_io *ai2c_region_lookup( + struct ai2c_priv *priv, + u32 regionId); + +/*! @fn int ai2c_stateSetup(struct ai2c_priv **outPriv); + @brief This is a one time initialization for the state linking all + of the I2C protocol layers to be called by the device + initialization step. + @param[out] outPriv Created device state structure + @Returns success/failure status of the operation +*/ +extern int ai2c_stateSetup(struct ai2c_priv **outPriv); + +/*! @fn int ai2c_memSetup(struct platform_device *pdev, + struct ai2c_priv *priv); + @brief This is a per-device to-be-mapped setup for the I2C protocol + layers to be called by the device initialization step. + @param[in] inPDev Source platform device data strucure + @param[in] inPriv Created device state structure + @Returns success/failure status of the operation +*/ +extern int ai2c_memSetup(struct platform_device *pdev, + struct ai2c_priv *priv); + +/*! @fn int ai2c_memDestroy(struct ai2c_priv *inPriv); + @brief This function will release resources acquired for the specified + I2C device driver. + @param[in] inPriv Created device state structure + @Returns success/failure status of the operation +*/ +extern int ai2c_memDestroy(struct ai2c_priv *inPriv); + #endif /* _AI2C_PLAT_H_ */ diff --git a/drivers/i2c/busses/ai2c/ai2c_sal.c b/drivers/i2c/busses/ai2c/ai2c_sal.c index 9b1ea7a..ceda0fa 100644 --- a/drivers/i2c/busses/ai2c/ai2c_sal.c +++ b/drivers/i2c/busses/ai2c/ai2c_sal.c @@ -37,10 +37,11 @@ void *ai2c_malloc(size_t size) if (size <= 0) { #ifdef AI2C_DEBUG AI2C_MSG(AI2C_MSG_DEBUG, - "WARNING: ai2c_malloc(%d) passed a zero or less size.\n", + "WARNING: ai2c_malloc(%d) passed a zero or " + "less size.\n", size); #endif - return NULL; + return 0; } p = __ai2c_malloc(size); @@ -57,10 +58,11 @@ void *ai2c_calloc(size_t no, size_t size) if (size <= 0 || no <= 0) { #ifdef AI2C_DEBUG AI2C_MSG(AI2C_MSG_DEBUG, - "WARNING: ai2c_calloc(no=%d, size=%d) passed a zero or less size.\n", + "WARNING: ai2c_calloc(no=%d, size=%d) " + "passed a zero or less size.\n", no, size); #endif - return NULL; + return 0; } p = __ai2c_calloc(no, size); @@ -76,10 +78,11 @@ void *ai2c_realloc(void *ptr, size_t size) if (size <= 0) { #ifdef AI2C_DEBUG AI2C_MSG(AI2C_MSG_DEBUG, - "WARNING: ai2c_realloc(%d) passed a zero or less size.\n", + "WARNING: ai2c_realloc(%d) passed a zero or " + "less size.\n", size); #endif - return NULL; + return 0; } ptr = __ai2c_realloc(ptr, size); diff --git a/drivers/i2c/busses/ai2c/ai2c_sal.h b/drivers/i2c/busses/ai2c/ai2c_sal.h index 4a39867..bbfd2f9 100644 --- a/drivers/i2c/busses/ai2c/ai2c_sal.h +++ b/drivers/i2c/busses/ai2c/ai2c_sal.h @@ -27,11 +27,352 @@ #ifndef __AI2C_SAL_H__ #define __AI2C_SAL_H__ -#include "ai2c_sal_types.h" +#include <generated/autoconf.h> + +#ifdef __KERNEL__ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/cdev.h> +#include <linux/of_platform.h> +#include <linux/init.h> +#include <linux/poll.h> +#include <linux/kthread.h> +#include <linux/sched.h> + +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/wait.h> +#include <asm/pgtable.h> + +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/spinlock.h> +#include <linux/signal.h> + +#include <linux/i2c.h> +#include <linux/i2c-dev.h> + +#include <linux/version.h> + +#include <linux/time.h> +#include <linux/fcntl.h> +#include <linux/unistd.h> +#include <linux/errno.h> +#include <linux/mman.h> + +#include <asm/byteorder.h> + +#else + +#include <stdio.h> +#include <stdlib.h> + +#endif + +#include "ai2c_types.h" #include "ai2c_dev.h" -#include "ai2c_sal_linux.h" -/* should not be in sal */ + +/************************************************************************** +* Some Constants +**************************************************************************/ + +#ifdef __BIG_ENDIAN +#undef AI2C_BIG_ENDIAN +#define AI2C_BIG_ENDIAN 9999 +#undef AI2C_LITTLE_ENDIAN +#endif + +#ifdef __LITTLE_ENDIAN +#undef AI2C_BIG_ENDIAN +#undef AI2C_LITTLE_ENDIAN +#define AI2C_LITTLE_ENDIAN 9998 +#endif + +/************************************************************************** +* Macros +**************************************************************************/ + +/* +* AI2C_MSG +* +* Print a message to the system console. +*/ +#ifdef __KERNEL__ + +#define AI2C_MSG(type, fmt, args...) \ + do { \ + if ((type) & AI2C_MSG_TRACE_LEVEL) { \ + if ((type) == AI2C_MSG_ERROR) \ + printk(KERN_ERR AI2C_MOD_NAME ": ERROR: "); \ + else \ + printk(KERN_WARNING AI2C_MOD_NAME ": "); \ + printk(fmt, ## args); \ + } \ + } while (0) + +#else + +#define AI2C_MSG(type, fmt, args...) \ + do { \ + if ((type) & AI2C_MSG_TRACE_LEVEL) { \ + if ((type) == AI2C_MSG_ERROR) \ + printf("[Error] " AI2C_MOD_NAME ": ERROR: "); \ + else \ + printf("[Warning] " AI2C_MOD_NAME ": "); \ + printf(fmt, ## args); \ + } \ + } while (0) + +#endif + + /* + * AI2C_LOG + * + * Print a message to the system log device and/or console. This + * interface is callable from interrupt level. + */ +#define AI2C_LOG \ + AI2C_MSG + +#ifndef AI2C_MSG_TRACE_LEVEL +#define AI2C_MSG_TRACE_LEVEL ai2c_trace_level +#endif + +extern int AI2C_MSG_TRACE_LEVEL; + + +/* +* Endian-ness Conversion +*/ + +#define AI2C_SWAP16m(n) \ + ((((u16)(n) >> 8) & 0x00ff) | \ + (((u16)(n) << 8) & 0xff00)) + +#define AI2C_SWAP32m(n) \ + ((((u32)(n) >> 24) & 0x000000ff) | \ + (((u32)(n) >> 8) & 0x0000ff00) | \ + (((u32)(n) << 8) & 0x00ff0000) | \ + (((u32)(n) << 24) & 0xff000000)) + +#define SWAP16(x) \ + { { \ + u16 val = x; \ + AI2C_SWAP16m(val); \ + } } + +#define SWAP32(x) \ + { { \ + u32 val = x; \ + AI2C_SWAP32m(val); \ + } } + + +/* +* Endian-ness I/O +*/ + +#ifdef CONFIG_ARM + +#define in_be8(x) (*x) +#define in_be16(x) AI2C_SWAP16m(*x) +#define in_be32(x) AI2C_SWAP32m(*x) + +#define in_le8(x) (*x) +#define in_le16(x) (*x) +#define in_le32(x) (*x) + +#define out_be8(a, v) (*a) = (v) +#define out_be16(a, v) (*a) = AI2C_SWAP16m(v) +#define out_be32(a, v) (*a) = AI2C_SWAP32m(v) + +#define out_le8(a, v) (*a) = (v) +#define out_le16(a, v) (*a) = (v) +#define out_le32(a, v) (*a) = (v) + +#endif /* CONFIG_ARM */ + + +#define AI2C_EDEV_BUS_ENFORCE_ORDERING() + +#define AI2C_BUS_READ8(addr) \ + readb((u8 *) (addr)) + +#define AI2C_BUS_READ16_ENDIAN(endian, addr) \ + in_##endian##16((u16 __iomem *) (addr)) + + +#define AI2C_BUS_READ16_LE(addr) AI2C_BUS_READ16_ENDIAN(le, addr) + +#define AI2C_BUS_READ16_BE(addr) AI2C_BUS_READ16_ENDIAN(be, addr) + +#define AI2C_BUS_READ16(addr, endian) \ + (endian == AI2C_DEV_ACCESS_BIG_ENDIAN) ? \ + AI2C_BUS_READ16_BE(addr) : AI2C_BUS_READ16_LE(addr) + +#define AI2C_BUS_READ32_ENDIAN(endian, addr) \ + in_##endian##32((u32 __iomem *) (addr)) + + +#define AI2C_BUS_READ32_LE(addr) AI2C_BUS_READ32_ENDIAN(le, addr) + +#define AI2C_BUS_READ32_BE(addr) AI2C_BUS_READ32_ENDIAN(be, addr) + +#define AI2C_BUS_READ32(addr, endian) \ + (endian == AI2C_DEV_ACCESS_BIG_ENDIAN) ? \ + AI2C_BUS_READ32_BE(addr) : AI2C_BUS_READ32_LE(addr) + + +#define AI2C_BUS_WRITE8(addr, data) \ + writeb((data), (u8 *) (addr)) + +#define AI2C_BUS_WRITE16_ENDIAN(endian, addr, data) \ + do { \ + u16 *__a__ = (u16 *) addr; \ + u16 __d__ = data; \ + out_##endian##16((u16 __iomem *) __a__, __d__); \ + AI2C_EDEV_BUS_ENFORCE_ORDERING(); \ + } while (0); + +#define AI2C_BUS_WRITE16_LE(addr, data) \ + AI2C_BUS_WRITE16_ENDIAN(le, addr, data) + +#define AI2C_BUS_WRITE16_BE(addr, data) \ + AI2C_BUS_WRITE16_ENDIAN(be, addr, data) + +#define AI2C_BUS_WRITE16(addr, data, endian) \ + do { \ + if (endian == AI2C_DEV_ACCESS_BIG_ENDIAN) { \ + AI2C_BUS_WRITE16_BE(addr, data); \ + } else { \ + AI2C_BUS_WRITE16_LE(addr, data); \ + } \ + } while (0); + +#define AI2C_BUS_WRITE32_ENDIAN(endian, addr, data) \ + do { \ + u32 *__a__ = (u32 *) addr; \ + u32 __d__ = data; \ + out_##endian##32((u32 __iomem *) __a__, __d__); \ + AI2C_EDEV_BUS_ENFORCE_ORDERING(); \ + } while (0); + +#define AI2C_BUS_WRITE32_LE(addr, data) \ + AI2C_BUS_WRITE32_ENDIAN(le, addr, data) + +#define AI2C_BUS_WRITE32_BE(addr, data) \ + AI2C_BUS_WRITE32_ENDIAN(be, addr, data) + +#define AI2C_BUS_WRITE32(addr, data, endian) \ + do { \ + if (endian == AI2C_DEV_ACCESS_BIG_ENDIAN) { \ + AI2C_BUS_WRITE32_BE(addr, data); \ + } else { \ + AI2C_BUS_WRITE32_LE(addr, data); \ + } \ + } while (0); + + /* + * Spinlock mutex stuff + */ + +#define AI2C_SPINLOCK_INIT(pSpinlock) \ + spin_lock_init(pSpinlock) + +#define AI2C_SPINLOCK_LOCK(pSpinlock) \ + spin_lock(pSpinlock) + +#define AI2C_SPINLOCK_TRYLOCK(pSpinlock) \ + spin_trylock(pSpinlock) + +#define AI2C_SPINLOCK_UNLOCK(pSpinlock) \ + spin_unlock(pSpinlock) + +#define AI2C_SPINLOCK_INTERRUPT_DISABLE(pSem, flags) \ + spin_lock_irqsave(pSem, flags) + +#define AI2C_SPINLOCK_INTERRUPT_ENABLE(pSem, flags) \ + spin_unlock_irqrestore(pSem, flags) + +#define AI2C_SPINLOCK_SW_INTERRUPT_DISABLE(pSem, flags) \ + spin_lock_bh(pSem) + +#define AI2C_SPINLOCK_SW_INTERRUPT_ENABLE(pSem, flags) \ + spin_unlock_bh(pSem) + + +#ifdef __KERNEL__ + /* + * Kernel memory allocation + */ + +#define __ai2c_malloc(size) kmalloc(size, GFP_KERNEL) +#define __ai2c_free(ptr) kfree(ptr) +#define __ai2c_realloc(ptr, size) (NULL) +#define __ai2c_calloc(no, size) kcalloc(no, size, GFP_KERNEL) + +#else + + /* + * User space memory allocation + */ + +#define __ai2c_malloc(size) malloc(size) +#define __ai2c_free(ptr) free(ptr) +#define __ai2c_realloc(ptr, size) (NULL) +#define __ai2c_calloc(no, size) calloc(no, size) + +#endif + + + /* + * Miscellaneous externs not provided by other headers reliably + */ + +extern int snprintf(char *s, size_t n, const char *format, ...); + +struct ai2c_rev_id { + +#ifdef NCP_BIG_ENDIAN + unsigned isAsic:1; + unsigned isFpga:1; + unsigned isSim:1; + unsigned:2; + unsigned secDisable:1; + unsigned sppDisable:1; + unsigned cpuDisable:4; + unsigned ecidChipType:5; + unsigned:1; + unsigned packageType:4; + unsigned chipVersion:6; + unsigned chipTyp:5; +#else + unsigned chipType:5; + unsigned chipVersion:6; + unsigned packageType:4; + unsigned:1; + unsigned ecidChipType:5; + unsigned cpuDisable:4; + unsigned sppDisable:1; + unsigned secDisable:1; + unsigned:2; + unsigned isSim:1; + unsigned isFpga:1; + unsigned isAsic:1; +#endif +}; + + +/************************************************************************** +* More Macros +**************************************************************************/ + +/* Should this be in sal? */ #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif @@ -40,6 +381,10 @@ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif +/************************************************************************** +* Function Prototypes +**************************************************************************/ + extern void *ai2c_malloc(size_t size); extern void *ai2c_realloc(void *ptr, size_t size); extern void *ai2c_calloc(size_t no, size_t size); diff --git a/drivers/i2c/busses/ai2c/ai2c_types.h b/drivers/i2c/busses/ai2c/ai2c_types.h index c748823..a0c04da 100644 --- a/drivers/i2c/busses/ai2c/ai2c_types.h +++ b/drivers/i2c/busses/ai2c/ai2c_types.h @@ -23,6 +23,48 @@ #ifndef AI2C_TYPES_H #define AI2C_TYPES_H +#ifdef __KERNEL__ + +#include <linux/types.h> + +#else + +#define u64 unsigned long long +#define u32 unsigned long +#define s32 signed long +#define size_t int + +#define AI2C_U32 unsigned long + +#define ai2c_uint8_t unsigned char +#define ai2c_uint16_t unsigned short +#define ai2c_uint32_t unsigned long +#define ai2c_uint64_t unsigned long long +#define ai2c_int8_t signed char +#define ai2c_int16_t signed short +#define ai2c_int32_t signed long +#define ai2c_int64_t signed long long +#define ai2c_bool_t unsigned short +#define ai2c_size_t signed long + +#endif + +/************************************************************************** +* Constants, #Defines, etc. +**************************************************************************/ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + /************************************************************************** * ACP chip types * @@ -36,9 +78,9 @@ #define AI2C_CHIP_ACP34xx 1 #define AI2C_CHIP_ACP32xx 2 #define AI2C_CHIP_ACP25xx 6 -#define AI2C_CHIP_ACP25xx_V2 7 +#define AI2C_CHIP_ACP25xx_V2 7 -#define AI2C_CHIP_X3X7_HYBRID 7 /* TEMP HACK */ +#define AI2C_CHIP_X3X7_HYBRID 7 /* TEMP HACK */ #define AI2C_CHIP_ACP55xx 9 /* AXM55xx, aka X7 */ #define AI2C_CHIP_ACP35xx 16 /* AXM35xx, aka X3 */ @@ -73,12 +115,4 @@ } while (0); -/* - * A general purpose way to eliminate warnings due the the label - * not being referenced. - */ -#define AI2C_RETURN_LABEL \ - goto ai2c_return; \ -ai2c_return: - #endif /* AI2C_TYPES_H */ -- 1.8.3 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto