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