[linux-yocto] [PATCH 4/5] drivers/i2c: Collapse AI2C driver implementation mods
Paul Butler
butler.paul at gmail.com
Mon Oct 28 17:15:52 PDT 2013
Signed-off-by: Paul Butler <paul.butler at windriver.com>
---
drivers/i2c/busses/ai2c/Makefile | 5 +-
drivers/i2c/busses/ai2c/ai2c_bus.h | 881 ++++++++++++++++++-
drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c | 5 +-
drivers/i2c/busses/ai2c/ai2c_mod.c | 1267 +++++++++++++++++++++++++++-
4 files changed, 2137 insertions(+), 21 deletions(-)
diff --git a/drivers/i2c/busses/ai2c/Makefile b/drivers/i2c/busses/ai2c/Makefile
index e618016..276a79c 100644
--- a/drivers/i2c/busses/ai2c/Makefile
+++ b/drivers/i2c/busses/ai2c/Makefile
@@ -7,10 +7,7 @@ MODULE := lsi_acp_i2c
obj-$(CONFIG_I2C_AXXIA) += $(MODULE).o
$(MODULE)-objs := ai2c_mod.o \
- ai2c_plat.o \
- ai2c_bus_axm5500.o \
- ai2c_dev_clock.o \
- ai2c_sal.o
+ ai2c_bus_axm5500.o
ccflags-$(CONFIG_I2C_AXXIA) := -DAI2C_MOD_NAME=\"ai2c\" \
-DAI2C_MSG_TRACE_LEVEL=ai2c_trace_level \
diff --git a/drivers/i2c/busses/ai2c/ai2c_bus.h b/drivers/i2c/busses/ai2c/ai2c_bus.h
index 8861ae5..9702ad9 100644
--- a/drivers/i2c/busses/ai2c/ai2c_bus.h
+++ b/drivers/i2c/busses/ai2c/ai2c_bus.h
@@ -28,12 +28,870 @@
#ifndef AI2C_BUS_H
#define AI2C_BUS_H
-#include "ai2c_types.h"
-#include "regs/ai2c_i2c_regs.h"
-#include "ai2c_plat.h"
+#include <generated/autoconf.h>
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/cdev.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.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/i2c-axxia.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 <linux/types.h>
+
+#include <asm/byteorder.h>
+
+/**************************************************************************
+* Basic Type Definitions, Constants, #Defines, etc.
+**************************************************************************/
+
+ /**************************************************************************
+ * Constants, #Defines, etc.
+ **************************************************************************/
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+ /**************************************************************************
+ * ACP chip types
+ *
+ * These are the base silicon chip types. Each chip may have one
+ * or more variants, but for the purpose of the chipType comparison
+ * we only care about the base silicon version. For any variant the
+ * driver will set the chipType in virtual register 0x301.0.0 to
+ * one of the following.
+ **************************************************************************/
+
+#define AI2C_CHIP_ACP34xx 1
+#define AI2C_CHIP_ACP32xx 2
+#define AI2C_CHIP_ACP25xx 6
+#define AI2C_CHIP_ACP25xx_V2 7
+
+#define AI2C_CHIP_X3X7_HYBRID 7 /* TEMP HACK */
+
+#define AI2C_CHIP_ACP55xx 9 /* AXM55xx, aka X7 */
+#define AI2C_CHIP_ACP35xx 16 /* AXM35xx, aka X3 */
+
+
+ /**************************************************************************
+ * API Configuration Status Codes, Typedefs, etc.
+ **************************************************************************/
+
+#define AI2C_ST_SUCCESS (0)
+
+
+ /**************************************************************************
+ * Function Call Support Typedefs, Constants, Macros, etc.
+ **************************************************************************/
+
+#ifdef AI2C_ERR_DEBUG
+#define AI2C_PRINT_LINE_FILE \
+ AI2C_MSG(AI2C_MSG_INFO, "%s : %s, line = %d\n", \
+ ai2c_status_get(ai2cStatus), __FILE__, __LINE__)
+#else
+#define AI2C_PRINT_LINE_FILE
+#endif /* AI2C_ERR_DEBUG */
+
+#define AI2C_CALL(ai2cFunc) \
+ do { \
+ ai2cStatus = (ai2cFunc); \
+ if (ai2cStatus != AI2C_ST_SUCCESS) { \
+ AI2C_PRINT_LINE_FILE; \
+ goto ai2c_return; \
+ } \
+ } while (0);
+
+
+/* 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 --- */
+#define AI2C_DEV_MAX_VERSION_LENGTH (41)
+
+
+/* --- AI2C Trace Level Definitions --- */
+#define AI2C_MSG_NONE (0x00000000)
+#define AI2C_MSG_INFO (0x00000001)
+#define AI2C_MSG_ERROR (0x00000002)
+#define AI2C_MSG_ENTRY (0x00000004)
+#define AI2C_MSG_EXIT (0x00000008)
+#define AI2C_MSG_CALL (AI2C_MSG_ENTRY | AI2C_MSG_EXIT)
+#define AI2C_MSG_IOR (0x00000010)
+#define AI2C_MSG_IOW (0x00000020)
+#define AI2C_MSG_IORW (AI2C_MSG_IOR | AI2C_MSG_IOW)
+#define AI2C_MSG_MEM (0x00000040)
+#define AI2C_MSG_MDIO (0x00000080)
+#define AI2C_MSG_DEBUG_IO (0x20000000)
+#define AI2C_MSG_DEBUG (0x40000000)
+#define AI2C_MSG_INTR (0x80000000)
+#define AI2C_MSG_ALL (0xFFFFFFFF)
+
+
+/* --- Device Target Access Map --- */
+struct ai2c_access_map {
+ u64 begin;
+ u64 end;
+ s32 word_size_in_bytes;
+ s32 access_size_in_words;
+};
+
+
+#define AI2C_DUMMY_REGION_MAP_INIT \
+ { \
+ { 0x00000000, 0x03000000, AI2C_DEV_ACCESS_RW }, \
+ { 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
+ */
+#define AI2C_NCA_CMD_CRBR (0x00000004)
+#define AI2C_NCA_CMD_CRBW (0x00000005)
+
+#define AI2C_EDEV_BUS_READ32(dev, p, o, var) \
+ ai2c_region_io_map[p].readFn(dev, &ai2c_region_io_map[p], \
+ o, (var), 1, 0, AI2C_NCA_CMD_CRBR, 4)
+
+#define AI2C_EDEV_BUS_BLOCK_READ32(dev, p, o, cnt, var) \
+ ai2c_region_io_map[p].readFn(dev, &ai2c_region_io_map[p], \
+ o, (var), cnt, 0, AI2C_NCA_CMD_CRBR, 4)
+
+#define AI2C_EDEV_BUS_WRITE32(dev, p, o, var) \
+ ai2c_region_io_map[p].writeFn(dev, &ai2c_region_io_map[p], \
+ o, (var), 1, 0, AI2C_NCA_CMD_CRBW, 4)
+
+#define AI2C_EDEV_BUS_BLOCK_WRITE32(dev, p, o, cnt, var) \
+ ai2c_region_io_map[p].writeFn(dev, &ai2c_region_io_map[p], \
+ o, (var), cnt, 0, AI2C_NCA_CMD_CRBW, 4)
+
+
+#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);
+
+
+ /**************************************************************************
+ * Event/Error Logging
+ **************************************************************************/
+
+/*
+* AI2C_MSG
+*
+* Print a message to the system console.
+*/
+#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)
+
+ /*
+ * 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;
+
+
+ /**************************************************************************
+ * Endianness
+ **************************************************************************/
+
+#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
+
+/*
+* 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)
+
+
+ /*
+ * 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)
+
+
+ /*
+ * 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
+
+#ifndef MAX
+#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);
+extern void ai2c_free(void *ptr);
/*****************************************************************************
-* Constants *
+* Internal Data Structure Definitions *
+*****************************************************************************/
+
+ /**********************************************************************
+ * ACP I/O Mapped Functions Stuff *
+ **********************************************************************/
+
+#define __ai2c_dev_direct_read ai2c_dev_direct_read
+#define __ai2c_dev_direct_write ai2c_dev_direct_write
+#define __ai2c_dev_indirect_read ai2c_dev_indirect_read
+#define __ai2c_dev_indirect_write ai2c_dev_indirect_write
+#define __ai2c_dev_dcr_read ai2c_dev_dcr_read
+#define __ai2c_dev_dcr_write ai2c_dev_dcr_write
+
+/*
+ * Enumeration of pages/regions tracked by this driver.
+ */
+enum {
+ AI2C_DEV_PAGE_AHB_BEGIN, /* Placeholder (0/1) */
+ AI2C_DEV_PAGE_I2C_0 = AI2C_DEV_PAGE_AHB_BEGIN,
+ AI2C_DEV_PAGE_I2C_1,
+ AI2C_DEV_PAGE_I2C_2,
+ AI2C_DEV_PAGE_I2C_3 /* aka SMB */,
+ AI2C_DEV_PAGE_GPIO_0,
+ AI2C_DEV_PAGE_RESET_CTRL,
+ AI2C_DEV_PAGE_TIMER,
+ AI2C_DEV_PAGE_GPREG,
+ AI2C_DEV_PAGE_AHB_END = AI2C_DEV_PAGE_GPREG,
+
+ AI2C_DEV_PAGE_END_MARKER,
+};
+
+#undef AI2C_DEV_APB_PAGE_BASE
+#define AI2C_DEV_APB_PAGE_BASE AI2C_DEV_PAGE_AHB_BEGIN
+
+
+ /**************************************************************************
+ * Macros *
+ **************************************************************************/
+
+#define DBGINFO(args...)
+ /* General debugging */
+#define XDBGINFO(args...)
+ /* Miscellaneous debugging, commented out */
+#define ADBGINFO(args...)
+ /* Address debugging */
+#define D1DBGINFO(args...)
+ /* Track descriptor chain register modifications */
+#define D2DBGINFO(args...)
+ /* Track descriptor chain tracking modifications */
+#define D3DBGINFO(args...)
+ /* Track descriptor chain reset modifications */
+#define D4DBGINFO(args...)
+ /* Track dme+descriptor chain modifications */
+#define ODBGINFO(args...)
+ /* Track tx irq transaction */
+#define O2DBGINFO(args...)
+ /* Track tx foreground transaction */
+#define O3DBGINFO(args...)
+ /* Track numFree changes for tx transaction */
+#define IDBGINFO(args...)
+ /* Track rx irq transaction */
+#define I2DBGINFO(args...)
+ /* Track rx foreground transaction */
+#define I3DBGINFO(args...)
+ /* Track numFree changes for rx transaction */
+#define SDBGINFO(args...)
+ /* Track dme select/release */
+#define DDBGINFO(args...)
+ /* Track dbell irq transaction */
+#define EIDBGINFO(args...)
+ /* Track enable/disable irqs */
+#define GSDBGINFO(args...) printk(args)
+ /* Dump lots of data to console during get_glob_stat */
+#undef MDBG_SUPPORT
+#ifdef MDBG_SUPPORT
+ #define MDBGINFO(args...) printk(args)
+ /* Track maintenance accesses */
+#else
+ #define MDBGINFO(args...)
+#endif
+
+ /**********************************************************************
+ * Macros for Paged Sysmem Access Methods *
+ **********************************************************************/
+
+#define AI2C_EDEV_BUS_PAGE_SHIFT 18
+#define AI2C_EDEV_BUS_PAGE_SIZE ((u64) 1 << AI2C_EDEV_BUS_PAGE_SHIFT)
+
+#define AI2C_EDEV_BUS_PAGE_MASK (AI2C_EDEV_BUS_PAGE_SIZE - 1) /* ??? */
+#define AI2C_EDEV_BUS_PAGE_OFFSET(x) \
+ ((u32) (((x) & (~AI2C_EDEV_BUS_PAGE_MASK)) >> \
+ AI2C_EDEV_BUS_PAGE_SHIFT)) /* ??? */
+
+
+ /**********************************************************************
+ * Low-level I/O based upon 'page' *
+ **********************************************************************/
+
+#define AI2C_DEV_BUS_ADDR(dev, pageId, offset) \
+ ((dev)->pageAddr[pageId] + offset)
+
+#define AI2C_DEV_PAGE_ENDIANNESS(pageId) (priv->pages[pageId].endianness)
+
+
+/**************************************************************************
+* Driver State management *
+**************************************************************************/
+
+ /**********************************************************************
+ * Support Memory Mappings for Driver State Structure *
+ **********************************************************************/
+
+#define AI2C_PAGE_FLAGS_NONE (0x00000000)
+#define AI2C_PAGE_FLAGS_I2CBUS (0x00000001)
+
+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 axxia_i2c_bus_platform_data *pdata;
+};
+
+struct ai2c_dev_chip_entry_s {
+ u32 chipType;
+ char *chipName;
+ u32 numActiveBusses;
+ struct ai2c_i2c_access *api;
+};
+
+
+ /**********************************************************************
+ * Driver State Structure *
+ **********************************************************************/
+
+struct ai2c_priv {
+ spinlock_t regLock;
+ spinlock_t ioLock;
+
+ struct ai2c_rev_id hw_rev;
+
+ /* Static configuration describing selected ACP I2C bus region */
+ struct ai2c_dev_chip_entry_s *busCfg;
+
+ /* Memory Mapping/Management constructs */
+ u32 numActiveBusses;
+ struct ai2c_dev_page_s *pages;
+ /* Per module memory pages */
+
+ /* Memory indexing support to reach selected ACP regions */
+ u32 *pageAddr;
+
+ /* Diagnostics */
+};
+
+ /**************************************************************************
+ * Exportable State *
+ **************************************************************************/
+
+extern int AI2C_MSG_TRACE_LEVEL;
+
+extern int ai2c_chip_ver;
+
+
+ /**************************************************************************
+ * Shared Functions *
+ **************************************************************************/
+
+extern int ai2c_dev_read32(
+ struct ai2c_priv *dev,
+ u32 regionId,
+ u64 offset,
+ u32 *buffer);
+
+extern int ai2c_dev_write32(
+ struct ai2c_priv *dev,
+ u32 regionId,
+ u64 offset,
+ u32 buffer);
+
+int ai2c_dev_direct_read(
+ struct ai2c_priv *priv,
+ struct ai2c_region_io *region,
+ u64 offset,
+ u32 *buffer,
+ u32 count,
+ u32 flags,
+ u32 cmdType,
+ u32 xferWidth);
+
+int ai2c_dev_direct_write(
+ struct ai2c_priv *priv,
+ struct ai2c_region_io *region,
+ u64 offset,
+ u32 *buffer,
+ u32 count,
+ u32 flags,
+ u32 cmdType,
+ u32 xferWidth);
+
+int ai2c_dev_dcr_read(
+ struct ai2c_priv *priv,
+ struct ai2c_region_io *region,
+ u64 offset,
+ u32 *buffer,
+ u32 count,
+ u32 flags,
+ u32 cmdType,
+ u32 xferWidth);
+
+int ai2c_dev_dcr_write(
+ struct ai2c_priv *priv,
+ struct ai2c_region_io *region,
+ u64 offset,
+ u32 *buffer,
+ u32 count,
+ u32 flags,
+ u32 cmdType,
+ u32 xferWidth);
+
+/*! @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);
+
+
+/*****************************************************************************
+* Bus Device Protocol Definitions *
*****************************************************************************/
/*****************************
@@ -92,10 +950,6 @@
#define DEV_10BIT_AUTO(ioc) TENBIT_SETENABLED(ioc)
-/*****************************************************************************
-* Type definitions *
-*****************************************************************************/
-
/*******************************************
* Common Protocol State & Callbacks
********************************************/
@@ -169,9 +1023,9 @@ struct ai2c_i2c_access {
extern struct ai2c_i2c_access ai2c_axm5500_cfg;
-/*****************************************************************************
-* Externally Visible Function Prototypes *
-*****************************************************************************/
+ /************************************************************************
+ * Externally Visible Function Prototypes *
+ ************************************************************************/
/*! @fn int ai2c_bus_init(ai2c_priv_t * inDevHdl);
@brief This is a one time initialization for the I2C protocol
@@ -228,4 +1082,9 @@ extern int ai2c_bus_block_write8(
*/
extern int ai2c_bus_destroy(struct ai2c_priv *priv);
+extern int ai2c_dev_clock_mhz(
+ struct ai2c_priv *priv, /* IN */
+ u32 *clockMhz); /* OUT: Calculated value */
+
+
#endif /* defined(AI2C_BUS_H) */
diff --git a/drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c b/drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c
index 01c1a38..2210d3a 100644
--- a/drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c
+++ b/drivers/i2c/busses/ai2c/ai2c_bus_axm5500.c
@@ -23,10 +23,7 @@
/* #define EXTRA_DEBUG */
#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"
+#include "ai2c_i2c_regs.h"
/*****************************************************************************
diff --git a/drivers/i2c/busses/ai2c/ai2c_mod.c b/drivers/i2c/busses/ai2c/ai2c_mod.c
index 63d3521..6692b2e 100644
--- a/drivers/i2c/busses/ai2c/ai2c_mod.c
+++ b/drivers/i2c/busses/ai2c/ai2c_mod.c
@@ -53,13 +53,14 @@
*/
#include "ai2c_bus.h"
-#include "regs/ai2c_cfg_node_reg_defines.h"
-#include "regs/ai2c_cfg_node_regs.h"
+#include "ai2c_i2c_regs.h"
#include "asm/lsi/acp_ncr.h"
+
/******************************************************************************
* --- Linux Module Interface --- *
******************************************************************************/
+
#define AI2C_PARM_INT int
#define AI2C_PARM_UINT uint
#define AI2C_MODULE_PARM(v, t) module_param(v, t, (S_IRUSR|S_IRGRP|S_IROTH|\
@@ -71,6 +72,7 @@
/*****************************
* --- Module Parameters --- *
*****************************/
+
int AI2C_MSG_TRACE_LEVEL;
int ai2c_chip_ver; /* Opt: Needed to figure out memory map, etc.
* Can verify against value from 0xa.0x10.0x2c
@@ -108,6 +110,1267 @@ struct local_state {
static struct local_state *ai2cModState;
/*****************************************************************************
+ * Local Functions: Memory
+ *****************************************************************************/
+
+/*
+ * definitions of the ai2c_malloc/ai2c_nvm_malloc family of functions.
+ */
+
+void *ai2c_malloc(size_t size)
+{
+ void *p;
+
+ if (size <= 0) {
+#ifdef AI2C_DEBUG
+ AI2C_MSG(AI2C_MSG_DEBUG,
+ "WARNING: ai2c_malloc(%d) passed a zero or "
+ "less size.\n",
+ size);
+#endif
+ return 0;
+ }
+
+ p = __ai2c_malloc(size);
+ if (p == NULL)
+ AI2C_MSG(AI2C_MSG_ERROR, "ai2c_malloc(%d) failed.\n", size);
+
+ return p;
+}
+
+void *ai2c_calloc(size_t no, size_t size)
+{
+ void *p;
+
+ 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",
+ no, size);
+#endif
+ return 0;
+ }
+
+ p = __ai2c_calloc(no, size);
+ if (p == NULL) {
+ AI2C_MSG(AI2C_MSG_ERROR,
+ "ai2c_calloc(no=%d, size=%d) failed.\n", no, size);
+ }
+ return p;
+}
+
+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",
+ size);
+#endif
+ return 0;
+ }
+
+ ptr = __ai2c_realloc(ptr, size);
+ if (ptr == NULL) {
+ AI2C_MSG(AI2C_MSG_ERROR,
+ "ai2c_realloc(ptr=%p, size=%d) failed.\n",
+ ptr, size);
+ }
+ return ptr;
+}
+
+void ai2c_free(void *ptr)
+{
+ if (ptr == NULL) {
+#ifdef AI2C_DEBUG
+ AI2C_MSG(AI2C_MSG_DEBUG,
+ "WARNING: ai2c_free(%p) passed a NULL pointer.\n",
+ ptr);
+#endif
+ return;
+ }
+
+ __ai2c_free(ptr);
+}
+
+/*****************************************************************************
+ * Clock Support
+ *****************************************************************************/
+
+/*
+ * Clock MHz calculation support Tables:
+ */
+
+/* Table 1-7: Feedback Divider Pre-Scalar */
+
+static const u8 Prescale[][2] = {
+ {0, 1},
+ {1, 3},
+ {2, 2},
+ {3, 4},
+};
+
+#define Prescale_COUNT (sizeof(Prescale)/(2*sizeof(u8)))
+
+/* Table 1-6: PLL Predivider */
+
+static const u8 Predivider[][2] = {
+ {0, 1},
+ {1, 16},
+ {2, 17},
+ {3, 30},
+ {4, 13},
+ {5, 18},
+ {6, 7},
+ {7, 31},
+ {8, 14},
+ {9, 11},
+ {10, 19},
+ {11, 21},
+ {12, 27},
+ {13, 8},
+ {14, 23},
+ {15, 32},
+ {16, 15},
+ {17, 29},
+ {18, 12},
+ {19, 6},
+ {20, 10},
+ {21, 20},
+ {22, 26},
+ {23, 22},
+ {24, 28},
+ {25, 5},
+ {26, 9},
+ {27, 25},
+ {28, 4},
+ {29, 24},
+ {30, 3},
+ {31, 2},
+};
+
+#define Predivider_COUNT (sizeof(Predivider)/(2*sizeof(u8)))
+
+/* Table 1-5: PLL Forward Dividers A,B */
+
+static const u8 ForwardDivider[][2] = {
+ {0, 1},
+ {1, 2},
+ {2, 28},
+ {3, 27},
+ {4, 22},
+ {5, 21},
+ {6, 30},
+ {7, 29},
+ {8, 24},
+ {9, 23},
+ {10, 12},
+ {11, 11},
+ {12, 16},
+ {13, 15},
+ {14, 32},
+ {15, 31},
+ {16, 26},
+ {17, 25},
+ {18, 20},
+ {19, 19},
+ {20, 10},
+ {21, 9},
+ {22, 14},
+ {23, 13},
+ {24, 18},
+ {25, 17},
+ {26, 8},
+ {27, 7},
+ {28, 6},
+ {29, 5},
+ {30, 4},
+ {31, 3},
+};
+
+#define ForwardDivider_COUNT (sizeof(ForwardDivider)/(2*sizeof(u8)))
+
+/* Table 1-11: PLL Feedback Divider */
+
+static const u8 FeedbackDivider[][2] = {
+ {0, 1},
+ {1, 123},
+ {2, 117},
+ {3, 251},
+ {4, 245},
+ {5, 69},
+ {6, 111},
+ {7, 125},
+ {8, 119},
+ {9, 95},
+ {10, 105},
+ {11, 197},
+ {12, 239},
+ {13, 163},
+ {14, 63},
+ {15, 253},
+ {16, 247},
+ {17, 187},
+ {18, 57},
+ {19, 223},
+ {20, 233},
+ {21, 207},
+ {22, 157},
+ {23, 71},
+ {24, 113},
+ {25, 15},
+ {26, 89},
+ {27, 37},
+ {28, 191},
+ {29, 19},
+ {30, 99},
+ {31, 127},
+ {32, 121},
+ {33, 109},
+ {34, 93},
+ {35, 61},
+ {36, 185},
+ {37, 155},
+ {38, 13},
+ {39, 97},
+ {40, 107},
+ {41, 11},
+ {42, 9},
+ {43, 81},
+ {44, 31},
+ {45, 49},
+ {46, 83},
+ {47, 199},
+ {48, 241},
+ {49, 33},
+ {50, 181},
+ {51, 143},
+ {52, 217},
+ {53, 173},
+ {54, 51},
+ {55, 165},
+ {56, 65},
+ {57, 85},
+ {58, 151},
+ {59, 147},
+ {60, 227},
+ {61, 41},
+ {62, 201},
+ {63, 255},
+ {64, 249},
+ {65, 243},
+ {66, 195},
+ {67, 237},
+ {68, 221},
+ {69, 231},
+ {70, 35},
+ {71, 189},
+ {72, 59},
+ {73, 183},
+ {74, 79},
+ {75, 29},
+ {76, 141},
+ {77, 215},
+ {78, 145},
+ {79, 225},
+ {80, 235},
+ {81, 219},
+ {82, 27},
+ {83, 139},
+ {84, 137},
+ {85, 135},
+ {86, 175},
+ {87, 209},
+ {88, 159},
+ {89, 53},
+ {90, 45},
+ {91, 177},
+ {92, 211},
+ {93, 23},
+ {94, 167},
+ {95, 73},
+ {96, 115},
+ {97, 67},
+ {98, 103},
+ {99, 161},
+ {100, 55},
+ {101, 205},
+ {102, 87},
+ {103, 17},
+ {104, 91},
+ {105, 153},
+ {106, 7},
+ {107, 47},
+ {108, 179},
+ {109, 171},
+ {110, 149},
+ {111, 39},
+ {112, 193},
+ {113, 229},
+ {114, 77},
+ {115, 213},
+ {116, 25},
+ {117, 133},
+ {118, 43},
+ {119, 21},
+ {120, 101},
+ {121, 203},
+ {122, 5},
+ {123, 169},
+ {124, 75},
+ {125, 131},
+ {126, 3},
+ {127, 129},
+ {128, 1},
+ {129, 250},
+ {130, 244},
+ {131, 124},
+ {132, 118},
+ {133, 196},
+ {134, 238},
+ {135, 252},
+ {136, 246},
+ {137, 222},
+ {138, 232},
+ {139, 70},
+ {140, 112},
+ {141, 36},
+ {142, 190},
+ {143, 126},
+ {144, 120},
+ {145, 60},
+ {146, 184},
+ {147, 96},
+ {148, 106},
+ {149, 80},
+ {150, 30},
+ {151, 198},
+ {152, 240},
+ {153, 142},
+ {154, 216},
+ {155, 164},
+ {156, 64},
+ {157, 146},
+ {158, 226},
+ {159, 254},
+ {160, 248},
+ {161, 236},
+ {162, 220},
+ {163, 188},
+ {164, 58},
+ {165, 28},
+ {166, 140},
+ {167, 224},
+ {168, 234},
+ {169, 138},
+ {170, 136},
+ {171, 208},
+ {172, 158},
+ {173, 176},
+ {174, 210},
+ {175, 72},
+ {176, 114},
+ {177, 160},
+ {178, 54},
+ {179, 16},
+ {180, 90},
+ {181, 46},
+ {182, 178},
+ {183, 38},
+ {184, 192},
+ {185, 212},
+ {186, 24},
+ {187, 20},
+ {188, 100},
+ {189, 168},
+ {190, 74},
+ {191, 128},
+ {192, 122},
+ {193, 116},
+ {194, 68},
+ {195, 110},
+ {196, 94},
+ {197, 104},
+ {198, 162},
+ {199, 62},
+ {200, 186},
+ {201, 56},
+ {202, 206},
+ {203, 156},
+ {204, 14},
+ {205, 88},
+ {206, 18},
+ {207, 98},
+ {208, 108},
+ {209, 92},
+ {210, 154},
+ {211, 12},
+ {212, 10},
+ {213, 8},
+ {214, 48},
+ {215, 82},
+ {216, 32},
+ {217, 180},
+ {218, 172},
+ {219, 50},
+ {220, 84},
+ {221, 150},
+ {222, 40},
+ {223, 200},
+ {224, 242},
+ {225, 194},
+ {226, 230},
+ {227, 34},
+ {228, 182},
+ {229, 78},
+ {230, 214},
+ {231, 144},
+ {232, 218},
+ {233, 26},
+ {234, 134},
+ {235, 174},
+ {236, 52},
+ {237, 44},
+ {238, 22},
+ {239, 166},
+ {240, 66},
+ {241, 102},
+ {242, 204},
+ {243, 86},
+ {244, 152},
+ {245, 6},
+ {246, 170},
+ {247, 148},
+ {248, 228},
+ {249, 76},
+ {250, 132},
+ {251, 42},
+ {252, 202},
+ {253, 4},
+ {254, 130},
+ {255, 2},
+};
+
+#define FeedbackDivider_COUNT (sizeof(FeedbackDivider)/(2*sizeof(u8)))
+
+int ai2c_dev_clock_mhz(
+ struct ai2c_priv *priv, /* IN */
+ u32 *clockMhz) /* OUT */
+{
+ int ai2cStatus = AI2C_ST_SUCCESS;
+ u32 sysPllCtrl;
+
+/*
+ * Equation:
+ * PLLOUTA = (CLKI * MULTINT.predivide * MULTINT.maindivide) /
+ * (PREDIV * RANGEA.predivide * RANGEA.maindivide)
+ *
+ * For SYSCLK, read content of sys_pll_ctrl (0x18d.0x0.0xc) defined as:
+ *
+ * Bits SW Name Description Reset
+ * 31:26 R/W prediv SYS PLL pre-divide value 6'h0
+ * 25:19 R/W rangeA SYS PLL range A value 7'h0
+ * 18:12 R/W rangeB SYS PLL range B value 7'h0
+ * 11:1 R/W multInt SYS PLL multiplier value 11'h0
+ * 0 R/W force_reset SYS PLL FF enable bit 1'h1
+ */
+ u32 prediv,
+ rangeA,
+ /* rangeB, */
+ multInt,
+ /* force_reset, */
+ v,
+ clki,
+ multInt_predivide,
+ multInt_maindivide,
+ rangeA_predivide,
+ rangeA_maindivide,
+ SYSCLK;
+
+ if ((clockMhz == NULL) || (priv == NULL))
+ AI2C_CALL(-ENOEXEC);
+
+ if (priv->hw_rev.isFpga) {
+ *clockMhz = 6;
+ return AI2C_ST_SUCCESS;
+ }
+
+ AI2C_CALL(ai2c_dev_read32(priv,
+ AI2C_REGION_CLK_CTRL, 0xC, &sysPllCtrl));
+
+ prediv = (sysPllCtrl >> 26) & 0x3f;
+ rangeA = (sysPllCtrl >> 19) & 0x7f;
+ /* rangeB = (sysPllCtrl >> 12) & 0x7f; */
+ multInt = (sysPllCtrl >> 1) & 0x7ff;
+ /* force_reset = (sysPllCtrl >> 0) & 0x1; */
+
+/*
+ * CLKI is 125Mhz
+ * MULTINT.predivide is the translated value from bits 8:9 of the
+ * multInt field.
+ * MULTINT.maindivide is the translated value from bits 7:0 of the
+ * multInt field.
+ * PREDIV is the translated value form the prediv field.
+ * RANGEA.predivide is the translated value form bits 6:5 of the
+ * rangeA field.
+ * RANGEA.maindivide is the translated value from bits 4:0 of the
+ * rangeA field.
+ */
+ clki = 125;
+
+ v = (multInt >> 8) & 0x3;
+ multInt_predivide = Prescale[v][1];
+
+ v = (multInt >> 0) & 0xff;
+ multInt_maindivide = FeedbackDivider[v][1];
+
+ v = prediv;
+ prediv = Predivider[v][1];
+
+ v = (rangeA >> 5) & 0x3;
+ rangeA_predivide = Prescale[v][1];
+
+ v = (rangeA >> 0) & 0x1f;
+ rangeA_maindivide = ForwardDivider[v][1];
+
+/*
+ * As an example of the SYS clock running at 400Mhz:
+ *
+ * The control register value is 0x02ed4566. It decodes as:
+ * prediv = 0x000
+ * rangeA = 0x05d
+ * multint = 0x2b3
+ *
+ * To get values for the equation:
+ * MULTINT.predivide = 0x02 Translated value from the tables: 2
+ * MULTINT.maindivide = 0xB3 Translated value from the tables: 16
+ * PREDIV = 0x00 Translated value from the tables: 1
+ * RANGEA.predivide = 0x02 Translated value from the tables: 2
+ * RANGEA.maindivide = 0x1d Translated value from the tables: 5
+ *
+ * Filling in the above values:
+ *
+ * SYSCLK = (CLKI * MULTINT.predivide * MULTINT.maindivide) /
+ * (PREDIV * RANGEA.predivide * RANGEA.maindivide)
+ * = (125Mhz * 2 * 16) / (1 * 2 * 5)
+ * = 4000Mhz / 10
+ * = 400Mhz
+ */
+
+ SYSCLK = (clki * multInt_predivide * multInt_maindivide) /
+ (prediv * rangeA_predivide * rangeA_maindivide);
+
+ (*clockMhz) = SYSCLK;
+
+ai2c_return:
+ return ai2cStatus;
+}
+
+/*****************************************************************************
+ * ACP/AXXIA Memory mapping & Device I/O
+ *****************************************************************************/
+
+/*
+ * This block of code defines the memory addresses for each h/w block
+ * that is accessible as a direct bus i/o operation.
+ *
+ * IMPORTANT: ALL BUS GROUPINGS MUST BE MAINTAINED
+ */
+static struct ai2c_dev_page_s ai2c_dev_page[AI2C_DEV_PAGE_END_MARKER] = {
+ {
+ AI2C_DEV_PAGE_I2C_0, "AXXIA_I2C0", 0, 0x00000000000ULL,
+ AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN,
+ AI2C_PAGE_FLAGS_I2CBUS, NULL,
+ },
+ {
+ AI2C_DEV_PAGE_I2C_1, "AXXIA_I2C1", 0, 0x00000000000ULL,
+ AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN,
+ AI2C_PAGE_FLAGS_I2CBUS, NULL,
+ },
+ {
+ AI2C_DEV_PAGE_I2C_2, "AXXIA_I2C2", 0, 0x00000000000ULL,
+ AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN,
+ AI2C_PAGE_FLAGS_I2CBUS, NULL,
+ },
+ {
+ AI2C_DEV_PAGE_I2C_3, "AXXIA_SMB", 0, 0x00000000000ULL,
+ AI2C_DEV_SIZE_4KB, AI2C_DEV_ACCESS_LITTLE_ENDIAN,
+ AI2C_PAGE_FLAGS_I2CBUS, NULL,
+ },
+ {
+ AI2C_DEV_PAGE_END_MARKER, NULL, 0, 0x00000000000ULL, 0, 0,
+ AI2C_PAGE_FLAGS_NONE, NULL,
+ },
+ {
+ AI2C_DEV_PAGE_END_MARKER, NULL, 0, 0x00000000000ULL, 0, 0,
+ AI2C_PAGE_FLAGS_NONE, NULL,
+ },
+ {
+ AI2C_DEV_PAGE_END_MARKER, NULL, 0, 0x00000000000ULL, 0, 0,
+ AI2C_PAGE_FLAGS_NONE, NULL,
+ },
+ {
+ AI2C_DEV_PAGE_END_MARKER, NULL, 0, 0x00000000000ULL, 0, 0,
+ AI2C_PAGE_FLAGS_NONE, NULL,
+ },
+};
+
+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 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) as
+ * the "AI2C_DEV_PAGE_xxx" enumeration.
+ */
+
+static struct ai2c_access_map ai2cDummyRegionMap[] = AI2C_DUMMY_REGION_MAP_INIT;
+
+static struct ai2c_region_io ai2c_region_io_map[] = {
+ /* 323.0 */
+ {
+ AI2C_REGION_I2C_0, ai2cDummyRegionMap,
+ __ai2c_dev_direct_read, __ai2c_dev_direct_write,
+ AI2C_DEV_PAGE_I2C_0,
+ },
+ /* 332.0 */
+ {
+ AI2C_REGION_I2C_1, ai2cDummyRegionMap,
+ __ai2c_dev_direct_read, __ai2c_dev_direct_write,
+ AI2C_DEV_PAGE_I2C_1,
+ },
+ /* 332.0 */
+ {
+ AI2C_REGION_I2C_2, ai2cDummyRegionMap,
+ __ai2c_dev_direct_read, __ai2c_dev_direct_write,
+ AI2C_DEV_PAGE_I2C_2,
+ },
+ /* 348.0 */
+ {
+ AI2C_REGION_I2C_3, ai2cDummyRegionMap,
+ __ai2c_dev_direct_read, __ai2c_dev_direct_write,
+ AI2C_DEV_PAGE_I2C_3,
+ },
+ /* 320.0 */
+ {
+ AI2C_REGION_GPIO_0, ai2cDummyRegionMap,
+ __ai2c_dev_direct_read, __ai2c_dev_direct_write,
+ AI2C_DEV_PAGE_GPIO_0,
+ },
+ /* 398.0 */
+ {
+ AI2C_REGION_RESET_CTRL, ai2cDummyRegionMap,
+ __ai2c_dev_dcr_read, __ai2c_dev_dcr_write,
+ AI2C_DEV_PAGE_RESET_CTRL,
+ },
+ /* 326.0 */
+ {
+ AI2C_REGION_TIMER, ai2cDummyRegionMap,
+ __ai2c_dev_direct_read, __ai2c_dev_direct_write,
+ AI2C_DEV_PAGE_TIMER,
+ },
+ /* 329.0 */
+ {
+ AI2C_REGION_GPREG, ai2cDummyRegionMap,
+ __ai2c_dev_direct_read, __ai2c_dev_direct_write,
+ AI2C_DEV_PAGE_GPREG,
+ },
+};
+
+static const u32 ai2c_region_pages_max =
+ sizeof(ai2c_region_io_map) / sizeof(struct ai2c_region_io);
+
+
+/*****************************************************************************
+ * Miscellaneous Utility functions
+ *****************************************************************************/
+
+u32 ai2c_page_to_region(
+ struct ai2c_priv *priv,
+ u32 pageId)
+{
+ int i;
+ for (i = 0; i < ai2c_region_pages_max; i++)
+ if (pageId == ai2c_region_io_map[i].pageId)
+ return ai2c_region_io_map[i].regionId;
+ return AI2C_REGION_NULL;
+}
+
+struct ai2c_region_io *ai2c_region_lookup(
+ struct ai2c_priv *priv,
+ u32 regionId)
+{
+ int i;
+ for (i = 0; i < ai2c_region_pages_max; i++)
+ if (regionId == ai2c_region_io_map[i].regionId)
+ return &ai2c_region_io_map[i];
+ return NULL;
+}
+
+/*****************************************************************************
+ * Read/Write ACP Memory Spaces
+ *****************************************************************************/
+
+/*
+ * ai2c_dev_direct_read
+ *
+ * Perform 32-bit AI2C device I/O to non-ConfigRing region.
+ */
+int ai2c_dev_direct_read(
+ struct ai2c_priv *priv,
+ struct ai2c_region_io *region,
+ u64 offset,
+ u32 *buffer,
+ u32 count,
+ u32 flags,
+ u32 cmdType,
+ u32 xferWidth)
+{
+ int st = 0;
+ u32 endianness;
+ unsigned long busAddr;
+ u32 i;
+
+ AI2C_MSG(AI2C_MSG_ENTRY,
+ "direct_read enter: %x.%x.%llx %d\n",
+ AI2C_NODE_ID(region->regionId),
+ AI2C_TARGET_ID(region->regionId),
+ (unsigned long long) offset, count);
+
+ if (priv->pageAddr[region->pageId] == 0) {
+ st = -EBADSLT;
+ goto cleanup;
+ }
+
+ busAddr = AI2C_DEV_BUS_ADDR(priv, region->pageId, offset);
+ endianness = AI2C_DEV_PAGE_ENDIANNESS(region->pageId);
+
+ switch (xferWidth) {
+ case 4:
+ 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",
+ region->regionId, offset, busAddr, buffer[i]);
+ }
+ break;
+ case 2:
+ {
+ u16 *p16 = (u16 *) buffer;
+ for (i = 0; i < count; i++, busAddr += 2)
+ p16[i] = AI2C_BUS_READ16(busAddr, endianness);
+ }
+ break;
+ case 1:
+ {
+ u8 *p8 = (u8 *) buffer;
+ for (i = 0; i < count; i++, busAddr += 1)
+ p8[i] = AI2C_BUS_READ8(busAddr);
+ }
+ break;
+ default:
+ st = -EACCES;
+ break;
+ }
+
+cleanup:
+ AI2C_MSG(AI2C_MSG_EXIT,
+ "direct_read exit: st=%d %x.%x.%llx=0x%08x\n",
+ st, AI2C_NODE_ID(region->regionId),
+ AI2C_TARGET_ID(region->regionId), (unsigned long long) offset,
+ buffer[0]);
+ return (int) st;
+}
+
+/*
+ * ai2c_dev_direct_write
+ *
+ * Perform 32-bit AI2C device I/O to non-ConfigRing region.
+ */
+int ai2c_dev_direct_write(
+ struct ai2c_priv *priv,
+ struct ai2c_region_io *region,
+ u64 offset,
+ u32 *buffer,
+ u32 count,
+ u32 flags,
+ u32 cmdType,
+ u32 xferWidth)
+{
+ int st = 0;
+ u32 endianness;
+ unsigned long busAddr;
+ u32 i;
+
+ AI2C_MSG(AI2C_MSG_ENTRY,
+ "direct_write enter: %x.%x.%llx 0x%08x (%d)\n",
+ AI2C_NODE_ID(region->regionId),
+ AI2C_TARGET_ID(region->regionId),
+ (unsigned long long) offset,
+ buffer[0], count);
+
+ if (priv->pageAddr[region->pageId] == 0) {
+ st = -EBADSLT;
+ goto cleanup;
+ }
+
+ busAddr = AI2C_DEV_BUS_ADDR(priv, region->pageId, offset);
+ endianness = AI2C_DEV_PAGE_ENDIANNESS(region->pageId);
+
+ switch (xferWidth) {
+ case 4:
+ 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",
+ region->regionId, offset, busAddr, buffer[i]);
+ }
+ break;
+
+ case 2:
+ {
+ u16 *buf16 = (u16 *) buffer;
+ 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",
+ region->regionId,
+ offset, busAddr, buf16[i]);
+ }
+ }
+ break;
+ case 1:
+ {
+ u8 *buf8 = (u8 *) buffer;
+ 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",
+ region->regionId,
+ offset, busAddr, buf8[i]);
+ }
+ }
+ break;
+ default:
+ st = -EACCES;
+ break;
+ }
+
+cleanup:
+ AI2C_MSG(AI2C_MSG_EXIT, "direct_write exit st=%d\n", st);
+ return (int) st;
+}
+
+/*
+ * ai2c_dev_read32
+ *
+ */
+int ai2c_dev_read32(
+ struct ai2c_priv *priv,
+ u32 regionId,
+ u64 offset,
+ u32 *buffer)
+{
+ int ai2cStatus = 0;
+ struct ai2c_region_io *region = ai2c_region_lookup(priv, regionId);
+ unsigned long lflags = 0;
+
+ AI2C_SPINLOCK_INTERRUPT_DISABLE(&priv->regLock, lflags);
+
+ AI2C_MSG(AI2C_MSG_ENTRY,
+ "dev_read32 enter: %x.%x.%llx %d\n",
+ AI2C_NODE_ID(regionId), AI2C_TARGET_ID(regionId),
+ (unsigned long long) offset, 1);
+
+ if (region) {
+ ai2cStatus =
+ AI2C_EDEV_BUS_BLOCK_READ32(priv,
+ region->pageId, offset, 1, buffer);
+
+ } else {
+
+#ifdef CONFIG_LSI_UBOOTENV
+ ai2cStatus = ncr_read(regionId, (u32) offset,
+ 1 * sizeof(u32), buffer);
+#else
+ ai2cStatus = -ENOSYS;
+#endif
+ }
+
+ AI2C_SPINLOCK_INTERRUPT_ENABLE(&priv->regLock, lflags);
+
+ return ai2cStatus;
+}
+
+/*
+ * ai2c_dev_write32
+ *
+ */
+int ai2c_dev_write32(
+ struct ai2c_priv *priv,
+ u32 regionId,
+ u64 offset,
+ u32 buffer)
+{
+ int ai2cStatus = 0;
+ struct ai2c_region_io *region = ai2c_region_lookup(priv, regionId);
+ unsigned long lflags = 0;
+
+ AI2C_SPINLOCK_INTERRUPT_DISABLE(&priv->regLock, lflags);
+
+ AI2C_MSG(AI2C_MSG_ENTRY,
+ "dev_write32 enter: %x.%x.%llx 0x%08x (%d)\n",
+ AI2C_NODE_ID(regionId), AI2C_TARGET_ID(regionId),
+ (unsigned long long) offset, (unsigned int)&buffer, 1);
+
+ if (region) {
+ ai2cStatus =
+ AI2C_EDEV_BUS_BLOCK_WRITE32(priv,
+ region->pageId, offset, 1,
+ &buffer);
+
+ } else {
+
+#ifdef CONFIG_LSI_UBOOTENV
+ ai2cStatus = ncr_write(regionId, (u32) offset,
+ 1 * sizeof(u32), &buffer);
+#else
+ ai2cStatus = -ENOSYS;
+#endif
+ }
+
+ AI2C_SPINLOCK_INTERRUPT_ENABLE(&priv->regLock, lflags);
+
+ return ai2cStatus;
+}
+
+/*
+ * ai2c_dev_dcr_read
+ *
+ * Perform 32-bit AI2C device I/O to non-Config Ring region.
+ */
+int ai2c_dev_dcr_read(
+ struct ai2c_priv *priv,
+ struct ai2c_region_io *region,
+ u64 offset,
+ u32 *buffer,
+ u32 count,
+ u32 flags,
+ u32 cmdType,
+ u32 xferWidth)
+{
+ return -ENOSYS;
+}
+
+/*
+ * ai2c_dev_dcr_write
+ *
+ * Perform 32-bit AI2C device I/O from non-Config Ring region.
+ */
+int ai2c_dev_dcr_write(
+ struct ai2c_priv *priv,
+ struct ai2c_region_io *region,
+ u64 offset,
+ u32 *buffer,
+ u32 count,
+ u32 flags,
+ u32 cmdType,
+ u32 xferWidth)
+{
+ return -ENOSYS;
+}
+
+/*****************************************************************************
+ * Basic configuration Fill-in
+ *****************************************************************************/
+
+static int ai2c_getChipType(struct ai2c_priv *priv)
+{
+ int ai2cStatus = AI2C_ST_SUCCESS;
+ u32 i;
+#ifdef CONFIG_LSI_UBOOTENV
+ ai2c_bool_t has_ECID = TRUE;
+ u32 rev_reg;
+ u32 pt_reg;
+ ai2c_cfg_node_node_cfg_r_t node_cfg;
+ ai2c_cfg_node_node_info_0_r_t node_info;
+
+ /*
+ * Determine device revision
+ */
+
+ /* Read the NCA local config node to see if we are an ASIC or FPGA */
+ AI2C_CALL(ai2c_dev_read32(priv, AI2C_REGION_NCA_CFG,
+ AI2C_CFG_NODE_NODE_CFG,
+ (u32 *) &node_cfg));
+ AI2C_CALL(ai2c_dev_read32(priv, AI2C_REGION_NCA_CFG,
+ AI2C_CFG_NODE_NODE_INFO_0,
+ (u32 *) &node_info));
+
+ if (node_cfg.fpga) {
+ priv->hw_rev.isFpga = 1;
+ /* v1 FPGA doesn't have the ECID block */
+ if (node_info.module_revision == 0)
+ has_ECID = FALSE;
+
+ } else
+ priv->hw_rev.isAsic = 1;
+
+ if (node_info.module_revision == AI2C_CHIP_ACP25xx ||
+ node_info.module_revision == AI2C_CHIP_ACP55xx)
+ has_ECID = FALSE;
+
+ /* Get the device chipType/Version from the ECID fuse block */
+ if (has_ECID) {
+
+ AI2C_CALL(ai2c_dev_read32(priv,
+ AI2C_REGION_ID(AI2C_NODE_X1_ECID, 0x10),
+ 0x2c, (u32 *) &rev_reg));
+
+ AI2C_CALL(ai2c_dev_read32(priv,
+ AI2C_REGION_ID(AI2C_NODE_X1_ECID, 0x10),
+ 0x20, &pt_reg));
+
+ priv->hw_rev.chipType = (rev_reg & 0x0000001f);
+ priv->hw_rev.chipVersion = (rev_reg & 0x000007e0) >> 5;
+ priv->hw_rev.cpuDisable = (rev_reg & 0x00007800) >> 11;
+ priv->hw_rev.sppDisable = (rev_reg & 0x00008000) >> 15;
+
+ priv->hw_rev.packageType = (pt_reg & 0xf0000000) >> 28;
+ } else {
+ /* if we don't have an ECID just use the NCA module version */
+ priv->hw_rev.chipType = node_info.module_revision;
+ priv->hw_rev.chipVersion = 0;
+ priv->hw_rev.packageType = 0;
+ priv->hw_rev.cpuDisable = 0;
+ priv->hw_rev.sppDisable = 0;
+ }
+
+ /* fixup chipType for ACP344x variants */
+ switch (priv->hw_rev.chipType) {
+ case 3:
+ case 4:
+ priv->hw_rev.chipType = AI2C_CHIP_ACP34xx;
+ break;
+ case 5:
+ priv->hw_rev.chipType = AI2C_CHIP_ACP34xx;
+ break;
+ default:
+ break;
+ }
+#endif
+
+ /* Environment variable override */
+ if (ai2c_chip_ver != -1) {
+ priv->hw_rev.chipType = ai2c_chip_ver;
+ priv->hw_rev.chipVersion = 0;
+ }
+#ifdef AI2C_CHIP_VER
+ else {
+ priv->hw_rev.chipType = AI2C_CHIP_VER;
+ priv->hw_rev.chipVersion = 0;
+ }
+#endif
+
+ 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:
+ return ai2cStatus;
+}
+
+int ai2c_stateSetup(
+ struct ai2c_priv **outPriv)
+{
+ int ai2cStatus = AI2C_ST_SUCCESS;
+ struct ai2c_priv *priv = NULL;
+
+ /* Now for the private memory for this module. */
+ priv = ai2c_malloc(sizeof(struct ai2c_priv));
+ if (!priv) {
+ AI2C_LOG(AI2C_MSG_ERROR,
+ "Could not allocate AI2C private memory root!\n");
+ ai2cStatus = -ENOMEM;
+ goto ai2c_return;
+ }
+ memset(priv, 0, sizeof(struct ai2c_priv));
+
+ /* Check chipType/chipVersion fields of 0xa.0x10.0x2c, first */
+ ai2cStatus = ai2c_getChipType(priv);
+ if (ai2cStatus != AI2C_ST_SUCCESS)
+ goto ai2c_return;
+
+ai2c_return:
+ if (ai2cStatus != AI2C_ST_SUCCESS)
+ (*outPriv) = NULL;
+ else
+ (*outPriv) = priv;
+
+ return ai2cStatus;
+}
+
+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 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
+ */
+ if (priv->pageAddr == NULL) {
+ 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));
+ }
+
+ for (i = 0; i < AI2C_DEV_PAGE_END_MARKER; 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:
+
+ if (ai2cStatus != AI2C_ST_SUCCESS) {
+ if (priv) {
+ if (priv->pageAddr) {
+ for (i = 0; i < AI2C_DEV_PAGE_END_MARKER; i++)
+ if (priv->pageAddr[i] != 0)
+ iounmap(
+ (void __iomem *)
+ priv->pageAddr[i]);
+ ai2c_free(priv->pageAddr);
+ }
+ ai2c_free(priv);
+ }
+ }
+
+ return ai2cStatus;
+}
+
+int ai2c_memDestroy(struct ai2c_priv *inPriv)
+{
+ int ai2cStatus = AI2C_ST_SUCCESS;
+ int i;
+
+ if (inPriv) {
+ if (inPriv->pageAddr) {
+ for (i = 0; i < AI2C_DEV_PAGE_END_MARKER; i++)
+ if (inPriv->pageAddr[i] != 0)
+ iounmap((void *)inPriv->pageAddr[i]);
+
+ ai2c_free(inPriv->pageAddr);
+ }
+
+ ai2c_free(inPriv);
+ }
+
+ return ai2cStatus;
+}
+
+/*****************************************************************************
* I2C Algorithm
*****************************************************************************/
--
1.8.4.1
More information about the linux-yocto
mailing list