diff options
author | Joshua Lock <josh@linux.intel.com> | 2010-05-18 14:51:13 +0100 |
---|---|---|
committer | Joshua Lock <josh@linux.intel.com> | 2010-05-19 12:20:16 +0100 |
commit | 5e8c7c54a9b297dae0081dd19a7bb94e23040a3d (patch) | |
tree | 948e3642c1bf426870b83c72c68c997dce66766c /meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-i2c.patch | |
parent | 5e07bc91281969d54896dd0a13e3d6134e432027 (diff) | |
download | ast2050-yocto-poky-5e8c7c54a9b297dae0081dd19a7bb94e23040a3d.zip ast2050-yocto-poky-5e8c7c54a9b297dae0081dd19a7bb94e23040a3d.tar.gz |
linux-moblin: add 2.6.33.2 kernel from MeeGo 1.0
Signed-off-by: Joshua Lock <josh@linux.intel.com>
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-i2c.patch')
-rw-r--r-- | meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-i2c.patch | 3435 |
1 files changed, 3435 insertions, 0 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-i2c.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-i2c.patch new file mode 100644 index 0000000..e6f6f67 --- /dev/null +++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-pch-i2c.patch @@ -0,0 +1,3435 @@ + + +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 |