generic-poky/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-i2c.patch

3436 lines
100 KiB
Diff

From: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
Subject: OKI Semiconductor PCH I2C driver
This driver implements I2C controls for PCH.
Signed-off-by: Masayuki Ohtake <masa-korg@dsn.okisemi.com>
Acked-by: Wang Qi <qi.wang@intel.com>
---
drivers/i2c/busses/Kconfig | 7 +
drivers/i2c/busses/Makefile | 3
drivers/i2c/busses/pch_common.h | 146
drivers/i2c/busses/pch_debug.h | 60
drivers/i2c/busses/pch_i2c_hal.c | 1930
drivers/i2c/busses/pch_i2c_hal.h | 337
drivers/i2c/busses/pch_i2c_main.c | 247
drivers/i2c/busses/pch_i2c_pci.c | 583
drivers/i2c/i2c-dev.c | 28
+++++++++++++++++++++++++++++++ 9 files changed, yy insertions(+)
diff -urN linux-2.6.33.1/drivers/i2c/busses/Kconfig topcliff-2.6.33.1/drivers/i2c/busses/Kconfig
--- linux-2.6.33.1/drivers/i2c/busses/Kconfig 2010-03-16 01:09:39.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/busses/Kconfig 2010-03-23 10:40:18.000000000 +0900
@@ -7,6 +7,13 @@
comment "PC SMBus host controller drivers"
depends on PCI
+config PCH_I2C
+ tristate "PCH I2C"
+ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SMB
+ PCH I2C Host controller.
+
config I2C_ALI1535
tristate "ALI 1535"
depends on PCI
diff -urN linux-2.6.33.1/drivers/i2c/busses/Makefile topcliff-2.6.33.1/drivers/i2c/busses/Makefile
--- linux-2.6.33.1/drivers/i2c/busses/Makefile 2010-03-16 01:09:39.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/busses/Makefile 2010-03-23 10:40:18.000000000 +0900
@@ -75,3 +75,6 @@
ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
EXTRA_CFLAGS += -DDEBUG
endif
+
+obj-$(CONFIG_PCH_I2C) += pch_i2c.o
+pch_i2c-objs := pch_i2c_main.o pch_i2c_pci.o pch_i2c_hal.o
diff -urN linux-2.6.33.1/drivers/i2c/busses/pch_common.h topcliff-2.6.33.1/drivers/i2c/busses/pch_common.h
--- linux-2.6.33.1/drivers/i2c/busses/pch_common.h 1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/busses/pch_common.h 2010-03-23 10:40:18.000000000 +0900
@@ -0,0 +1,146 @@
+/*!
+ * @file ioh_common.h
+ * @brief Provides the macro definitions used by all files.
+ * @version 1.0.0.0
+ * @section
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * History:
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * created:
+ * WIPRO 03/07/2009
+ * modified:
+ * WIPRO 05/08/2009
+ *
+ */
+
+#ifndef __IOH_COMMON_H__
+#define __IOH_COMMON_H__
+
+/*! @ingroup Global
+@def IOH_WRITE8
+@brief Macro for writing 8 bit data to an io/mem address
+*/
+#define IOH_WRITE8(val, addr) iowrite8((val), (void __iomem *)(addr))
+/*! @ingroup Global
+@def IOH_LOG
+@brief Macro for writing 16 bit data to an io/mem address
+*/
+#define IOH_WRITE16(val, addr) iowrite16((val), (void __iomem *)(addr))
+/*! @ingroup Global
+@def IOH_LOG
+@brief Macro for writing 32 bit data to an io/mem address
+*/
+#define IOH_WRITE32(val, addr) iowrite32((val), (void __iomem *)(addr))
+
+/*! @ingroup Global
+@def IOH_READ8
+@brief Macro for reading 8 bit data from an io/mem address
+*/
+#define IOH_READ8(addr) ioread8((void __iomem *)(addr))
+/*! @ingroup Global
+@def IOH_READ16
+@brief Macro for reading 16 bit data from an io/mem address
+*/
+#define IOH_READ16(addr) ioread16((void __iomem *)(addr))
+/*! @ingroup Global
+@def IOH_READ32
+@brief Macro for reading 32 bit data from an io/mem address
+*/
+#define IOH_READ32(addr) ioread32((void __iomem *)(addr))
+/*! @ingroup Global
+@def IOH_WRITE32_F
+@brief Macro for writing 32 bit data to an io/mem address
+*/
+#define IOH_WRITE32_F(val, addr) do \
+ { IOH_WRITE32((val), (addr)); (void)IOH_READ32((addr)); } while (0);
+
+/*! @ingroup Global
+@def IOH_WRITE_BYTE
+@brief Macro for writing 1 byte data to an io/mem address
+*/
+#define IOH_WRITE_BYTE IOH_WRITE8
+/*! @ingroup Global
+@def IOH_WRITE_WORD
+@brief Macro for writing 1 word data to an io/mem address
+*/
+#define IOH_WRITE_WORD IOH_WRITE16
+/*! @ingroup Global
+@def IOH_WRITE_LONG
+@brief Macro for writing long data to an io/mem address
+*/
+#define IOH_WRITE_LONG IOH_WRITE32
+
+/*! @ingroup Global
+@def IOH_READ_BYTE
+@brief Macro for reading 1 byte data from an io/mem address
+*/
+#define IOH_READ_BYTE IOH_READ8
+/*! @ingroup Global
+@def IOH_READ_WORD
+@brief Macro for reading 1 word data from an io/mem address
+*/
+#define IOH_READ_WORD IOH_READ16
+/*! @ingroup Global
+@def IOH_READ_LONG
+@brief Macro for reading long data from an io/mem address
+*/
+#define IOH_READ_LONG IOH_READ32
+
+/* Bit Manipulation Macros */
+
+/*! @ingroup Global
+@def IOH_READ_LONG
+@brief macro to set a specified bit(mask) at the
+ specified address
+*/
+#define IOH_SET_ADDR_BIT(addr, bitmask) IOH_WRITE_LONG((IOH_READ_LONG(addr) |\
+ (bitmask)), (addr))
+
+/*! @ingroup Global
+@def IOH_READ_LONG
+@brief macro to clear a specified bit(mask) at the specified address
+*/
+#define IOH_CLR_ADDR_BIT(addr, bitmask) IOH_WRITE_LONG((IOH_READ_LONG(addr) &\
+ ~(bitmask)), (addr))
+
+/*! @ingroup Global
+@def IOH_READ_LONG
+@brief macro to set a specified bitmask for a variable
+*/
+#define IOH_SET_BITMSK(var, bitmask) ((var) |= (bitmask))
+
+/*! @ingroup Global
+@def IOH_READ_LONG
+@brief macro to clear a specified bitmask for a variable
+*/
+#define IOH_CLR_BITMSK(var, bitmask) ((var) &= (~(bitmask)))
+
+/*! @ingroup Global
+@def IOH_READ_LONG
+@brief macro to set a specified bit for a variable
+*/
+#define IOH_SET_BIT(var, bit) ((var) |= (1<<(bit)))
+
+/*! @ingroup Global
+@def IOH_READ_LONG
+@brief macro to clear a specified bit for a variable
+*/
+#define IOH_CLR_BIT(var, bit) ((var) &= ~(1<<(bit)))
+
+#endif
diff -urN linux-2.6.33.1/drivers/i2c/busses/pch_debug.h topcliff-2.6.33.1/drivers/i2c/busses/pch_debug.h
--- linux-2.6.33.1/drivers/i2c/busses/pch_debug.h 1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/busses/pch_debug.h 2010-03-23 10:40:18.000000000 +0900
@@ -0,0 +1,60 @@
+/*!
+ * @file ioh_debug.h
+ * @brief Provides the macro definitions used for debugging.
+ * @version 1.0.0.0
+ * @section
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * History:
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * created:
+ * WIPRO 03/07/2009
+ * modified:
+ * WIPRO 05/08/2009
+ *
+ */
+
+#ifndef __IOH_DEBUG_H__
+#define __IOH_DEBUG_H__
+
+#ifdef MODULE
+#define IOH_LOG(level, fmt, args...) printk(level "%s:" fmt "\n",\
+ THIS_MODULE->name, ##args)
+#else
+#define IOH_LOG(level, fmt, args...) printk(level "%s:" fmt "\n" ,\
+ __FILE__, ##args)
+#endif
+
+
+#ifdef DEBUG
+ #define IOH_DEBUG(fmt, args...) IOH_LOG(KERN_DEBUG, fmt, ##args)
+#else
+ #define IOH_DEBUG(fmt, args...)
+#endif
+
+#ifdef IOH_TRACE_ENABLED
+ #define IOH_TRACE IOH_DEBUG
+#else
+ #define IOH_TRACE(fmt, args...)
+#endif
+
+#define IOH_TRACE_ENTER IOH_TRACE("Enter %s", __func__)
+#define IOH_TRACE_EXIT IOH_TRACE("Exit %s", __func__)
+
+
+#endif
diff -urN linux-2.6.33.1/drivers/i2c/busses/pch_i2c_hal.c topcliff-2.6.33.1/drivers/i2c/busses/pch_i2c_hal.c
--- linux-2.6.33.1/drivers/i2c/busses/pch_i2c_hal.c 1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/busses/pch_i2c_hal.c 2010-03-23 10:40:18.000000000 +0900
@@ -0,0 +1,1930 @@
+/*!
+* @file ioh_i2c_hal.c
+* @brief This file contains definitions of HAL Layer APIs and
+* Internal functions
+* @version 0.95
+* @section
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+* History:
+* Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+* All rights reserved.
+*
+* created:
+* WIPRO 02/20/2009
+* modified:
+* WIPRO 05/21/2009
+*
+*/
+
+/*includes*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+
+#include "pch_i2c_hal.h"
+#include "pch_common.h"
+#include "pch_debug.h"
+
+/**
+ *macro definition
+ */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CSADR
+@brief I2CSADR register offset
+*/
+#define IOH_I2CSADR (0x00) /* I2C slave address register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CCTL
+@brief I2CCTL register offset
+*/
+#define IOH_I2CCTL (0x04) /* I2C control register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CSR
+@brief I2CSR register offset
+*/
+#define IOH_I2CSR (0x08) /* I2C status register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CDR
+@brief I2CDR register offset
+*/
+#define IOH_I2CDR (0x0C) /* I2C data register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CMON
+@brief I2CMON register offset
+*/
+#define IOH_I2CMON (0x10) /* I2C bus monitor register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CBC
+@brief I2CBC register offset
+*/
+#define IOH_I2CBC (0x14) /* I2C bus transfer rate setup counter */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CMOD
+@brief I2CMOD register offset
+*/
+#define IOH_I2CMOD (0x18) /* I2C mode register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CBUFSLV
+@brief I2CBUFSLV register offset
+*/
+#define IOH_I2CBUFSLV (0x1C) /* I2C buffer mode slave address register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CBUFSUB
+@brief I2CBUFSUB register offset
+*/
+#define IOH_I2CBUFSUB (0x20) /* I2C buffer mode subaddress register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CBUFFOR
+@brief I2CBUFFOR register offset
+*/
+#define IOH_I2CBUFFOR (0x24) /* I2C buffer mode format register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CBUFCTL
+@brief I2CBUFCTL register offset
+*/
+#define IOH_I2CBUFCTL (0x28) /* I2C buffer mode control register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CBUFMSK
+@brief I2CBUFMSK register offset
+*/
+#define IOH_I2CBUFMSK (0x2C) /* I2C buffer mode interrupt mask register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CBUFSTA
+@brief I2CBUFSTA register offset
+*/
+#define IOH_I2CBUFSTA (0x30) /* I2C buffer mode status register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CBUFLEV
+@brief I2CBUFLEV register offset
+*/
+#define IOH_I2CBUFLEV (0x34) /* I2C buffer mode level register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CESRFOR
+@brief I2CESRFOR register offset
+*/
+#define IOH_I2CESRFOR (0x38) /* EEPROM software reset mode format register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CESRCTL
+@brief I2CESRCTL register offset
+*/
+#define IOH_I2CESRCTL (0x3C) /* EEPROM software reset mode control register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CESRMSK
+@brief I2CESRMSK register offset
+*/
+#define IOH_I2CESRMSK (0x40) /* EEPROM software reset mode
+ * interrupt mask register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CESRSTA
+@brief I2CESRSTA register offset
+*/
+#define IOH_I2CESRSTA (0x44) /* EEPROM software reset mode status register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CTMR
+@brief I2CTMR register offset
+*/
+#define IOH_I2CTMR (0x48) /* I2C timer register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CSRST
+@brief I2CSRST register offset
+*/
+#define IOH_I2CSRST (0xFC) /* I2C reset register */
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CNF
+@brief I2CNF register offset
+*/
+#define IOH_I2CNF (0xF8) /* I2C noise filter register */
+
+/*! @ingroup I2C_HALLayer
+@def BUS_IDLE_TIMEOUT
+@brief Time out value when waiting for Bus Idle
+*/
+#define BUS_IDLE_TIMEOUT (20)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_I2CCTL_I2CMEN
+@brief Bitmask to enable I2CMEN bit
+*/
+#define IOH_I2CCTL_I2CMEN (0x0080)
+
+/*! @ingroup I2C_HALLayer
+@def TEN_BIT_ADDR_DEFAULT
+@brief Default bits to be added for 10 bit addressing
+*/
+#define TEN_BIT_ADDR_DEFAULT (0xF000)
+
+/*! @ingroup I2C_HALLayer
+@def TEN_BIT_ADDR_MASK
+@brief 10 bit address mask
+*/
+#define TEN_BIT_ADDR_MASK (0xF0)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_START
+@brief Set the start bit in Normal mode
+*/
+#define IOH_START (0x0020)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_ESR_START
+@brief Bitmask to set Start bit in EEPROM Software Reset mode
+*/
+#define IOH_ESR_START (0x0001)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_BUFF_START
+@brief Bitmask to set Start bit in Buffer mode
+*/
+#define IOH_BUFF_START (0x1)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_REPSTART
+@brief Bitmask to set repeated start bit
+*/
+#define IOH_REPSTART (0x0004)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_ACK
+@brief Ack bit position in I2CCTL register
+*/
+#define IOH_ACK (0x0008)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_GETACK
+@brief Mask to extract the ack bit
+*/
+#define IOH_GETACK (0x0001)
+
+/*! @ingroup I2C_HALLayer
+@def CLR_REG
+@brief Mask for register reset
+*/
+#define CLR_REG (0x0)
+/*! @ingroup I2C_HALLayer
+@def I2C_RD
+@brief Set read bit in I2CDR with slave address
+*/
+#define I2C_RD (0x1)
+
+/*! @ingroup I2C_HALLayer
+@def I2CMCF_BIT
+@brief Mask for I2CMCF bit
+*/
+#define I2CMCF_BIT (0x0080)
+
+/*! @ingroup I2C_HALLayer
+@def I2CMIF_BIT
+@brief Mask for I2CMIF bit
+*/
+#define I2CMIF_BIT (0x0002)
+
+/*! @ingroup I2C_HALLayer
+@def I2CMAL_BIT
+@brief Mask for I2CMAL bit
+*/
+#define I2CMAL_BIT (0x0010)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMFI_BIT
+@brief Mask for I2CBMFI bit
+*/
+#define I2CBMFI_BIT (0x0001)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMAL_BIT
+@brief Mask for I2CBMAL bit
+*/
+#define I2CBMAL_BIT (0x0002)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMNA_BIT
+@brief Mask for I2CBMNA bit
+*/
+#define I2CBMNA_BIT (0x0004)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMTO_BIT
+@brief Mask for I2CBMTO bit
+*/
+#define I2CBMTO_BIT (0x0008)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMIS_BIT
+@brief Mask for I2CBMIS bit
+*/
+#define I2CBMIS_BIT (0x0010)
+
+/*! @ingroup I2C_HALLayer
+@def I2CESRFI_BIT
+@brief Mask for I2CESRFI bit
+*/
+#define I2CESRFI_BIT (0X0001)
+
+/*! @ingroup I2C_HALLayer
+@def I2CESRTO_BIT
+@brief Mask for I2CESRTO bit
+*/
+#define I2CESRTO_BIT (0x0002)
+
+/*! @ingroup I2C_HALLayer
+@def I2CESRFIIE_BIT
+@brief Mask for I2CESRFIIE bit
+*/
+#define I2CESRFIIE_BIT (0x1)
+
+/*! @ingroup I2C_HALLayer
+@def I2CESRTOIE_BIT
+@brief Mask for I2CESRTOIE bit
+*/
+#define I2CESRTOIE_BIT (0x2)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMDZ_BIT
+@brief Mask for I2CBMDZ bit
+*/
+#define I2CBMDZ_BIT (0x0040)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMAG_BIT
+@brief Mask for I2CBMAG bit
+*/
+#define I2CBMAG_BIT (0x0020)
+
+/*! @ingroup I2C_HALLayer
+@def I2CMBB_BIT
+@brief Mask for I2CMBB bit
+*/
+#define I2CMBB_BIT (0x0020)
+
+/*! @ingroup I2C_HALLayer
+@def BUFFER_MODE_MASK
+@brief Status bit mask in buffer mode
+*/
+#define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \
+ I2CBMTO_BIT | I2CBMIS_BIT)
+
+/*! @ingroup I2C_HALLayer
+@def I2C_ADDR_MSK
+@brief Mask to get the 8 LSB bits in 10 bit addressing
+*/
+#define I2C_ADDR_MSK (0xFF)
+
+/*! @ingroup I2C_HALLayer
+@def I2C_MSB_2B_MSK
+@brief Mask to get the 2 MSB bits in 10 bit addressing
+*/
+#define I2C_MSB_2B_MSK (0x300)
+
+/*! @ingroup I2C_HALLayer
+@def FAST_MODE_CLK
+@brief Fast mode clock in KHz
+*/
+#define FAST_MODE_CLK (400)
+
+/*! @ingroup I2C_HALLayer
+@def FAST_MODE_EN
+@brief Enable the fast mode
+*/
+#define FAST_MODE_EN (0x0001)
+
+/*! @ingroup I2C_HALLayer
+@def SUB_ADDR_LEN_MAX
+@brief Maximum sub address length
+*/
+#define SUB_ADDR_LEN_MAX (4)
+
+/*! @ingroup I2C_HALLayer
+@def BUF_LEN_MAX
+@brief Maximum buffer length in buffer mode
+*/
+#define BUF_LEN_MAX (32)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_BUFFER_MODE
+@brief To enable the buffer mode
+*/
+#define IOH_BUFFER_MODE (0x1)
+
+/*! @ingroup I2C_HALLayer
+@def EEPROM_SW_RST_MODE
+@brief Mask to enable the EEPROM Software Reset mode
+*/
+#define EEPROM_SW_RST_MODE (0x0002)
+
+/*! @ingroup I2C_HALLayer
+@def NORMAL_INTR_ENBL
+@brief Mask to enable the I2C interrupts in normal mode
+*/
+#define NORMAL_INTR_ENBL (0x0300)
+
+/*! @ingroup I2C_HALLayer
+@def EEPROM_RST_INTR_ENBL
+@brief Mask to enable I2CESRFI, I2CESRTO interrupts
+ in EEPROM Software Reset mode
+*/
+#define EEPROM_RST_INTR_ENBL (I2CESRFIIE_BIT | I2CESRTOIE_BIT)
+
+/*! @ingroup I2C_HALLayer
+@def EEPROM_RST_INTR_DISBL
+@brief Mask to disable interrupts in EEPROM Software Reset mode
+*/
+#define EEPROM_RST_INTR_DISBL (0x0)
+
+/*! @ingroup I2C_HALLayer
+@def BUFFER_MODE_INTR_ENBL
+@brief Mask to enable I2CBMIS,I2CBMTO,I2CBMNA,I2CBMAL,I2CBMFI
+ interrupts in Buffer mode
+*/
+#define BUFFER_MODE_INTR_ENBL (0x001F)
+
+/*! @ingroup I2C_HALLayer
+@def BUFFER_MODE_INTR_DISBL
+@brief Mask to disable all interrupts in Buffer mode
+*/
+#define BUFFER_MODE_INTR_DISBL (0x0)
+
+/*! @ingroup I2C_HALLayer
+@def NORMAL_MODE
+@brief Specifies Normal mode
+*/
+#define NORMAL_MODE (0x0)
+
+/*! @ingroup I2C_HALLayer
+@def BUFFER_MODE
+@brief Specifies Buffer mode
+*/
+#define BUFFER_MODE (0x1)
+
+/*! @ingroup I2C_HALLayer
+@def EEPROM_SR_MODE
+@brief Specifies EEPROM software reset mode
+*/
+#define EEPROM_SR_MODE (0x2)
+
+/*! @ingroup I2C_HALLayer
+@def I2C_TX_MODE
+@brief Specifies Master transmission mode
+*/
+#define I2C_TX_MODE (0x0010)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_BUF_TX
+@brief Specifies Buffer transmission mode
+*/
+#define IOH_BUF_TX (0xFFF7)
+
+/*! @ingroup I2C_HALLayer
+@def IOH_BUF_RD
+@brief Specifies Buffer reception mode
+*/
+#define IOH_BUF_RD (0x0008)
+
+/*! @ingroup I2C_HALLayer
+@def I2C_ERROR_MASK
+@brief Mask for errors in all modes
+*/
+#define I2C_ERROR_MASK (I2CESRTO_EVENT | I2CBMIS_EVENT | I2CBMTO_EVENT | \
+ I2CBMNA_EVENT | I2CBMAL_EVENT | I2CMAL_EVENT)
+
+/*! @ingroup I2C_HALLayer
+@def I2CMAL_EVENT
+@brief MAL bit position in event flag
+*/
+#define I2CMAL_EVENT (0x0001)
+
+/*! @ingroup I2C_HALLayer
+@def I2CMCF_EVENT
+@brief MCF bit position in event flag
+*/
+#define I2CMCF_EVENT (0x0002)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMFI_EVENT
+@brief I2CBMFI bit position in event flag
+*/
+#define I2CBMFI_EVENT (0x0004)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMAL_EVENT
+@brief I2CBMAL bit position in event flag
+*/
+#define I2CBMAL_EVENT (0x0008)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMNA_EVENT
+@brief I2CBMNA bit position in event flag
+*/
+#define I2CBMNA_EVENT (0x0010)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMTO_EVENT
+@brief I2CBMTO bit position in event flag
+*/
+#define I2CBMTO_EVENT (0x0020)
+
+/*! @ingroup I2C_HALLayer
+@def I2CBMIS_EVENT
+@brief I2CBMIS bit position in event flag
+*/
+#define I2CBMIS_EVENT (0x0040)
+
+/*! @ingroup I2C_HALLayer
+@def I2CESRFI_EVENT
+@brief I2CESRFI bit position in event flag
+*/
+#define I2CESRFI_EVENT (0x0080)
+
+/*! @ingroup I2C_HALLayer
+@def I2CESRTO_EVENT
+@brief I2CESRTO bit position in event flag
+*/
+#define I2CESRTO_EVENT (0x0100)
+
+/*
+ * wait queue head
+ */
+
+/*! @ingroup I2C_UtilitiesAPI
+@var ioh_i2c_event
+@brief Wait queue head
+@remarks This global variable is used to synchronize
+ data handling with interrupts
+@see - ioh_i2c_init
+ - ioh_i2c_cb
+*/
+static wait_queue_head_t ioh_i2c_event;
+
+/* Function prototypes */
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_start(struct i2c_algo_ioh_data * adap)
+@brief Function to generate start condition in normal mode
+*/
+static void ioh_i2c_start(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_buff_mode_start(struct i2c_algo_ioh_data * adap)
+@brief Function to generate start condition in buffer mode
+*/
+static void ioh_i2c_buff_mode_start(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_eeprom_swrst_start(struct i2c_algo_ioh_data * adap)
+@brief Function to generate start condition in EEPROM Software
+ Reset mode
+*/
+static void ioh_i2c_eeprom_swrst_start(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_stop(struct i2c_algo_ioh_data *adap)
+@brief Function to generate stop condition in normal mode
+*/
+static void ioh_i2c_stop(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_repstart(struct i2c_algo_ioh_data *adap)
+@brief Function to generate repeated start condition in normal mode
+*/
+static void ioh_i2c_repstart(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_getack(struct i2c_algo_ioh_data *adap)
+@brief Function to confirm ACK/NACK
+*/
+static s32 ioh_i2c_getack(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_sendack(struct i2c_algo_ioh_data *adap)
+@brief Function to send ACK
+*/
+static void ioh_i2c_sendack(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_sendnack(struct i2c_algo_ioh_data *adap)
+@brief Function to send NACK
+*/
+static void ioh_i2c_sendnack(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_wait_for_bus_idle
+ (struct i2c_algo_ioh_data *adap,s32 timeout)
+@brief Function to check the status of bus
+*/
+static s32 ioh_i2c_wait_for_bus_idle(struct i2c_algo_ioh_data *adap,
+ s32 timeout);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn ioh_i2c_wait_for_xfer_complete(struct i2c_algo_ioh_data *adap)
+@brief Function to wait till transfer complete.
+*/
+static s32 ioh_i2c_wait_for_xfer_complete(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_HALLayerAPI
+ @fn ioh_i2c_init(struct i2c_algo_ioh_data * adap)
+ @remarks Implements the hardware initialization of I2C module.
+ The main tasks performed by this method are:
+ - Clear I2CCTL,I2CMOD,I2CBUFFOR,I2CBUFSLV,I2CBUFSUB,I2CBUFMSK,
+ I2CESRFOR,I2CESRMSK registers.
+ - Set I2CMEN in I2CCTL to 1.
+ - Set bus speed based on module parameter.
+ - Enable required interrupts.
+ - Initialize wait queue head.
+ @note This function always returns @ref IOH_I2C_SUCCESS
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval s32
+ - @ref IOH_I2C_SUCCESS Function returns successfully.
+ @see - ioh_i2c_probe
+ - ioh_i2c_resume
+ <hr>
+ */
+s32 ioh_i2c_init(struct i2c_algo_ioh_data *adap)
+{
+ u32 ioh_i2cbc;
+ u32 ioh_i2ctmr;
+ u32 reg_value = 0;
+
+#ifndef FPGA
+ /*reset I2C controller */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CSRST, 0x1);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CSRST, 0x0);
+#endif
+ /* Initialize I2C registers */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CCTL, CLR_REG);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CMOD, CLR_REG);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFFOR, CLR_REG);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFSLV, CLR_REG);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFSUB, CLR_REG);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFMSK, CLR_REG);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CESRFOR, CLR_REG);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CESRMSK, CLR_REG);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CNF, 0x21);
+ IOH_DEBUG
+ ("Cleared the registers IOH_I2CCTL,IOH_I2CMOD,IOH_I2CBUFFOR\n,"
+ "IOH_I2CBUFSLV,IOH_I2CBUFSUB,IOH_I2CBUFMSK,"
+ "\nIOH_I2CESRFOR,IOH_I2CESRMSK\n");
+
+ reg_value |= IOH_I2CCTL_I2CMEN;
+ adap->set_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL,
+ IOH_I2CCTL_I2CMEN);
+
+ ioh_i2c_speed = (ioh_i2c_speed == 400) ? 400 : 100;
+
+ if (ioh_i2c_speed == FAST_MODE_CLK) {
+ reg_value |= FAST_MODE_EN;
+ IOH_DEBUG("Fast mode enabled\n");
+ }
+
+ ioh_i2c_clk = (ioh_i2c_clk <= 0
+ || ioh_i2c_clk > IOH_I2C_MAX_CLK) ? 62500 : ioh_i2c_clk;
+
+ ioh_i2cbc = ((ioh_i2c_clk) + (ioh_i2c_speed * 4)) / (ioh_i2c_speed * 8);
+ /* Set transfer speed in I2CBC */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBC, ioh_i2cbc);
+
+ ioh_i2ctmr = (ioh_i2c_clk) / 8;
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CTMR, ioh_i2ctmr);
+
+ reg_value |= NORMAL_INTR_ENBL; /* Enable interrupts in normal mode */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CCTL, reg_value);
+
+ IOH_DEBUG("In ioh_i2c_init: I2CCTL =%x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+ IOH_DEBUG("In ioh_i2c_init: ioh_i2cbc =%x\n", ioh_i2cbc);
+ IOH_DEBUG("In ioh_i2c_init: ioh_i2ctmr =%x\n", ioh_i2ctmr);
+
+ IOH_DEBUG("Enable interrupts\n");
+ init_waitqueue_head(&ioh_i2c_event);
+ return IOH_I2C_SUCCESS;
+}
+
+/*! @ingroup I2C_HALLayerAPI
+ @fn ioh_i2c_writebytes(struct i2c_adapter *i2c_adap ,
+ struct i2c_msg *msgs, u32 last, u32 first)
+ @remarks Function to write data to I2C bus in normal mode.
+ The main tasks performed by this method are:
+ - Enable transmission mode.
+ - Send out the slave address.
+ - Wait for Bus idle and send out Start signal
+ - Perform data write operation.
+ - Send stop or repeat start as necessary, depending on whether
+ the current message is the last message or not.
+ - Return with number of bytes transferred successfully or
+ the error code
+ @param i2c_adap [@ref IN] contains reference to the struct i2c_adapter
+ @param msgs [@ref IN] contains reference to i2c_msg structure
+ @param last [@ref IN] specifies whether last message or not
+ In the case of compound mode it will be
+ 1 for last message, otherwise 0.
+ @param first [@ref IN] specifies whether first message or not
+ 1 for first message otherwise 0.
+ @retval s32
+ - Number of bytes transferred successfully
+ - @ref IOH_I2C_FAIL @ref ioh_i2c_wait_for_bus_idle,
+ @ref ioh_i2c_wait_for_xfer_complete,
+ @ref ioh_i2c_getack fails
+ - -ERESTARTSYS
+ @ref ioh_i2c_wait_for_xfer_complete was interrupted by a signal
+ @see ioh_i2c_xfer
+ <hr>
+ */
+s32 ioh_i2c_writebytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ u32 last, u32 first)
+{
+
+ struct i2c_algo_ioh_data *adap = i2c_adap->algo_data;
+
+ u8 *buf;
+ u32 length;
+ u32 addr;
+ u32 addr_2_msb;
+ u32 addr_8_lsb;
+ s32 wrcount = IOH_I2C_FAIL;
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+ /* enable master tx */
+ adap->set_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL,
+ I2C_TX_MODE);
+
+ IOH_DEBUG("In ioh_i2c_writebytes : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+ IOH_DEBUG("In ioh_i2c_writebytes : msgs->len = %d\n", length);
+
+ if (first) {
+ if (ioh_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) ==
+ IOH_I2C_FAIL) {
+ return IOH_I2C_FAIL;
+ }
+ }
+
+ if ((msgs->flags & I2C_M_TEN) != false) {
+ addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CDR,
+ (addr_2_msb | TEN_BIT_ADDR_MASK));
+
+ if (first)
+ ioh_i2c_start(adap);
+ if ((ioh_i2c_wait_for_xfer_complete(adap) == IOH_I2C_SUCCESS) &&
+ (ioh_i2c_getack(adap) == IOH_I2C_SUCCESS)) {
+ addr_8_lsb = (addr & I2C_ADDR_MSK);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CDR,
+ (addr_8_lsb));
+
+ } else {
+ ioh_i2c_stop(adap);
+ return IOH_I2C_FAIL;
+ }
+ } else {
+ /* set 7 bit slave address and R/W bit as 0 */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CDR,
+ ((addr) << 1));
+ if (first)
+ ioh_i2c_start(adap);
+ }
+
+ if ((ioh_i2c_wait_for_xfer_complete(adap) == IOH_I2C_SUCCESS) &&
+ (ioh_i2c_getack(adap) == IOH_I2C_SUCCESS)) {
+ for (wrcount = 0; wrcount < length; ++wrcount) {
+ /* write buffer value to I2C data register */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CDR,
+ buf[wrcount]);
+ IOH_DEBUG
+ ("ioh_i2c_writebytes : writing %x to Data register\n",
+ buf[wrcount]);
+
+ if (ioh_i2c_wait_for_xfer_complete(adap) !=
+ IOH_I2C_SUCCESS) {
+ wrcount = IOH_I2C_FAIL;
+ break;
+ }
+
+ IOH_DEBUG("ioh_i2c_wait_for_xfer_complete return %d",
+ IOH_I2C_SUCCESS);
+
+ if (ioh_i2c_getack(adap)) {
+ wrcount = IOH_I2C_FAIL;
+ break;
+ }
+ }
+
+ /* check if this is the last message */
+ if (last)
+ ioh_i2c_stop(adap);
+ else
+ ioh_i2c_repstart(adap);
+ } else {
+ ioh_i2c_stop(adap);
+ }
+
+ IOH_DEBUG(KERN_INFO, "ioh_i2c_writebytes return=%d\n", wrcount);
+
+ return wrcount;
+}
+
+/*! @ingroup I2C_HALLayerAPI
+ @fn ioh_i2c_readbytes(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, u32 last, u32 first)
+ @remarks Function to read data from I2C bus in normal mode.
+ The main tasks performed by this method are:
+ - Enable Reception mode.
+ - Send out the slave address.
+ - Wait for Bus idle and send out Start signal
+ - Perform data reads.
+ - Send stop or repeat start as necessary, depending on whether
+ the current
+ message read is the last message or not
+ - Return with number of bytes read (if successful) or
+ the error code
+ @param i2c_adap [@ref IN] contains reference to the struct i2c_adapter
+ @param msgs [@ref INOUT] contains reference to i2c_msg structure
+ @param last [@ref IN] specifies whether last message or not
+ @param first [@ref IN] specifies whether first message or not
+ @retval s32 - Number of Bytes read successfully
+ - @ref IOH_I2C_FAIL @ref ioh_i2c_wait_for_bus_idle,
+ @ref ioh_i2c_wait_for_xfer_complete,
+ @ref ioh_i2c_getack fails
+ - -ERESTARTSYS
+ @ref ioh_i2c_wait_for_xfer_complete was interrupted by a signal
+ @see ioh_i2c_xfer
+ <hr>
+ */
+s32 ioh_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ u32 last, u32 first)
+{
+
+ struct i2c_algo_ioh_data *adap = i2c_adap->algo_data;
+
+ u8 *buf;
+ u32 count = IOH_I2C_FAIL;
+ u32 length;
+ u32 addr;
+ u32 addr_2_msb;
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+
+ /* enable master reception */
+ adap->clr_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL,
+ I2C_TX_MODE);
+
+ if (first) {
+ if (ioh_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) ==
+ IOH_I2C_FAIL) {
+ return IOH_I2C_FAIL;
+ }
+ }
+
+ if ((msgs->flags & I2C_M_TEN) != false) {
+ addr_2_msb = (((addr & I2C_MSB_2B_MSK) >> 7) | (I2C_RD));
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CDR,
+ (addr_2_msb | TEN_BIT_ADDR_MASK));
+
+ } else {
+ /* 7 address bits + R/W bit */
+ addr = (((addr) << 1) | (I2C_RD));
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CDR, addr);
+ }
+
+ /* check if it is the first message */
+ if (first == true)
+ ioh_i2c_start(adap);
+
+ if ((ioh_i2c_wait_for_xfer_complete(adap) == IOH_I2C_SUCCESS)
+ && (ioh_i2c_getack(adap) == IOH_I2C_SUCCESS)) {
+ IOH_DEBUG("ioh_i2c_wait_for_xfer_complete return %d",
+ IOH_I2C_SUCCESS);
+
+ if (length == 0) {
+
+ ioh_i2c_stop(adap);
+ (void)adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CDR);
+
+ count = length;
+ } else {
+ int read_index = 0;
+ int loop;
+ ioh_i2c_sendack(adap);
+
+ /* Dummy read */
+
+ for (loop = 1; loop < length; loop++) {
+ buf[read_index] =
+ adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CDR);
+
+ if (loop != 1)
+ read_index++;
+
+ if (ioh_i2c_wait_for_xfer_complete(adap) !=
+ IOH_I2C_SUCCESS) {
+ ioh_i2c_stop(adap);
+ return IOH_I2C_FAIL;
+ }
+
+ } /* end for */
+
+ ioh_i2c_sendnack(adap);
+
+ buf[read_index] =
+ adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CDR);
+
+ if (length != 1)
+ read_index++;
+
+ if (ioh_i2c_wait_for_xfer_complete(adap) ==
+ IOH_I2C_SUCCESS) {
+ if (last)
+ ioh_i2c_stop(adap);
+ else
+ ioh_i2c_repstart(adap);
+
+ buf[read_index++] =
+ adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CDR);
+ count = read_index;
+ }
+
+ }
+ } else {
+ ioh_i2c_stop(adap);
+ }
+
+ return count;
+}
+
+/*! @ingroup I2C_HALLayerAPI
+ @fn ioh_i2c_entcb(s32(*ioh_i2c_ptr)(struct i2c_algo_ioh_data *adap))
+ @remarks Function to register call back function.
+ The main tasks performed by this method are:
+ - Validate ioh_i2c_ptr
+ - Update the reference of the callback function in the callback
+ function pointer.
+ @param ioh_i2c_ptr [@ref IN] Contains reference to call back function
+ @retval None
+ @see ioh_i2c_probe
+ <hr>
+ */
+void ioh_i2c_entcb(s32(*ioh_i2c_ptr) (struct i2c_algo_ioh_data *adap))
+{
+ if (ioh_i2c_ptr != NULL) {
+ IOH_DEBUG("value in ioh_i2c_ptr = %p", ioh_i2c_ptr);
+ /* set the handler call back function */
+ ioh_i2c_cbr = ioh_i2c_ptr;
+ IOH_DEBUG("value updated in ioh_i2c_cbr = %p", ioh_i2c_cbr);
+ IOH_DEBUG("Invoked ioh_i2c_entcb successfully");
+
+ }
+}
+
+/*! @ingroup I2C_HALLayerAPI
+ @fn ioh_i2c_handler(int irq,void * pData)
+ @remarks This function implements the interrupt handler for
+ the IOH I2C controller.
+ The main tasks performed by this method are:
+ - Invoke callback function.
+ - Based on return value of callback function,
+ return IRQ_NONE or IRQ_HANDLED
+ @param irq [@ref IN] irq number
+ @param pData [@ref IN] cookie passed back to the handler function
+ @retval irqreturn_t
+ - IRQ_NONE Not our interrupt
+ - IRQ_HANDLED Interrupt serviced
+ @see ioh_i2c_probe
+ <hr>
+ */
+irqreturn_t ioh_i2c_handler(int irq, void *pData)
+{
+ s32 ret = 0;
+ u32 i;
+
+ struct adapter_info *adap_info = (struct adapter_info *)pData;
+ /* invoke the call back */
+
+ if (ioh_i2c_cbr != NULL) {
+ for (i = 0; i < IOH_I2C_MAX_CHN; i++)
+ ret |= (ioh_i2c_cbr) (&adap_info->ioh_i2c_data[i]);
+ } else {
+ IOH_LOG(KERN_ERR, " Call back pointer null ...");
+ }
+
+ IOH_DEBUG("ioh_i2c_cb return = %d\n", ret);
+
+ if (ret == IOH_I2C_EVENT_SET)
+ IOH_DEBUG(" ioh_i2c_handler return IRQ_HANDLED");
+ else
+ IOH_DEBUG("ioh_i2c_handler return IRQ_NONE");
+
+ return (ret == IOH_I2C_EVENT_SET) ? (IRQ_HANDLED) : (IRQ_NONE);
+}
+
+/*! @ingroup I2C_HALLayerAPI
+ @fn ioh_i2c_buffer_read
+ (struct i2c_adapter * i2c_adap,struct i2c_msg *msgs)
+ @remarks Function to read data from I2C bus in buffer mode.
+ The main tasks performed by this method are:
+ - Enable Buffer Mode.
+ - Set timeout interval in I2CTMR register.
+ - Enable buffer mode interrupts.
+ - Set the I2C Slave Address in the I2CBUFSLV register.
+ - Set the number of bytes, transmission mode and
+ sub-address length in I2CBUFFOR register.
+ - Perform the data read.
+ - Disable buffer mode interrupts.
+ @param i2c_adap [@ref IN] contains reference to the struct i2c_adapter
+ @param msgs [@ref INOUT] contains reference to i2c_msg structure
+ @retval s32
+ - @ref IOH_I2C_SUCCESS Function returns successfully
+ - @ref IOH_I2C_FAIL @ref ioh_i2c_wait_for_bus_idle,
+ @ref ioh_i2c_wait_for_xfer_complete,
+ @ref ioh_i2c_getack fails
+ - -ERESTARTSYS
+ @ref ioh_i2c_wait_for_xfer_complete was interrupted by a signal
+ @see ioh_i2c_xfer
+ <hr>
+ */
+s32 ioh_i2c_buffer_read(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs)
+{
+
+ struct i2c_algo_ioh_data *adap = i2c_adap->algo_data;
+
+ u32 loop;
+ u32 rdcount = 0;
+ u32 length;
+ u32 i2cbufsub = 0;
+ u32 addr;
+ u32 i2cbufslv_7_lsb;
+ u32 i2cbufslv_10_9_bit;
+ u32 msglen;
+ /* initialize to invalid length, so that no sub address is tx-ed */
+ u32 subaddrlen = 5;
+ u32 i2cmod_prev;
+ s32 i;
+ u32 time_interval = i2c_adap->timeout;
+ u32 i2ctmr;
+ s32 retvalue = IOH_I2C_FAIL;
+ u8 *buf;
+
+ length = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFMSK,
+ BUFFER_MODE_INTR_ENBL);
+
+ /* get the current value of I2C mod register */
+ i2cmod_prev = adap->readreg((adap->ioh_i2c_base_address), IOH_I2CMOD);
+
+ /* enable buffer mode */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CMOD,
+ IOH_BUFFER_MODE);
+
+ time_interval = (time_interval <= 10) ? (time_interval) : (10);
+
+ /* value of I2CT = (Timeout interval * PCLK frequency)/ 8 */
+ i2ctmr = (time_interval * (ioh_i2c_clk)) / 8;
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CTMR, i2ctmr);
+
+ /* if 10 bit addressing is selected */
+
+ if ((msgs->flags & I2C_M_TEN) != false) {
+ /* get the 8 LSBits */
+ i2cbufslv_7_lsb = (addr & I2C_ADDR_MSK);
+
+ /* get the 2 MSBits */
+ i2cbufslv_10_9_bit = ((addr & I2C_MSB_2B_MSK) << 1);
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFSLV,
+ (TEN_BIT_ADDR_DEFAULT | i2cbufslv_7_lsb |
+ i2cbufslv_10_9_bit));
+ } else {
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFSLV,
+ ((addr & I2C_ADDR_MSK) << 1));
+ }
+
+ /* get sub address length, restrict to 4 bytes max */
+ subaddrlen =
+ (buf[0] <= SUB_ADDR_LEN_MAX) ? (buf[0]) : (SUB_ADDR_LEN_MAX);
+
+ for (i = (subaddrlen - 1); i >= 0; i--) {
+ /* frame the sub address based on the length */
+ i2cbufsub |= (((u32) buf[2 - i]) << (8 * i));
+ }
+
+ msglen = length - (subaddrlen + 1);
+
+ loop = (subaddrlen + 1);
+
+ /* write the sub address to the reg */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFSUB, i2cbufsub);
+ /* clear buffers */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFLEV, CLR_REG);
+
+ rdcount = (msglen <= BUF_LEN_MAX) ? (msglen) : (BUF_LEN_MAX);
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFFOR,
+ ((rdcount << 4) | (IOH_BUF_RD) | (subaddrlen)));
+
+ do {
+ if (ioh_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) ==
+ IOH_I2C_FAIL) {
+ break;
+ }
+
+ ioh_i2c_buff_mode_start(adap);
+
+ IOH_DEBUG("buffer mode start");
+
+ if ((adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CBUFSTA) & I2CBMDZ_BIT) != 0) {
+ IOH_DEBUG("buffer read error 1");
+ break;
+ }
+
+ if (ioh_i2c_wait_for_xfer_complete(adap) == IOH_I2C_FAIL) {
+ IOH_DEBUG("buffer read error2");
+ break;
+ }
+
+ IOH_DEBUG("ioh_i2c_wait_for_xfer_complete return %d",
+ IOH_I2C_SUCCESS);
+
+ retvalue = rdcount;
+
+ for (; rdcount > 0; rdcount--, loop++) {
+ buf[loop] =
+ adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CDR);
+
+ }
+ } while (0);
+
+ /* disable buffer mode interrupts */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFMSK,
+ BUFFER_MODE_INTR_DISBL);
+ /* restore the I2CMOD register */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CMOD, i2cmod_prev);
+
+ return retvalue;
+}
+
+/*! @ingroup I2C_HALLayerAPI
+ @fn ioh_i2c_buffer_write
+ (struct i2c_adapter * i2c_adap,struct i2c_msg * msgs)
+ @remarks Function to write data to I2C bus in buffer mode.
+ The main tasks performed by this method are:
+ - Enable Buffer Mode.
+ - Set timeout interval in I2CTMR register.
+ - Enable buffer mode interrupts.
+ - Set the I2C Slave Address in the I2CBUFSLV register.
+ - Set the number of bytes, transmission mode and
+ subaddress length in I2CBUFFOR register.
+ - Perform data transfer.
+ - Disable the buffer mode interrupts.
+ @param i2c_adap [@ref IN] contains reference to the struct i2c_adapter
+ @param msgs [@ref INOUT] contains reference to i2c_msg structure
+ @retval s32
+ - @ref IOH_I2C_SUCCESS Function returns successfully
+ - @ref IOH_I2C_FAIL @ref ioh_i2c_wait_for_bus_idle,
+ @ref ioh_i2c_wait_for_xfer_complete,
+ @ref ioh_i2c_getack fails
+ - -ERESTARTSYS
+ @ref ioh_i2c_wait_for_xfer_complete was interrupted by a signal
+ @see ioh_i2c_xfer
+ <hr>
+ */
+s32 ioh_i2c_buffer_write(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs)
+{
+ struct i2c_algo_ioh_data *adap = i2c_adap->algo_data;
+
+ u32 loop = 0;
+ u32 wrcount = 0;
+ u32 msglen;
+ u32 i2cbufsub = 0;
+ u32 addr;
+ u32 i2cbufslv_7_lsb;
+ u32 i2cbufslv_10_9_bit;
+
+ /* initialize to invalid length, so that no sub address is tx-ed */
+ u32 subaddrlen = 5;
+ u32 i2cmod_prev;
+ s32 i;
+ u32 time_interval = i2c_adap->timeout;
+ u32 i2ctmr;
+ s32 retvalue = IOH_I2C_FAIL;
+ u8 *buf;
+
+ msglen = msgs->len;
+ buf = msgs->buf;
+ addr = msgs->addr;
+
+ /* get the current value of I2C mod register */
+ i2cmod_prev = adap->readreg((adap->ioh_i2c_base_address), IOH_I2CMOD);
+ /* enable buffer mode */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CMOD,
+ IOH_BUFFER_MODE);
+
+ time_interval = (time_interval <= 10) ? (time_interval) : (10);
+ /* value of I2CT = (Timeout interval * PCLK frequency)/ 8 */
+ i2ctmr = (time_interval * (ioh_i2c_clk)) / 8;
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CTMR, i2ctmr);
+
+ /* enable buffer mode interrupts */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFMSK,
+ BUFFER_MODE_INTR_ENBL);
+
+ /* if 10 bit addressing is selected */
+
+ if ((msgs->flags & I2C_M_TEN) != false) {
+ IOH_DEBUG("ioh_i2c_buffer_write...ten bit addressing");
+ /* get the 8 LSBits */
+ i2cbufslv_7_lsb = (addr & I2C_ADDR_MSK);
+
+ /* get the 2 MSBits */
+ i2cbufslv_10_9_bit = ((addr & I2C_MSB_2B_MSK) << 1);
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFSLV,
+ (TEN_BIT_ADDR_DEFAULT | i2cbufslv_7_lsb |
+ i2cbufslv_10_9_bit));
+ } else {
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFSLV,
+ ((addr & I2C_ADDR_MSK) << 1));
+
+ }
+
+ /* get sub address length, restrict to 4 bytes max */
+ subaddrlen =
+ (buf[0] <= SUB_ADDR_LEN_MAX) ? (buf[0]) : (SUB_ADDR_LEN_MAX);
+
+ for (i = (subaddrlen - 1); i >= 0; i--) {
+ /* frame the sub address based on the length */
+ i2cbufsub |= (((u32) buf[2 - i]) << (8 * i));
+ }
+
+ /* subaddrlen bytes + the 1st field */
+ loop = subaddrlen + 1;
+
+ msglen = msglen - loop;
+
+ /* write the sub address to the reg */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFSUB, i2cbufsub);
+
+ /* clear buffers */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFLEV, CLR_REG);
+
+ msglen = (msglen < BUF_LEN_MAX) ? (msglen) : (BUF_LEN_MAX);
+
+ for (wrcount = 0; wrcount < msglen; wrcount++) {
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CDR,
+ buf[loop]);
+ IOH_DEBUG("Buffer mode %x", (buf[loop] & 0xff));
+ loop++;
+ }
+
+ /* set the number of bytes, transmission mode and sub address length */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFFOR,
+ ((((wrcount << 4) & (IOH_BUF_TX)) | (subaddrlen))));
+
+ do {
+ if ((ioh_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT)) ==
+ IOH_I2C_FAIL) {
+ break;
+ }
+
+ /* issue start bits */
+ ioh_i2c_buff_mode_start(adap);
+
+ if (((adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CBUFSTA)) & (I2CBMDZ_BIT |
+ I2CBMAG_BIT)) != false) {
+ break;
+ }
+
+ if (ioh_i2c_wait_for_xfer_complete(adap) == IOH_I2C_FAIL)
+ break;
+
+ IOH_DEBUG("ioh_i2c_wait_for_xfer_complete return %d",
+ IOH_I2C_SUCCESS);
+ retvalue = wrcount;
+ } while (0);
+
+ /* disable buffer mode interrupts */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFMSK,
+ BUFFER_MODE_INTR_DISBL);
+ /* restore the I2CMOD register */
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CMOD, i2cmod_prev);
+
+ return retvalue;
+}
+
+/*! @ingroup I2C_HALLayerAPI
+ @fn ioh_i2c_eeprom_sw_reset
+ (struct i2c_adapter * i2c_adap,struct i2c_msg *msgs)
+ @remarks Function for triggering EEPROM software reset.
+ The main tasks performed by this method are:
+ - Enable EEPROM software reset mode.
+ - Enable the required interrupts.
+ - Update timeout value in I2CTMR register.
+ - Invoke @ref ioh_i2c_eeprom_swrst_start to
+ send software reset pattern.
+ - Disable interrupts.
+ @param i2c_adap [@ref IN] contains reference to the struct i2c_adapter
+ @param msgs [@ref IN] contains reference to i2c_msg structure
+ @retval s32
+ - @ref IOH_I2C_SUCCESS Function returns successfully
+ - i@ref IOH_I2C_FAIL @ref ioh_i2c_wait_for_bus_idle,
+ @ref ioh_i2c_wait_for_xfer_complete,
+ - -ERESTARTSYS
+ @ref ioh_i2c_wait_for_xfer_complete was interrupted by a signal
+ @see ioh_i2c_xfer
+ <hr>
+ */
+s32 ioh_i2c_eeprom_sw_reset(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs)
+{
+
+ struct i2c_algo_ioh_data *adap = i2c_adap->algo_data;
+
+ u32 time_interval = i2c_adap->timeout;
+ u32 i2ctmr;
+ u32 i2cmod_prev;
+ u32 ioh_pattern;
+
+ s32 ret_val = IOH_I2C_FAIL; /* init return value to error */
+
+ /* get the current value of I2C mod register */
+ i2cmod_prev = adap->readreg((adap->ioh_i2c_base_address), IOH_I2CMOD);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CMOD, CLR_REG);
+ adap->set_reg_bit((adap->ioh_i2c_base_address), IOH_I2CMOD,
+ EEPROM_SW_RST_MODE);
+
+ IOH_DEBUG("ioh_i2c_eeprom_sw_reset : I2CMOD %x\n",
+ adap->readreg((adap->ioh_i2c_base_address), IOH_I2CMOD));
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CESRMSK,
+ EEPROM_RST_INTR_ENBL);
+
+ time_interval = (time_interval <= 10) ? (time_interval) : (10);
+
+ /* value of I2CT = (Timeout interval * PCLK frequency)/ 8 */
+ i2ctmr = (time_interval * (ioh_i2c_clk)) / 8;
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CTMR, i2ctmr);
+
+ /* get the EEPROM reset pattern */
+ ioh_pattern = (u32) (*(msgs->buf));
+
+ /* mode 1 & 2 are used for buffer mode selection */
+ ioh_pattern -= 2;
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CESRFOR,
+ ioh_pattern);
+
+ IOH_DEBUG("ioh_i2c_eeprom_sw_reset : I2CESRFOR %x\n",
+ adap->readreg((adap->ioh_i2c_base_address), IOH_I2CESRFOR));
+
+ if (ioh_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) ==
+ IOH_I2C_SUCCESS) {
+
+ ioh_i2c_eeprom_swrst_start(adap);
+ ret_val = ioh_i2c_wait_for_xfer_complete(adap);
+
+ IOH_DEBUG("ioh_i2c_wait_for_xfer_complete return =%d\n",
+ ret_val);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CMOD,
+ i2cmod_prev);
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CESRMSK,
+ EEPROM_RST_INTR_DISBL);
+ }
+
+ IOH_DEBUG("ioh_i2c_eeprom_sw_reset return=%d\n", ret_val);
+
+ return ret_val;
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_cb(struct i2c_algo_ioh_data * adap)
+ @remarks Interrupt handler Call back function.
+ The main tasks performed by this method are:
+ - Get the current operation mode.
+ - For the current mode ,check if any of the required interrupt
+ bits are set.
+ - Invoke wake_up_interruptible function to unblock the functions
+ waiting for these events.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval s32
+ - @ref IOH_I2C_EVENT_SET Valid I2C event recognized and flagged
+ - @ref IOH_I2C_EVENT_NONE No valid I2C event
+ @see ioh_i2c_probe
+ <hr>
+ */
+s32 ioh_i2c_cb(struct i2c_algo_ioh_data *adap)
+{
+ u32 reg_val;
+ u32 i2c_mode;
+ u32 i2c_interrupt = false;
+
+ reg_val = adap->readreg((adap->ioh_i2c_base_address), IOH_I2CMOD);
+ /* get the current mode of operation */
+ i2c_mode = reg_val & (BUFFER_MODE | EEPROM_SR_MODE);
+
+ switch (i2c_mode) {
+
+ case NORMAL_MODE:
+ {
+ reg_val =
+ adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CSR);
+ reg_val &= (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT);
+
+ if (reg_val != 0) {
+
+ if (I2CMAL_BIT & reg_val) {
+ adap->ioh_i2c_event_flag |=
+ I2CMAL_EVENT;
+ }
+
+ if (I2CMCF_BIT & reg_val) {
+ adap->ioh_i2c_event_flag |=
+ I2CMCF_EVENT;
+ }
+
+ /* clear the applicable bits */
+ adap->clr_reg_bit((adap->ioh_i2c_base_address),
+ IOH_I2CSR, reg_val);
+
+ IOH_DEBUG("ioh_i2c_cb : IOH_I2CSR = %x\n",
+ (adap->
+ readreg(adap->ioh_i2c_base_address,
+ IOH_I2CSR)));
+
+ i2c_interrupt = true;
+ }
+
+ break;
+ }
+
+ case BUFFER_MODE:
+ {
+ reg_val =
+ adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CBUFSTA);
+ reg_val &= BUFFER_MODE_MASK;
+ if (reg_val != 0) {
+ /* there is a co-relation between the buffer
+ * mode interrupt flags' bit */
+ /* positions and the flag positions in event
+ * flag. for e.g. I2CBMFI is at position */
+ /* 0 in the I2CBUFSTA register. its position
+ * in the event flag is 2, hence left shifting
+ */
+ adap->ioh_i2c_event_flag |= ((reg_val) << 2);
+
+ /* clear the applicable bits */
+ adap->clr_reg_bit((adap->ioh_i2c_base_address),
+ IOH_I2CBUFSTA, reg_val);
+
+ IOH_DEBUG("ioh_i2c_cb : IOH_I2CBUFSTA = %x\n",
+ (adap->
+ readreg(adap->ioh_i2c_base_address,
+ IOH_I2CBUFSTA)));
+
+ i2c_interrupt = true;
+ }
+
+ break;
+
+ }
+
+ case EEPROM_SR_MODE:
+ {
+ reg_val =
+ adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CESRSTA);
+ reg_val &= (I2CESRFI_BIT | I2CESRTO_BIT);
+ if (reg_val != 0) {
+
+ adap->ioh_i2c_event_flag |= ((reg_val) << 7);
+
+ /* clear the applicable bits */
+ adap->clr_reg_bit((adap->ioh_i2c_base_address),
+ IOH_I2CESRSTA, reg_val);
+
+ IOH_DEBUG("ioh_i2c_cb : IOH_I2CESRSTA = %x\n",
+ (adap->
+ readreg(adap->ioh_i2c_base_address,
+ IOH_I2CESRSTA)));
+
+ i2c_interrupt = true;
+ }
+
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ } /* end switch */
+
+ if (i2c_interrupt == true)
+ wake_up_interruptible(&ioh_i2c_event);
+
+ return ((i2c_interrupt ==
+ true) ? (IOH_I2C_EVENT_SET) : (IOH_I2C_EVENT_NONE));
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_start(struct i2c_algo_ioh_data * adap)
+ @remarks The main tasks performed by this method are:
+ - Generate I2C start condition in normal mode
+ by setting I2CCTL.I2CMSTA to 1.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval None
+ @see - ioh_i2c_readbytes
+ - ioh_i2c_writebytes
+ <hr>
+ */
+static void ioh_i2c_start(struct i2c_algo_ioh_data *adap)
+{
+ IOH_DEBUG("In ioh_i2c_start : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+ adap->set_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL, IOH_START);
+ IOH_DEBUG(" Invoke ioh_i2c_start successfully \n");
+ IOH_DEBUG("In ioh_i2c_start : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_buff_mode_start(struct i2c_algo_ioh_data * adap)
+ @remarks The main tasks performed by this method are:
+ - Generate I2C start condition in buffer mode
+ by setting I2CBUFCTL.I2CBMSTA to 1.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval None
+ @see - ioh_i2c_buffer_read
+ - ioh_i2c_buffer_write
+ <hr>
+ */
+static void ioh_i2c_buff_mode_start(struct i2c_algo_ioh_data *adap)
+{
+ IOH_DEBUG("In ioh_i2c_buff_mode_start : I2CBUFCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CBUFCTL)));
+ adap->set_reg_bit((adap->ioh_i2c_base_address), IOH_I2CBUFCTL,
+ IOH_BUFF_START);
+
+ IOH_DEBUG(" Invoke ioh_i2c_buff_mode_start successfully \n");
+ IOH_DEBUG("In ioh_i2c_buff_mode_start : I2CBUFCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CBUFCTL)));
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_eeprom_swrst_start(struct i2c_algo_ioh_data * adap)
+ @remarks The main tasks performed by this method are:
+ - Generate I2C start condition in EEPROM sw reset mode
+ by setting I2CESRCTL.I2CSTA to 1.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval None
+ @see ioh_i2c_eeprom_sw_reset
+ <hr>
+ */
+static void ioh_i2c_eeprom_swrst_start(struct i2c_algo_ioh_data *adap)
+{
+ IOH_DEBUG("In ioh_i2c_eeprom_swrst_start : I2CESRCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CESRCTL)));
+ adap->set_reg_bit((adap->ioh_i2c_base_address), IOH_I2CESRCTL,
+ IOH_ESR_START);
+
+ IOH_DEBUG(" Invoked ioh_i2c_eeprom_swrst_start successfully\n");
+ IOH_DEBUG("In ioh_i2c_eeprom_swrst_start : I2CESRCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CESRCTL)));
+
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_stop(struct i2c_algo_ioh_data *adap)
+ @remarks Function to generate stop condition in normal mode.
+ The main tasks performed by this method are:
+ - Generate I2C stop condition by setting I2CCTL.I2CMSTA to 0.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval None
+ @see - ioh_i2c_readbytes
+ - ioh_i2c_writebytes
+ <hr>
+ */
+static void ioh_i2c_stop(struct i2c_algo_ioh_data *adap)
+{
+ IOH_DEBUG("In ioh_i2c_stop : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+ /* clear the start bit */
+ adap->clr_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL, IOH_START);
+ IOH_DEBUG(" Invoke ioh_i2c_stop successfully \n");
+ IOH_DEBUG("In ioh_i2c_stop : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_repstart(struct i2c_algo_ioh_data *adap)
+ @remarks Function to generate repeated start condition in normal mode.
+ The main tasks performed by this method are:
+ - Generate repeated start condition by setting using
+ I2CCTL.I2CRSTA to 1.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval None
+ @see - ioh_i2c_readbytes
+ - ioh_i2c_writebytes
+ <hr>
+ */
+static void ioh_i2c_repstart(struct i2c_algo_ioh_data *adap)
+{
+ IOH_DEBUG("In ioh_i2c_repstart : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+ adap->set_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL,
+ IOH_REPSTART);
+
+ IOH_DEBUG(" Invoke ioh_i2c_repstart successfully \n");
+ IOH_DEBUG("In ioh_i2c_repstart : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_getack(struct i2c_algo_ioh_data *adap)
+ @remarks Function to confirm ACK/NACK.
+ The main tasks performed by this method are:
+ - Get the ACK status from I2CSR.
+ - Return success if ACK received or failure otherwise.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval s32
+ - @ref IOH_I2C_SUCCESS Acknowledgement was received.
+ - @ref IOH_I2C_FAIL No acknowledgement received.
+ @see - ioh_i2c_readbytes
+ - ioh_i2c_writebytes
+ <hr>
+ */
+static s32 ioh_i2c_getack(struct i2c_algo_ioh_data *adap)
+{
+ u32 reg_val;
+ reg_val =
+ (adap->readreg((adap->ioh_i2c_base_address), IOH_I2CSR) &
+ IOH_GETACK);
+
+ if (reg_val == 0)
+ IOH_DEBUG("ioh_i2c_getack : return%d \n", IOH_I2C_SUCCESS);
+ else
+ IOH_DEBUG("ioh_i2c_getack : return%d \n", IOH_I2C_FAIL);
+
+ return (((reg_val) == 0) ? (IOH_I2C_SUCCESS) : (IOH_I2C_FAIL));
+
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_sendack(struct i2c_algo_ioh_data *adap)
+ @remarks Function to send ACK.
+ The main tasks performed by this method are:
+ - Clear the I2C TXAK bit in I2CCTL register .
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval None
+ @see ioh_i2c_readbytes
+ <hr>
+ */
+static void ioh_i2c_sendack(struct i2c_algo_ioh_data *adap)
+{
+ IOH_DEBUG("In ioh_i2c_sendack : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+ adap->clr_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL, IOH_ACK);
+
+ IOH_DEBUG("Invoke ioh_i2c_sendack successfully\n");
+ IOH_DEBUG("In ioh_i2c_sendack : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_sendnack(struct i2c_algo_ioh_data *adap)
+ @remarks Function to send NACK.
+ The main tasks performed by this method are:
+ - Set the I2C TXAK bit in I2CCTL register .
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval None
+ @see ioh_i2c_readbytes
+ <hr>
+ */
+static void ioh_i2c_sendnack(struct i2c_algo_ioh_data *adap)
+{
+ IOH_DEBUG("In ioh_i2c_sendnack : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+ adap->set_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL, IOH_ACK);
+ IOH_DEBUG("Invoke ioh_i2c_sendnack successfully\n");
+ IOH_DEBUG("In ioh_i2c_sendnack : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_wait_for_bus_idle
+ (struct i2c_algo_ioh_data *adap,s32 timeout)
+ @remarks Function to check the status of bus.
+ The main tasks performed by this method are:
+ - Get the status of Bus Busy.
+ - If bus is busy sleep for 1 msec and again check.
+ - Repeat until bus is free or timeout happens.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @param timeout [@ref IN] waiting time counter (us)
+ @retval s32
+ - @ref IOH_I2C_SUCCESS The function returns successfully.
+ - @ref IOH_I2C_FAIL The bus is still idle.
+ @see - ioh_i2c_readbytes
+ - ioh_i2c_writebytes
+ - ioh_i2c_buffer_read
+ - ioh_i2c_buffer_write
+ - ioh_i2c_eeprom_sw_reset
+ <hr>
+ */
+static s32 ioh_i2c_wait_for_bus_idle(struct i2c_algo_ioh_data *adap,
+ s32 timeout)
+{
+ u32 reg_value;
+
+ /* get the status of bus busy */
+ reg_value =
+ (adap->readreg((adap->ioh_i2c_base_address), IOH_I2CSR) &
+ (I2CMBB_BIT));
+
+ while ((timeout != 0) && (reg_value != 0)) {
+ msleep(1); /* wait for 100 ms */
+ reg_value =
+ (adap->readreg((adap->ioh_i2c_base_address),
+ IOH_I2CSR) & (I2CMBB_BIT));
+ timeout--;
+ }
+
+ IOH_DEBUG("In ioh_i2c_wait_for_bus_idle : I2CSR = %x\n",
+ adap->readreg((adap->ioh_i2c_base_address), IOH_I2CSR));
+
+ if (timeout == 0) {
+ IOH_LOG(KERN_ERR, "ioh_i2c_wait_for_bus_idle :return%d\n",
+ IOH_I2C_FAIL);
+ } else {
+ IOH_DEBUG("ioh_i2c_wait_for_bus_idle : return %d\n",
+ IOH_I2C_SUCCESS);
+ }
+
+ return ((timeout <= 0) ? (IOH_I2C_FAIL) : (IOH_I2C_SUCCESS));
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_wait_for_xfer_complete(struct i2c_algo_ioh_data * adap)
+ @remarks This functions initiates a wait for the transfer complete event
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval s32
+ - @ref IOH_I2C_SUCCESS Function returns successfully.
+ - @ref IOH_I2C_FAIL Any error occurs.
+ - -ERESTARTSYS wait_event_interruptible_timeout
+ API was interrupted
+ @see - ioh_i2c_readbytes
+ - ioh_i2c_writebytes
+ - ioh_i2c_buffer_read
+ - ioh_i2c_buffer_write
+ - ioh_i2c_eeprom_sw_reset
+ <hr>
+*/
+static s32 ioh_i2c_wait_for_xfer_complete(struct i2c_algo_ioh_data *adap)
+{
+
+ u32 temp_flag;
+ s32 ret = IOH_I2C_FAIL;
+ ret =
+ wait_event_interruptible_timeout(ioh_i2c_event,
+ (adap->ioh_i2c_event_flag != 0),
+ msecs_to_jiffies(50));
+
+ IOH_DEBUG
+ ("adap->ioh_i2c_event_flag in ioh_i2c_wait_for_xfer_complete=%x",
+ adap->ioh_i2c_event_flag);
+ temp_flag = adap->ioh_i2c_event_flag;
+ adap->ioh_i2c_event_flag = 0;
+
+ if (ret == 0) {
+ IOH_LOG(KERN_ERR, "ioh_i2c_wait_for_xfer_complete : Timeout\n");
+ } else if (ret < 0) {
+ IOH_LOG(KERN_ERR,
+ "ioh_i2c_wait_for_xfer_complete failed : "
+ "Interrupted by other signal\n");
+ ret = -ERESTARTSYS;
+ } else if ((temp_flag & I2C_ERROR_MASK) == 0) {
+ ret = IOH_I2C_SUCCESS;
+ } else {
+ IOH_LOG(KERN_ERR,
+ "ioh_i2c_wait_for_xfer_complete failed : "
+ "Error in transfer\n");
+ }
+
+ IOH_DEBUG(KERN_ERR, "ioh_i2c_wait_for_xfer_complete returns %d\n", ret);
+
+ return ret;
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_writereg(u32 addr,u32 offset,u32 val)
+ @remarks Function for writing data to register.
+ The main tasks performed by this method are:
+ - Compute the target address by adding the offset to
+ the base address.
+ - Write the specified value to the target address.
+ @param addr [@ref IN] Base address for the I2C channel
+ @param offset [@ref IN] offset for the register
+ @param val [@ref IN] Value to be written
+ @retval None
+ @see ioh_i2c_probe
+ <hr>
+ */
+void ioh_i2c_writereg(u32 addr, u32 offset, u32 val)
+{
+ IOH_WRITE_LONG(val, (addr + offset));
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_readreg(u32 addr,u32 offset)
+ @remarks Function for reading data from register.
+ The main tasks performed by this method are:
+ - Compute the target address by adding the offset to
+ the base address.
+ - Read the register value and return the same.
+ @param addr [@ref IN] Base address for the I2C channel
+ @param offset [@ref IN] offset for the register
+ @retval u32
+ The content of the register that is read.
+ @see ioh_i2c_probe
+ <hr>
+ */
+u32 ioh_i2c_readreg(u32 addr, u32 offset)
+{
+ u32 ret;
+ ret = IOH_READ_LONG(addr + offset);
+ return ret;
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_setbit(u32 addr,u32 offset,u32 bitmask)
+ @remarks Function to set particular bit in register.
+ The main tasks performed by this method are:
+ - Compute the target address by adding the offset
+ to the base address.
+ - Read the register value at the target address.
+ - Perform logical OR with bitmask and write back
+ to the target address.
+ @param addr [@ref IN] Base address for the I2C channel
+ @param offset [@ref IN] offset for the register
+ @param bitmask [@ref IN] bit position
+ @retval None
+ @see ioh_i2c_probe
+ <hr>
+ */
+void ioh_i2c_setbit(u32 addr, u32 offset, u32 bitmask)
+{
+ IOH_WRITE_LONG(((IOH_READ_LONG(addr + offset)) | (bitmask)),
+ (addr + offset));
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_clrbit(u32 addr,u32 off,u32 bitmask)
+ @remarks Function to reset particular bit in register.
+ The main tasks performed by this method are:
+ - Compute the target address by adding the offset
+ to the base address.
+ - Read the register value at the target address.
+ - Perform logical AND with bitmask and write back
+ to the target address.
+ @param addr [@ref IN] Base address for the I2C channel
+ @param offset [@ref IN] offset for the register
+ @param bitmask [@ref IN] bit position
+ @retval None
+ @see ioh_i2c_probe
+ <hr>
+ */
+void ioh_i2c_clrbit(u32 addr, u32 offset, u32 bitmask)
+{
+ IOH_WRITE_LONG(((IOH_READ_LONG(addr + offset)) & (~(bitmask))),
+ (addr + offset));
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_disbl_int(struct i2c_algo_ioh_data * adap)
+ @remarks Function to disable IOH I2C interrupts.
+ The main tasks performed by this method are:
+ - Disable the following interrupts:
+ MAL,MCF,I2CESRFI,I2CESRTO,I2CBMIS,I2CBMTO,I2CBMNA,
+ I2CBMAL and I2CBMFI.
+ @param adap [@ref IN] Contains reference to struct i2c_algo_ioh_data
+ @retval None
+ @see - ioh_i2c_remove
+ - ioh_i2c_suspend
+ <hr>
+*/
+void ioh_i2c_disbl_int(struct i2c_algo_ioh_data *adap)
+{
+
+ adap->clr_reg_bit((adap->ioh_i2c_base_address), IOH_I2CCTL,
+ NORMAL_INTR_ENBL);
+
+ IOH_DEBUG("ioh_i2c_disbl_int : I2CCTL = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CCTL)));
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CESRMSK,
+ EEPROM_RST_INTR_DISBL);
+
+ IOH_DEBUG("ioh_i2c_disbl_int : IOH_I2CESRMSK = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CESRMSK)));
+
+ adap->writereg((adap->ioh_i2c_base_address), IOH_I2CBUFMSK,
+ BUFFER_MODE_INTR_DISBL);
+
+ IOH_DEBUG("ioh_i2c_disbl_int : IOH_I2CBUFMSK = %x\n",
+ (adap->readreg(adap->ioh_i2c_base_address, IOH_I2CBUFMSK)));
+
+}
diff -urN linux-2.6.33.1/drivers/i2c/busses/pch_i2c_hal.h topcliff-2.6.33.1/drivers/i2c/busses/pch_i2c_hal.h
--- linux-2.6.33.1/drivers/i2c/busses/pch_i2c_hal.h 1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/busses/pch_i2c_hal.h 2010-03-23 10:40:18.000000000 +0900
@@ -0,0 +1,337 @@
+#ifndef __IOH_I2C_HAL_H__
+#define __IOH_I2C_HAL_H__
+/*!
+* @file ioh_i2c_hal.h
+* @brief This file provides the function prototypes and macros to the I2C module.
+* @version 0.95
+* @section
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+* History:
+* Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+* All rights reserved.
+*
+* created:
+* WIPRO 02/20/2009
+* modified:
+* WIPRO 05/21/2009
+*
+*/
+
+/*! @defgroup I2C*/
+
+/*! @defgroup I2C_Global
+@ingroup I2C
+@brief This group describes the global entities within
+ the module.
+@remarks This group includes all the global data structures
+ used within the modules. These are mainly used to
+ store the device related information which is used
+ through out the module.
+<hr>
+*/
+
+/*! @defgroup I2C_PCILayer
+@ingroup I2C
+@brief This group describes the PCI layer interface
+ functionalities.
+@remarks This group contains the functions and data structures
+ that are used to interface the module with PCI Layer
+ subsystem of the Kernel.
+<hr>
+*/
+
+/*! @defgroup I2C_InterfaceLayer
+@ingroup I2C
+@brief This group describes the Driver interface functionalities.
+@remarks This group contains the data structures and functions used
+ to interface the module driver with the kernel subsystem.
+<hr>
+*/
+
+/*! @defgroup I2C_HALLayer
+@ingroup I2C
+@brief This group describes the hardware specific functionalities.
+@remarks This group contains the functions and data structures used
+ by the module to communicate with the hardware. These
+ functions are device specific and designed according to the
+ device specifications.
+<hr>
+*/
+
+/*! @defgroup I2C_Utilities
+@ingroup I2C
+@brief This group describes the utility functionalities.
+@remarks This group contains the functions and data structures used
+ to assist the other functionalities in their operations.
+<hr>
+*/
+
+/*! @defgroup I2C_PCILayerAPI
+@ingroup I2C_PCILayer
+@brief This group contains the API(functions) used as the PCI
+ interface between the Kernel subsystem and the module.
+<hr>
+*/
+
+/*! @defgroup I2C_PCILayerFacilitators
+@ingroup I2C_PCILayer
+@brief This group contains the data structures used by the PCI
+ Layer APIs for their functionalities.
+<hr>
+*/
+
+/*! @defgroup I2C_InterfaceLayerAPI
+@ingroup I2C_InterfaceLayer
+@brief This group contains the API(functions) used as the Driver
+ interface between the Kernel subsystem and the module.
+<hr>
+*/
+
+/*! @defgroup I2C_InterfaceLayerFacilitators
+@ingroup I2C_InterfaceLayer
+@brief This group contains the data structures used by the Driver
+ interface APIs for their functionalities.
+<hr>
+*/
+
+/*! @defgroup I2C_HALLayerAPI
+@ingroup I2C_HALLayer
+@brief This group contains the APIs(functions) used to interact with
+ the hardware. These APIs act as an interface between the
+ hardware and the other driver functions.
+<hr>
+*/
+
+/*! @defgroup I2C_UtilitiesAPI
+@ingroup I2C_Utilities
+@brief This group contains the APIs(functions) used by other functions.
+<hr>
+*/
+
+/*includes*/
+#include <linux/irqreturn.h>
+
+/*! @ingroup I2C_Global
+@def IOH_I2C_SUCCESS
+@brief Success status code
+*/
+#define IOH_I2C_SUCCESS (0)
+
+/*! @ingroup I2C_Global
+@def IOH_I2C_FAIL
+@brief Error status code
+*/
+#define IOH_I2C_FAIL (-1)
+
+/*! @ingroup I2C_Global
+@def IOH_I2C_MAX_CHN
+@brief Maximum I2C channels available
+*/
+#define IOH_I2C_MAX_CHN (1)
+
+/*! @ingroup I2C_Global
+@def IOH_I2C_EVENT_SET
+@brief I2C Interrupt Event Set Status
+*/
+#define IOH_I2C_EVENT_SET (0)
+
+/*! @ingroup I2C_Global
+@def IOH_I2C_EVENT_NONE
+@brief I2C Interrupt Event Clear Status
+*/
+#define IOH_I2C_EVENT_NONE (1)
+
+/*! @ingroup I2C_Global
+@def IOH_I2C_MAX_CLK
+@brief Maximum peripheral Clock speed supported in MHz
+*/
+#define IOH_I2C_MAX_CLK (100000)
+
+
+/* flag for Buffer mode enable */
+#define IOH_BUFFER_MODE_ENABLE (0x0002)
+
+/* flag for EEPROM SW RST enable */
+#define IOH_EEPROM_SW_RST_MODE_ENABLE (0x0008)
+
+/* for mode selection */
+#define I2C_MODE_SEL (0x711)
+
+/*structures*/
+/*! @ingroup I2C_HALLayer
+@struct i2c_algo_ioh_data
+@brief This structure contains references to methods implementing
+ I2C driver functionalities.
+@note The concerned details should be provided during
+ the data transfer.
+@see - ioh_i2c_init
+ - ioh_i2c_entcb
+ - ioh_i2c_cb
+ - ioh_i2c_disbl_int
+*/
+
+struct i2c_algo_ioh_data {
+
+ struct adapter_info *p_adapter_info;
+ /**< stores the reference to adapter_info structure*/
+
+ struct i2c_adapter ioh_i2c_adapter;
+ /**< stores the reference to i2c_adapter structure*/
+
+ u32 ioh_i2c_base_address; /**< specifies the remapped base address*/
+ int ioh_i2c_buff_mode_en; /**< specifies if buffer mode is enabled*/
+ u32 ioh_i2c_event_flag; /**< specifies occurrence of interrupt events*/
+
+ bool ioh_i2c_xfer_in_progress;
+ /**< specifies whether the transfer is completed */
+
+ void (*writereg) (u32 addr, u32 off, u32 val);
+ /**< stores the reference to register write function*/
+
+ u32(*readreg) (u32 addr, u32 off);
+ /**< stores the reference to register read function*/
+
+ void (*set_reg_bit) (u32 addr, u32 off, u32 bitmsk);
+ /**< stores the reference to register bit setting function*/
+
+ void (*clr_reg_bit) (u32 addr, u32 off, u32 bitmsk);
+ /**< stores the reference to register bit clearing function*/
+};
+
+/*! @ingroup I2C_HALLayer
+@struct adapter_info
+@brief This structure holds the adapter information
+ for the IOH i2c controller.
+@note This structure contains instances of struct i2c_algo_ioh_data
+ for the available I2C channels and also a variable for saving
+ the suspend status.
+@see - ioh_i2c_probe
+ - ioh_i2c_remove
+ - ioh_i2c_suspend
+ - ioh_i2c_resume
+*/
+
+struct adapter_info {
+
+ struct i2c_algo_ioh_data ioh_i2c_data[IOH_I2C_MAX_CHN];
+ /**< stores a list of i2c_algo_ioh_data;
+ there will be as many elements as maximum I2C channels*/
+
+ bool ioh_i2c_suspended;
+ /**< specifies whether the system is suspended or not*/
+};
+
+/**global variables*/
+extern int ioh_i2c_speed;
+extern int ioh_i2c_clk;
+extern s32(*ioh_i2c_cbr) (struct i2c_algo_ioh_data *);
+
+extern struct i2c_algorithm ioh_i2c_algorithm;
+
+/* Function prototypes */
+/*! @ingroup I2C_HALLayerAPI
+@fn s32 ioh_i2c_init(struct i2c_algo_ioh_data *adap)
+@brief Function to initialize IOH I2C hardware
+*/
+s32 ioh_i2c_init(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_HALLayerAPI
+@fn s32 ioh_i2c_writebytes(struct i2c_adapter *i2c_adap ,
+ struct i2c_msg *msgs,u32 last, u32 first)
+@brief Function for data write in normal mode
+*/
+s32 ioh_i2c_writebytes(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, u32 last, u32 first);
+
+/*! @ingroup I2C_HALLayerAPI
+@fn s32 ioh_i2c_readbytes(struct i2c_adapter *i2c_adap ,
+ struct i2c_msg *msgs,u32 last, u32 first)
+@brief Function for data read in normal mode
+*/
+s32 ioh_i2c_readbytes(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, u32 last, u32 first);
+
+/*! @ingroup I2C_HALLayerAPI
+@fn s32 ioh_i2c_eeprom_sw_reset(struct i2c_adapter * i2c_adap,
+ struct i2c_msg *msgs)
+@brief Function for triggering EEPROM software reset mode
+*/
+s32 ioh_i2c_eeprom_sw_reset(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs);
+
+/*! @ingroup I2C_HALLayerAPI
+@fn s32 ioh_i2c_buffer_write
+ (struct i2c_adapter * i2c_adap,struct i2c_msg *msgs)
+@brief Function for data write in buffer mode
+*/
+s32 ioh_i2c_buffer_write(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs);
+
+/*! @ingroup I2C_HALLayerAPI
+@fn s32 ioh_i2c_buffer_read
+ (struct i2c_adapter * i2c_adap,struct i2c_msg *msgs)
+@brief Function for data read in buffer mode
+*/
+s32 ioh_i2c_buffer_read(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs);
+
+/*! @ingroup I2C_HALLayerAPI
+@fn irqreturn_t ioh_i2c_handler(int irq,void *pData)
+@brief Interrupt handler
+*/
+irqreturn_t ioh_i2c_handler(int irq, void *pData);
+
+/*! @ingroup I2C_HALLayerAPI
+@fn void ioh_i2c_entcb
+ (s32(*ioh_i2c_ptr)(struct i2c_algo_ioh_data *adap))
+@brief Function for registering the interrupt handler call back
+*/
+void ioh_i2c_entcb(s32(*ioh_i2c_ptr) (struct i2c_algo_ioh_data *adap));
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn s32 ioh_i2c_cb(struct i2c_algo_ioh_data * adap)
+@brief Call back function invoked from interrupt handler
+*/
+s32 ioh_i2c_cb(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn void ioh_i2c_disbl_int(struct i2c_algo_ioh_data *adap)
+@brief Function for disabling the interrupt
+*/
+void ioh_i2c_disbl_int(struct i2c_algo_ioh_data *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn void ioh_i2c_writereg(u32 addr,u32 off,u32 val)
+@brief Function for writing data to register
+*/
+void ioh_i2c_writereg(u32 addr, u32 off, u32 val);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn u32 ioh_i2c_readreg(u32 addr,u32 off)
+@brief Function for reading data from register
+*/
+u32 ioh_i2c_readreg(u32 addr, u32 off);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn void ioh_i2c_setbit(u32 addr,u32 off,u32 bitmsk)
+@brief Function to set a particular bit in a register
+*/
+void ioh_i2c_setbit(u32 addr, u32 off, u32 bitmsk);
+
+/*! @ingroup I2C_UtilitiesAPI
+@fn void ioh_i2c_clrbit(u32 addr,u32 off,u32 bitmsk)
+@brief Function to clear a particular bit in a register
+*/
+void ioh_i2c_clrbit(u32 addr, u32 off, u32 bitmsk);
+#endif
diff -urN linux-2.6.33.1/drivers/i2c/busses/pch_i2c_main.c topcliff-2.6.33.1/drivers/i2c/busses/pch_i2c_main.c
--- linux-2.6.33.1/drivers/i2c/busses/pch_i2c_main.c 1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/busses/pch_i2c_main.c 2010-03-23 10:40:18.000000000 +0900
@@ -0,0 +1,247 @@
+/*!
+ * @file ioh_i2c_main.c
+ * @brief This file contains the definitions
+ * of Interface Layer APIs for IOH I2C driver.
+ * @version 0.95
+ * @section
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * History:
+ * Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+ * All rights reserved.
+ *
+ * created:
+ * WIPRO 02/20/2009
+ * modified:
+ * WIPRO 05/21/2009
+ *
+ */
+
+/*includes*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+
+#include "pch_i2c_hal.h"
+#include "pch_common.h"
+#include "pch_debug.h"
+
+/* Function prototypes */
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_func(struct i2c_adapter *adap)
+ @brief This function returns the functionalities supported
+ by I2C driver.
+ */
+static u32 ioh_i2c_func(struct i2c_adapter *adap);
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,s32 num)
+ @brief This function handles data transfer through I2C bus
+ */
+static s32 ioh_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+ s32 num);
+
+/*structures*/
+
+/*! @ingroup I2C_Global
+ @struct ioh_i2c_algorithm
+ @brief This an instance of the kernel structure i2c_algorithm structure
+ and it stores the properties of the IOH I2C algorithm driver.
+ @note This structure stores the references of the @ref ioh_i2c_xfer
+ and @ref ioh_i2c_func functions.
+ @see ioh_i2c_probe
+ */
+
+struct i2c_algorithm ioh_i2c_algorithm = {
+ .master_xfer = ioh_i2c_xfer,
+ .functionality = ioh_i2c_func
+};
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_func(struct i2c_adapter *adap)
+ @brief Function return the functionality of the I2C driver
+ @remarks Returns (I2C_FUNC_I2C) | (I2C_FUNC_SMBUS_EMUL) |
+ (I2C_FUNC_10BIT_ADDR)
+ @param adap [@ref IN] Contains reference to i2c_adapter structure
+ @retval u32
+ - Bitwise OR of the feature status codes supported
+ by this algorithm driver.
+ @see ioh_i2c_algorithm
+ */
+static u32 ioh_i2c_func(struct i2c_adapter *adap)
+{
+ u32 ret;
+ ret = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+ return ret;
+}
+
+/*! @ingroup I2C_UtilitiesAPI
+ @fn ioh_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs,s32 num)
+ @brief Function to transfer data through I2C bus
+ @remarks Function to transfer data through I2C bus
+ The main tasks performed by this method are:
+ - Check if system is suspended.
+ - If EEPROM software reset command is received,
+ then invoke function ioh_i2c_eeprom_sw_reset.
+ - If Buffer mode selection command is received,
+ check the value of msgs[0]->buf[0]. If set,
+ enable buffer mode, by setting the variable
+ adap->ioh_i2c_buff_mode_en. Otherwise reset the flag.
+ - If no special command, perform the requested
+ data transfer operation.
+ @note The master transfer function ioh_i2c_xfer
+ is invoked by the Linux I2C core, whenever
+ communication/data transfer with the IOH I2C
+ driver is necessary. The Linux I2C core
+ ensures that the function is called with
+ valid parameters only.
+ @param i2c_adap [@ref IN] contains reference to the struct i2c_adapter
+ @param msgs [@ref IN] contains reference to i2c_msg structure
+ @param num [@ref IN] number of messages
+ @retval s32
+ - @ref IOH_I2C_SUCCESS
+ Function returns successfully for EEPROM sw reset mode,
+ buffer mode selection commands.
+ - The number of bytes transferred for successful operation
+ of read/write calls.
+ - @ref IOH_I2C_FAIL
+ Any error occurs during the execution of the function.
+ @see ioh_i2c_algorithm
+ <hr>
+ */
+
+static s32 ioh_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, s32 num)
+{
+
+ struct i2c_msg *pmsg;
+ u32 i = 0;
+ u32 status;
+ u32 msglen;
+ u32 subaddrlen;
+ s32 ret = IOH_I2C_FAIL;
+
+ struct i2c_algo_ioh_data *adap = i2c_adap->algo_data;
+
+ if (adap->p_adapter_info->ioh_i2c_suspended == false) {
+ IOH_DEBUG("ioh_i2c_xfer "
+ "adap->p_adapter_info->ioh_i2c_suspended is %d\n",
+ adap->p_adapter_info->ioh_i2c_suspended);
+ /* transfer not completed */
+ adap->ioh_i2c_xfer_in_progress = true;
+ IOH_DEBUG(" adap->ioh_i2c_xfer_in_progress is %d\n",
+ adap->ioh_i2c_xfer_in_progress);
+ pmsg = &msgs[0];
+ status = pmsg->flags;
+ /* special commands for IOH I2C driver */
+ if ((status &
+ (IOH_EEPROM_SW_RST_MODE_ENABLE | IOH_BUFFER_MODE_ENABLE))
+ != false) {
+ if ((status & IOH_EEPROM_SW_RST_MODE_ENABLE) != false) {
+ /* check whether EEPROM sw reset is enabled */
+ IOH_DEBUG("ioh_i2c_xfer invoking "
+ "ioh_i2c_eeprom_sw_reset\n");
+ IOH_DEBUG("After invoking "
+ "I2C_MODE_SEL :flag= 0x%x\n", status);
+ ret = ioh_i2c_eeprom_sw_reset(i2c_adap, pmsg);
+ } else {
+ adap->ioh_i2c_buff_mode_en =
+ (pmsg->buf[0] == 1) ?
+ (IOH_BUFFER_MODE_ENABLE) : (pmsg->buf[0]);
+ ret = IOH_I2C_SUCCESS;
+ }
+ /* transfer completed */
+ adap->ioh_i2c_xfer_in_progress = false;
+ IOH_DEBUG("adap->ioh_i2c_xfer_in_progress is %d\n",
+ adap->ioh_i2c_xfer_in_progress);
+ IOH_DEBUG(KERN_INFO,
+ "After mode selection "
+ "ioh_i2c_xfer return = %d\n", ret);
+ return ret;
+ }
+ for (i = 0; i < num; i++) {
+ pmsg = &msgs[i];
+ pmsg->flags |= adap->ioh_i2c_buff_mode_en;
+ status = pmsg->flags;
+ IOH_DEBUG("After invoking I2C_MODE_SEL :flag= 0x%x\n",
+ status);
+ /* calculate sub address length and message length */
+ /* these are applicable only for buffer mode */
+ subaddrlen = pmsg->buf[0];
+ /* calculate actual message length excluding
+ * the sub address fields */
+ msglen = (pmsg->len) - (subaddrlen + 1);
+
+ if (((status & IOH_BUFFER_MODE_ENABLE) != false)
+ && (msglen != 0)) {
+ /* Buffer mode cannot be used for transferring
+ * 0 byte data. Hence when buffer mode is
+ * enabled and 0 byte transfer is requested,
+ * normal mode transfer will be used */
+ if ((status & (I2C_M_RD)) != false) {
+ IOH_DEBUG(KERN_INFO,
+ "ioh_i2c_xfer invoking "
+ "ioh_i2c_buffer_read\n");
+ ret =
+ ioh_i2c_buffer_read(i2c_adap, pmsg);
+ } else {
+ IOH_DEBUG(KERN_INFO,
+ "ioh_i2c_xfer invoking "
+ "ioh_i2c_buffer_write\n");
+ ret =
+ ioh_i2c_buffer_write(i2c_adap, pmsg);
+ }
+ } else {
+ if ((status & (I2C_M_RD)) != false) {
+ IOH_DEBUG(KERN_INFO,
+ "ioh_i2c_xfer invoking "
+ "ioh_i2c_readbytes\n");
+ ret =
+ ioh_i2c_readbytes(i2c_adap, pmsg,
+ (i + 1 == num),
+ (i == 0));
+ } else {
+ IOH_DEBUG(KERN_INFO,
+ "ioh_i2c_xfer invoking "
+ "ioh_i2c_writebytes\n");
+ ret =
+ ioh_i2c_writebytes(i2c_adap, pmsg,
+ (i + 1 == num),
+ (i == 0));
+ }
+ }
+
+ }
+
+ adap->ioh_i2c_xfer_in_progress = false; /* transfer completed */
+
+ IOH_DEBUG(" adap->ioh_i2c_xfer_in_progress is %d\n",
+ adap->ioh_i2c_xfer_in_progress);
+ }
+ IOH_DEBUG(KERN_INFO, "ioh_i2c_xfer return:%d\n\n\n\n", ret);
+
+ return ret;
+}
diff -urN linux-2.6.33.1/drivers/i2c/busses/pch_i2c_pci.c topcliff-2.6.33.1/drivers/i2c/busses/pch_i2c_pci.c
--- linux-2.6.33.1/drivers/i2c/busses/pch_i2c_pci.c 1970-01-01 09:00:00.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/busses/pch_i2c_pci.c 2010-03-23 10:40:18.000000000 +0900
@@ -0,0 +1,583 @@
+/*!
+* @file ioh_i2c_pci.c
+* @brief This file contains the definitions of I2C_PCILayer APIs.
+* @version 0.95
+* @section
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+* History:
+* Copyright (C) 2008 OKI SEMICONDUCTOR Co., LTD.
+* All rights reserved.
+*
+* created:
+* WIPRO 02/20/2009
+* modified:
+* WIPRO 05/21/2009
+*
+*/
+
+/*includes*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+
+#include "pch_i2c_hal.h"
+#include "pch_common.h"
+#include "pch_debug.h"
+
+/**
+ *macro definition
+ */
+
+/*! @ingroup I2C_PCILayer
+@def PCI_DEVICE_ID_IOH_I2C
+@brief Device ID of the device supported by IOH I2C
+ driver in GE configuration.
+*/
+#define PCI_DEVICE_ID_IOH_I2C (0x8817)
+
+/*
+ * variable declaration
+ */
+/*! @ingroup I2C_Global
+@var ioh_i2c_speed
+@brief specifies I2C bus speed in Kbps
+@note This parameter is provided as module parameter
+ while loading the driver. If no value is provided,
+ by default the speed is set to 100 kbps.
+@see ioh_i2c_init
+<hr>
+*/
+int ioh_i2c_speed = 100;
+
+/*! @ingroup I2C_Global
+@var ioh_i2c_clock
+@brief specifies I2C clock speed in KHz
+@note This parameter is provided as module parameter
+ while inserting the driver. If no value is provided,
+ by default the speed is set to 62500KHz.
+@see ioh_i2c_init
+<hr>
+*/
+/* int ioh_i2c_clk = 62500; */
+int ioh_i2c_clk = 50000;
+
+/*! @ingroup I2C_Global
+@var ioh_i2c_cbr
+@brief I2C_Global function pointer to save reference to
+ callback function
+@see ioh_i2c_entcb
+<hr>
+*/
+s32(*ioh_i2c_cbr) (struct i2c_algo_ioh_data *);
+
+/*! @ingroup I2C_Global
+@var MODULE_NAME
+@brief I2C_Global variable storing the name of this driver
+@see ioh_i2c_probe
+<hr>
+*/
+#define MODULE_NAME "pch_i2c" /* name for the driver */
+
+/* Function prototypes */
+/*! @ingroup I2C_PCILayerAPI
+@fn ioh_i2c_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+@brief This function implements the probe routine
+ for IOH I2C driver module
+*/
+static int __devinit ioh_i2c_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id);
+
+/*! @ingroup I2C_PCILayerAPI
+@fn ioh_i2c_remove(struct pci_dev *pdev)
+@brief This function implements the remove routine
+ for IOH I2C driver module.
+*/
+static void __devexit ioh_i2c_remove(struct pci_dev *pdev);
+
+/*! @ingroup I2C_PCILayerAPI
+@fn ioh_i2c_suspend(struct pci_dev* pdev,pm_message_t state)
+@brief This function implements the suspend routine
+ for IOH I2C driver module
+*/
+static int ioh_i2c_suspend(struct pci_dev *pdev, pm_message_t state);
+
+/*! @ingroup I2C_PCILayerAPI
+@fn ioh_i2c_resume(struct pci_dev* pdev)
+@brief This function implements the resume routine
+ for IOH I2C driver module
+*/
+static int ioh_i2c_resume(struct pci_dev *pdev);
+
+/*structures*/
+/*! @ingroup I2C_PCILayerFacilitators
+@struct ioh_i2c_pcidev_id
+@brief Store information of supported PCI devices
+@note This is an instance of pci_device_id structure and
+ holds information of the PCI devices that are supported
+ by this driver
+@see ioh_i2c_pcidriver
+*/
+
+static struct pci_device_id __devinitdata ioh_i2c_pcidev_id[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_IOH_I2C)},
+ {0,}
+};
+
+/*! @ingroup I2C_PCILayerFacilitators
+@struct ioh_i2c_pcidriver
+@brief Store the references of PCI driver interfaces to kernel
+@note This is an instance of pci_driver and this structure specifies
+ the driver details to be registered with the kernel
+@see - ioh_i2c_pci_init
+ - ioh_i2c_pci_exit
+<hr>
+*/
+
+static struct pci_driver ioh_i2c_pcidriver = {
+ .name = "ioh_i2c",
+ .id_table = ioh_i2c_pcidev_id,
+ .probe = ioh_i2c_probe,
+ .remove = __devexit_p(ioh_i2c_remove),
+#ifdef CONFIG_PM
+ .suspend = ioh_i2c_suspend,
+ .resume = ioh_i2c_resume
+#endif
+};
+
+/*! @ingroup I2C_PCILayerAPI
+ @fn ioh_i2c_probe(struct pci_dev *pdev, const struct
+ pci_device_id *id)
+ @remarks The main tasks performed by this method are:
+ - Allocate memory for driver private data.
+ - Enable the PCI device.
+ - Reserve the PCI regions.
+ - Map the device address of the IO BAR.
+ - Register the interrupt handler.
+ - Initialize the members in adap_info->ioh_i2c_data.
+ - Register the ioh_i2c_adapter.
+ - Initialize the IOH I2C hardware.
+ @note This function is invoked by the PCI core when a device is
+ found for this driver to control
+ @param pdev [@ref IN] contains reference to
+ PCI device descriptor for the peripheral
+ @param id [@ref IN] contains reference to
+ the pci_device_id table of matching peripheral
+ @retval int
+ - @ref IOH_I2C_SUCCESS Function returns successfully.
+ - -EIO pci_enable_device fails
+ - -EINVAL pci_enable_device/request_irq fails
+ - -EBUSY pci_request_regions/request_irq fails
+ - -ENOMEM i2c_add_adapter/request_irq/pci_iomap/kzalloc fails
+ - -EAGAIN i2c_add_adapter fails
+ - -ENOSYS request_irq fails
+ @see ioh_i2c_pcidriver
+ <hr>
+ */
+static int __devinit ioh_i2c_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+
+ int i;
+ u32 base_addr;
+ s32 ret = IOH_I2C_SUCCESS;
+
+ IOH_DEBUG("Enterred in i2c_probe\n");
+
+ do {
+ struct adapter_info *adap_info =
+ kzalloc((sizeof(struct adapter_info)), GFP_KERNEL);
+ if (adap_info == NULL) {
+ IOH_LOG(KERN_ERR, "Memory allocation failed FAILED");
+ ret = -ENOMEM;
+ break;
+ }
+
+ IOH_DEBUG
+ ("Function kzalloc invoked successfully "
+ "and adap_info valu = %p\n",
+ adap_info);
+
+ ret = pci_enable_device(pdev);
+
+ if (ret) {
+ IOH_LOG(KERN_ERR, "pci_enable_device FAILED");
+ kfree(adap_info);
+ break;
+ }
+
+ IOH_DEBUG("pci_enable_device returns %d\n", ret);
+
+ ret = pci_request_regions(pdev, MODULE_NAME);
+ if (ret) {
+ IOH_LOG(KERN_ERR, "pci_request_regions FAILED");
+ pci_disable_device(pdev);
+ kfree(adap_info);
+ break;
+ }
+
+ IOH_DEBUG("pci_request_regions returns %d\n", ret);
+
+ /* Wipro 1/13/2010 Use Mem BAR */
+ base_addr = (unsigned long)pci_iomap(pdev, 1, 0);
+
+ if (base_addr == 0) {
+ IOH_LOG(KERN_ERR, "pci_iomap FAILED");
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ kfree(adap_info);
+ ret = -ENOMEM;
+ break;
+ }
+
+ IOH_DEBUG("pci_iomap invoked successfully\n");
+
+ ioh_i2c_entcb(ioh_i2c_cb);
+ IOH_DEBUG("ioh_i2c_entcb invoked successfully\n");
+
+ for (i = 0; i < IOH_I2C_MAX_CHN; i++) {
+ adap_info->ioh_i2c_data[i].p_adapter_info = adap_info;
+ adap_info->ioh_i2c_data[i].writereg = ioh_i2c_writereg;
+ adap_info->ioh_i2c_data[i].readreg = ioh_i2c_readreg;
+ adap_info->ioh_i2c_data[i].set_reg_bit = ioh_i2c_setbit;
+ adap_info->ioh_i2c_data[i].clr_reg_bit = ioh_i2c_clrbit;
+
+ adap_info->ioh_i2c_data[i].ioh_i2c_adapter.owner =
+ THIS_MODULE;
+ adap_info->ioh_i2c_data[i].ioh_i2c_adapter.class =
+ I2C_CLASS_HWMON;
+ strcpy(adap_info->ioh_i2c_data[i].ioh_i2c_adapter.name,
+ "ioh_i2c");
+ adap_info->ioh_i2c_data[i].ioh_i2c_adapter.algo =
+ &ioh_i2c_algorithm;
+ adap_info->ioh_i2c_data[i].ioh_i2c_adapter.algo_data =
+ &adap_info->ioh_i2c_data[i];
+
+ /* (i * 0x80) + base_addr; */
+ adap_info->ioh_i2c_data[i].ioh_i2c_base_address =
+ base_addr;
+
+ adap_info->ioh_i2c_data[i].ioh_i2c_adapter.dev.parent =
+ &pdev->dev;
+
+ ret =
+ i2c_add_adapter(&
+ (adap_info->ioh_i2c_data[i].
+ ioh_i2c_adapter));
+
+ if (ret) {
+ IOH_LOG(KERN_ERR, "i2c_add_adapter FAILED");
+
+ pci_iounmap(pdev, (void *)base_addr);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ kfree(adap_info);
+ break;
+ }
+
+ IOH_DEBUG("i2c_add_adapter returns %d for channel-%d\n",
+ ret, i);
+ (void)ioh_i2c_init(&adap_info->ioh_i2c_data[i]);
+ IOH_DEBUG("ioh_i2c_init invoked successfully \n");
+
+ }
+
+ if (ret)
+ break;
+
+ ret = request_irq(pdev->irq, &ioh_i2c_handler, IRQF_SHARED,
+ MODULE_NAME, (void *)adap_info);
+
+ if (ret) {
+ IOH_DEBUG("request_irq Failed\n");
+
+ for (i = 0; i < IOH_I2C_MAX_CHN; i++) {
+ i2c_del_adapter(&
+ (adap_info->
+ ioh_i2c_data
+ [i].ioh_i2c_adapter));
+ }
+
+ pci_iounmap(pdev, (void *)base_addr);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ kfree(adap_info);
+ break;
+ }
+
+ IOH_DEBUG("request_irq returns %d\n", ret);
+
+ IOH_DEBUG("ioh_i2c_probe returns %d\n", IOH_I2C_SUCCESS);
+ pci_set_drvdata(pdev, (void *)adap_info);
+ return IOH_I2C_SUCCESS;
+ } while (0);
+
+ return ret;
+}
+
+/*! @ingroup I2C_PCILayerAPI
+ @fn ioh_i2c_remove(struct pci_dev *pdev)
+ @remarks The main tasks performed by this method are:
+ - Disable interrupts.
+ - Unregister interrupt handler.
+ - Unregister i2c_adapter.
+ - Release IO memory.
+ - Release PCI regions.
+ - Disable PCI device.
+ @note This function is invoked when the IOH I2C driver module is
+ unloaded from the system using rmmod command or when the
+ IOH I2C device is removed from the system.
+ @param pdev [@ref INOUT] contains reference to
+ PCI device descriptor for the peripheral
+ @retval None
+ @see ioh_i2c_pcidriver
+ <hr>
+ */
+
+static void __devexit ioh_i2c_remove(struct pci_dev *pdev)
+{
+ int i;
+
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+ IOH_DEBUG(" invoked function pci_get_drvdata successfully\n");
+
+ for (i = 0; i < IOH_I2C_MAX_CHN; i++) {
+ ioh_i2c_disbl_int(&adap_info->ioh_i2c_data[i]);
+
+ if (i == (IOH_I2C_MAX_CHN - 1)) {
+ free_irq(pdev->irq, (void *)adap_info);
+ IOH_DEBUG(" free_irq invoked successfully\n");
+ }
+
+ i2c_del_adapter(&(adap_info->ioh_i2c_data[i].ioh_i2c_adapter));
+
+ IOH_DEBUG(" invoked i2c_del_adapter successfully\n");
+
+ }
+
+ if (adap_info->ioh_i2c_data[0].ioh_i2c_base_address) {
+ pci_iounmap(pdev,
+ (void *)adap_info->ioh_i2c_data[0].
+ ioh_i2c_base_address);
+ IOH_DEBUG(" pci_iounmap invoked successfully\n");
+ adap_info->ioh_i2c_data[0].ioh_i2c_base_address = 0;
+ }
+
+ pci_set_drvdata(pdev, NULL);
+
+ pci_release_regions(pdev);
+ IOH_DEBUG(" pci_release_regions invoked successfully\n");
+
+ pci_disable_device(pdev);
+ kfree(adap_info);
+ IOH_DEBUG(" pci_disable_device invoked successfully\n");
+ IOH_DEBUG(" ioh_i2c_remove invoked successfully\n");
+}
+
+#ifdef CONFIG_PM
+
+/*! @ingroup I2C_PCILayerAPI
+ @fn ioh_i2c_suspend(struct pci_dev* pdev,pm_message_t state)
+ @remarks The main tasks performed by this method are:
+ - Wait for any transfer in progress to complete.
+ - Disable interrupts.
+ - Save PCI device state.
+ - Disable PM notifications.
+ - Disable the PCI device.
+ - Move the device to D3Hot power state.
+ @note This function is invoked by the kernel when the system is
+ transitioning to low power state.
+ @param pdev [@ref INOUT]
+ contains reference to PCI device descriptor for the peripheral
+ @param state [@ref IN]
+ Represents the low power state the system is transitioning to.
+ @retval int
+ - @ref IOH_I2C_SUCCESS Function returns successfully.
+ - -ENOMEM pci_save_state fails.
+ @see ioh_i2c_pcidriver
+ */
+static int ioh_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+
+ int i;
+ int ret;
+
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+ IOH_DEBUG(" invoked function pci_get_drvdata successfully\n");
+
+ adap_info->ioh_i2c_suspended = true;
+
+ for (i = 0; i < IOH_I2C_MAX_CHN; i++) {
+ while ((adap_info->ioh_i2c_data[i].ioh_i2c_xfer_in_progress ==
+ true)) {
+ /* It is assumed that any pending transfer will
+ * be completed after the delay
+ */
+ msleep(1);
+ }
+ /* Disable the i2c interrupts */
+ ioh_i2c_disbl_int(&adap_info->ioh_i2c_data[i]);
+ }
+
+ IOH_DEBUG("I2CSR = %x\n",
+ ioh_i2c_readreg(adap_info->
+ ioh_i2c_data[0].ioh_i2c_base_address, 0x08));
+ IOH_DEBUG("I2CBUFSTA = %x\n",
+ ioh_i2c_readreg(adap_info->
+ ioh_i2c_data[0].ioh_i2c_base_address, 0x30));
+ IOH_DEBUG("I2CESRSTA = %x\n",
+ ioh_i2c_readreg(adap_info->
+ ioh_i2c_data[0].ioh_i2c_base_address, 0x44));
+
+ IOH_DEBUG(" invoked function ioh_i2c_disbl_int successfully\n");
+
+ ret = pci_save_state(pdev);
+
+ if (ret) {
+ IOH_LOG(KERN_ERR, "pci_save_state failed\n");
+ return ret;
+ }
+
+ IOH_DEBUG("Invoked pci_save_state successfully\n");
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ IOH_DEBUG("Invoked pci_enable_wake successfully\n");
+
+ pci_disable_device(pdev);
+ IOH_DEBUG("Invoked pci_disable_device successfully\n");
+
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ IOH_DEBUG("Invoked pci_set_power_state successfully\n");
+ IOH_DEBUG("ioh_i2c_suspend returns %d\n", IOH_I2C_SUCCESS);
+
+ return IOH_I2C_SUCCESS;
+
+}
+
+/*! @ingroup I2C_PCILayerAPI
+ @fn ioh_i2c_resume(struct pci_dev* pdev)
+ @remarks The main tasks performed by this method are:
+ - Move device to D0 power state.
+ - Restore PCI device state.
+ - Enable the PCI device state.
+ - Disable PM notifications.
+ - Initialize IOH I2C device.
+ @note This function is invoked by the kernel when the system is
+ transitioning to normal power state from a lower power state.
+ @param pdev [@ref INOUT]
+ contains reference to PCI device descriptor for the peripheral
+ @retval int
+ - @ref IOH_I2C_SUCCESS Function returns successfully.
+ - -EIO pci_enable_device fails.
+ - -EINVAL pci_enable_device fails.
+ @see ioh_i2c_pcidriver
+ <hr>
+ */
+static int ioh_i2c_resume(struct pci_dev *pdev)
+{
+
+ struct adapter_info *adap_info = pci_get_drvdata(pdev);
+ int i;
+
+ IOH_DEBUG(" invoked function pci_get_drvdata successfully\n");
+
+ pci_set_power_state(pdev, PCI_D0);
+ IOH_DEBUG("Invoked pci_set_power_state successfully\n");
+
+ pci_restore_state(pdev);
+ IOH_DEBUG("Invoked pci_restore_state successfully\n");
+
+ if (pci_enable_device(pdev) < 0) {
+ IOH_LOG(KERN_ERR,
+ "pci_enable_device failed in ioh_i2c_resume\n");
+ return -EIO;
+ }
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+
+ IOH_DEBUG("Invoked pci_enable_wake successfully\n");
+
+ for (i = 0; i < IOH_I2C_MAX_CHN; i++)
+ (void)ioh_i2c_init(&adap_info->ioh_i2c_data[i]);
+
+ IOH_DEBUG("Invoked ioh_i2c_init successfully\n");
+
+ adap_info->ioh_i2c_suspended = false;
+
+ IOH_DEBUG("ioh_i2c_resume return %d\n", IOH_I2C_SUCCESS);
+ return IOH_I2C_SUCCESS;
+}
+
+#endif
+
+/*! @ingroup I2C_InterfaceLayerAPI
+ @fn ioh_i2c_pci_init(void)
+ @brief This function implements the module entry point.
+ @remarks This function invoked at module insertion
+ The main task performed by this method:
+ - Register the PCI driver with PCI core
+ using pci_register_driver API.
+ @param None
+ @retval int
+ - 0 Function returns successfully.
+ - -EEXIST pci_register_driver fails
+ - -EINVAL pci_register_driver fails
+ - -ENOMEM pci_register_driver fails
+ <hr>
+ */
+static int __init ioh_i2c_pci_init(void)
+{
+
+ IOH_DEBUG
+ ("ioh_i2c_pci_init : Invoked pci_register_driver successfully\n");
+ return pci_register_driver(&ioh_i2c_pcidriver);
+}
+
+/*! @ingroup I2C_InterfaceLayerAPI
+ @fn ioh_i2c_pci_exit(void)
+ @brief This function implements the module exit point.
+ @remarks This function is invoked when IOH I2C driver module is being
+ removed from the system. The main task performed by this method:
+ - Unregister the PCI driver with PCI core using
+ the pci_unregister_driver API
+ @param None
+ @retval None
+ */
+static void __exit ioh_i2c_pci_exit(void)
+{
+ IOH_DEBUG
+ ("ioh_i2c_pci_exit : Invoked pci_unregister_driver successfully \n ");
+ pci_unregister_driver(&ioh_i2c_pcidriver);
+
+}
+
+MODULE_DESCRIPTION("IOH I2C PCI Driver");
+MODULE_LICENSE("GPL");
+module_init(ioh_i2c_pci_init);
+module_exit(ioh_i2c_pci_exit);
+module_param(ioh_i2c_speed, int, (S_IRUSR | S_IWUSR));
+module_param(ioh_i2c_clk, int, (S_IRUSR | S_IWUSR));
diff -urN linux-2.6.33.1/drivers/i2c/i2c-dev.c topcliff-2.6.33.1/drivers/i2c/i2c-dev.c
--- linux-2.6.33.1/drivers/i2c/i2c-dev.c 2010-03-16 01:09:39.000000000 +0900
+++ topcliff-2.6.33.1/drivers/i2c/i2c-dev.c 2010-03-24 11:21:29.000000000 +0900
@@ -36,7 +36,7 @@
#include <linux/i2c-dev.h>
#include <linux/jiffies.h>
#include <asm/uaccess.h>
-
+#include "busses/pch_i2c_hal.h"
static struct i2c_driver i2cdev_driver;
/*
@@ -147,6 +147,11 @@
if (tmp==NULL)
return -ENOMEM;
+ if (copy_from_user(tmp, buf, count)) {
+ kfree(tmp);
+ return -EFAULT;
+ }
+
pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
iminor(file->f_path.dentry->d_inode), count);
@@ -372,6 +377,12 @@
struct i2c_client *client = (struct i2c_client *)file->private_data;
unsigned long funcs;
+ unsigned long ioh_mode;
+ int ret;
+
+ struct i2c_msg msg;
+ unsigned char msgbuf[1];
+
dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
cmd, arg);
@@ -427,6 +438,22 @@
*/
client->adapter->timeout = msecs_to_jiffies(arg * 10);
break;
+ case I2C_MODE_SEL:
+ ioh_mode = arg;
+
+ if (ioh_mode <= 4) {
+ msgbuf[0] = ioh_mode;
+ msg.buf = msgbuf;
+ msg.len = 1;
+ msg.flags = (ioh_mode <=1) ? \
+ (IOH_BUFFER_MODE_ENABLE) : \
+ (IOH_EEPROM_SW_RST_MODE_ENABLE);
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ } else {
+ printk(KERN_ERR "I2C mode sel:Invalid mode \n");
+ ret = -EINVAL;
+ }
+ return ret;
default:
/* NOTE: returning a fault code here could cause trouble
* in buggy userspace code. Some old kernel bugs returned