diff options
Diffstat (limited to 'target/linux/coldfire/patches/025-Add-I2C-driver-for-MCF5445x-MCF547x-MCF548x.patch')
-rw-r--r-- | target/linux/coldfire/patches/025-Add-I2C-driver-for-MCF5445x-MCF547x-MCF548x.patch | 1216 |
1 files changed, 0 insertions, 1216 deletions
diff --git a/target/linux/coldfire/patches/025-Add-I2C-driver-for-MCF5445x-MCF547x-MCF548x.patch b/target/linux/coldfire/patches/025-Add-I2C-driver-for-MCF5445x-MCF547x-MCF548x.patch deleted file mode 100644 index 743af7f..0000000 --- a/target/linux/coldfire/patches/025-Add-I2C-driver-for-MCF5445x-MCF547x-MCF548x.patch +++ /dev/null @@ -1,1216 +0,0 @@ -From a7c7130d916c1f7e0d27ad9b338912496ad53089 Mon Sep 17 00:00:00 2001 -From: Alison Wang <b18965@freescale.com> -Date: Thu, 4 Aug 2011 09:59:46 +0800 -Subject: [PATCH 25/52] Add I2C driver for MCF5445x/MCF547x/MCF548x. - -Add common I2C driver for MCF5445x/MCF547x/MCF548x and add I2C slave -mode support for MCF5445x. - -Configure I2C adaptor as slave mode and Support I2C adaptor as a -"eeprom-like" slave device. - -Signed-off-by: Alison Wang <b18965@freescale.com> ---- - arch/m68k/include/asm/mcfi2c.h | 57 +++ - drivers/i2c/busses/Kconfig | 24 ++ - drivers/i2c/busses/Makefile | 2 + - drivers/i2c/busses/i2c-algo-mcf.h | 23 ++ - drivers/i2c/busses/i2c-mcf-slave.c | 358 ++++++++++++++++++ - drivers/i2c/busses/i2c-mcf.c | 698 ++++++++++++++++++++++++++++++++++++ - 6 files changed, 1162 insertions(+), 0 deletions(-) - create mode 100644 arch/m68k/include/asm/mcfi2c.h - create mode 100644 drivers/i2c/busses/i2c-algo-mcf.h - create mode 100644 drivers/i2c/busses/i2c-mcf-slave.c - create mode 100644 drivers/i2c/busses/i2c-mcf.c - ---- /dev/null -+++ b/arch/m68k/include/asm/mcfi2c.h -@@ -0,0 +1,57 @@ -+/* -+ * mcfi2c.h -- ColdFire mcfv4/mcfv4e i2c controller support. -+ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ */ -+#ifndef MCF_I2C_H -+#define MCF_I2C_H -+ -+/* Register read/write macros */ -+#if defined(CONFIG_M547X_8X) -+#define MCF_I2AR MCF_REG08(0x008F00) /* I2C Address */ -+#define MCF_I2FDR MCF_REG08(0x008F04) /* I2C Frequency Divider */ -+#define MCF_I2CR MCF_REG08(0x008F08) /* I2C Control */ -+#define MCF_I2SR MCF_REG08(0x008F0C) /* I2C Status */ -+#define MCF_I2DR MCF_REG08(0x008F10) /* I2C Data I/O */ -+#define MCF_I2ICR MCF_REG08(0x008F20) /* I2C Interrupt Control */ -+#elif defined(CONFIG_M5445X) || defined(CONFIG_M5441X) -+#define MCF_I2AR (*(volatile u8 *)(0xFC058000)) /* I2C Address */ -+/* I2C Frequency Divider */ -+#define MCF_I2FDR (*(volatile u8 *)(0xFC058004)) -+#define MCF_I2CR (*(volatile u8 *)(0xFC058008)) /* I2C Control */ -+#define MCF_I2SR (*(volatile u8 *)(0xFC05800C)) /* I2C Status */ -+#define MCF_I2DR (*(volatile u8 *)(0xFC058010)) /* I2C Data I/O */ -+#endif -+ -+/* Bit definitions and macros for MCF_I2C_I2AR */ -+#define MCF_I2AR_ADR(x) (((x)&0x7F)<<1) -+ -+/* Bit definitions and macros for MCF_I2C_I2FDR */ -+#define MCF_I2FDR_IC(x) (((x)&0x3F)<<0) -+ -+/* Bit definitions and macros for MCF_I2C_I2CR */ -+#define MCF_I2CR_RSTA (0x04) -+#define MCF_I2CR_TXAK (0x08) -+#define MCF_I2CR_MTX (0x10) -+#define MCF_I2CR_MSTA (0x20) -+#define MCF_I2CR_IIEN (0x40) -+#define MCF_I2CR_IEN (0x80) -+ -+/* Bit definitions and macros for MCF_I2C_I2SR */ -+#define MCF_I2SR_RXAK (0x01) -+#define MCF_I2SR_IIF (0x02) -+#define MCF_I2SR_SRW (0x04) -+#define MCF_I2SR_IAL (0x10) -+#define MCF_I2SR_IBB (0x20) -+#define MCF_I2SR_IAAS (0x40) -+#define MCF_I2SR_ICF (0x80) -+ -+/* Bit definitions and macros for MCF_I2C_I2ICR */ -+#if defined(CONFIG_M547X_8X) -+#define MCF_I2ICR_IE (0x01) -+#define MCF_I2ICR_RE (0x02) -+#define MCF_I2ICR_TE (0x04) -+#define MCF_I2ICR_BNBE (0x08) -+#endif -+ -+/********************************************************************/ -+#endif ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig -@@ -431,6 +431,30 @@ config I2C_IXP2000 - This driver is deprecated and will be dropped soon. Use i2c-gpio - instead. - -+config I2C_MCF -+ tristate "MCF ColdFire I2C Interface" -+ depends on I2C && COLDFIRE -+ help -+ If you say yes to this option, support will be included for the -+ I2C on most ColdFire CPUs -+ -+ This driver can also be built as a module. If so, the module -+ will be called i2c-mcf. -+ -+config I2C_MCF_SLAVE -+ tristate "MCF ColdFire I2C Slave Interface" -+ depends on !(I2C_MCF) -+ default n -+ help -+ mcf i2c adapter slave mode, only supported on mcf5445x platform. -+ -+config I2C_SLAVE_TEST -+ bool "I2C Slave Mode Test Configuration" -+ depends on I2C_MCF_SLAVE -+ default y -+ help -+ This configuration help to test I2C slave mode -+ - config I2C_MPC - tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx" - depends on PPC32 ---- a/drivers/i2c/busses/Makefile -+++ b/drivers/i2c/busses/Makefile -@@ -77,5 +77,7 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o - obj-$(CONFIG_I2C_STUB) += i2c-stub.o - obj-$(CONFIG_SCx200_ACB) += scx200_acb.o - obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o -+obj-$(CONFIG_I2C_MCF) += i2c-mcf.o -+obj-$(CONFIG_I2C_MCF_SLAVE) += i2c-mcf-slave.o - - ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG ---- /dev/null -+++ b/drivers/i2c/busses/i2c-algo-mcf.h -@@ -0,0 +1,23 @@ -+#ifndef I2C_ALGO_MCF_H -+#define I2C_ALGO_MCF_H 1 -+ -+/* --- Defines for pcf-adapters --------------------------------------- */ -+#include <linux/i2c.h> -+ -+struct i2c_algo_mcf_data { -+ void *data; /* private data for lolevel routines */ -+ void (*setmcf) (void *data, int ctl, int val); -+ int (*getmcf) (void *data, int ctl); -+ int (*getown) (void *data); -+ int (*getclock) (void *data); -+ void (*waitforpin) (void); -+ /* local settings */ -+ int udelay; -+ int mdelay; -+ int timeout; -+}; -+ -+int i2c_mcf_add_bus(struct i2c_adapter *); -+int i2c_mcf_del_bus(struct i2c_adapter *); -+ -+#endif /* I2C_ALGO_MCF_H */ ---- /dev/null -+++ b/drivers/i2c/busses/i2c-mcf-slave.c -@@ -0,0 +1,358 @@ -+/* -+ * i2c-mcf-slave.c - support adpater slave mode, now only support -+ * mcf5445x platform -+ * -+ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ * Lanttor Guo <lanttor.guo@freescale.com> -+ * -+ * 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; either version 2 of the License, or -+ * (at your option) any later version. -+*/ -+ -+#ifdef CONFIG_I2C_SLAVE_TEST -+#define DEBUG -+#endif -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/errno.h> -+#include <linux/i2c.h> -+#include <linux/delay.h> -+#include <linux/string.h> -+#include <linux/platform_device.h> -+#include <linux/interrupt.h> -+#include <linux/proc_fs.h> -+#include <linux/types.h> -+#include <asm/coldfire.h> -+#include <asm/mcfsim.h> -+#include <asm/irq.h> -+#include <asm/mcfi2c.h> -+#if defined(CONFIG_M5445X) -+#include <asm/mcf5445x_intc.h> -+#endif -+ -+#define IRQ (64+30) -+#define SLAVE_HANDLER_NAME "mcf-i2c slave handler" -+#define I2C_BUFFER_SIZE 50 -+ -+/* Structure for storing I2C transfer data */ -+struct i2c_buffer { -+ int tx_index; /* TX index */ -+ int rx_index; /* RX index */ -+ u16 length; /* Length of the buffer in bytes */ -+ u8 buf[I2C_BUFFER_SIZE]; /* Data buffer */ -+}; -+ -+struct i2c_buffer i2c_tx_buffer; -+struct i2c_buffer i2c_rx_buffer; -+ -+u8 *tx_string = "abcdefghijklmnopqrstuvwxyz0123456789)!@#$%^&*([]."; -+ -+/* -+ * I2C slave mode interrupt handler -+ * -+ */ -+static irqreturn_t i2c_slave_handler(int this_irq, void *dev_id) -+{ -+ u8 dummy_read; -+ int tmp_index; -+ -+#ifdef DEBUG -+ printk(KERN_INFO "i2c adapter slave mode irq handler.\n"); -+#endif -+ -+ /* Clear I2C interupt flag */ -+ MCF_I2SR = ~MCF_I2SR_IIF; -+ -+ /* Check if this device is in Master or Slave Mode. */ -+ if (MCF_I2CR & MCF_I2CR_MSTA) { -+ /* Master mode, do nothing here */ -+ printk(KERN_INFO "i2c master mode at %s(), do nothing!\n", -+ __func__); -+ return IRQ_NONE; -+ } else { -+ /* Slave Mode - Check if Arbitration Lost. */ -+ if (MCF_I2SR & MCF_I2SR_IAL) { -+ -+ #ifdef DEBUG -+ printk(KERN_INFO "Arbitration Lost.\n"); -+ #endif -+ -+ /* Clear IAL bit */ -+ MCF_I2SR &= ~MCF_I2SR_IAL; -+ -+ /* Arbitration Lost - -+ * Check if this device is being addressed as slave. -+ *(If not, nothing more needs to be done.) -+ */ -+ if (MCF_I2SR & MCF_I2SR_IAAS) { -+ /* Addressed as slave - -+ * Check if master was reading from slave or -+ * writing to slave. -+ */ -+ if (MCF_I2SR & MCF_I2SR_SRW) { -+ /* Set tx_index to 0 */ -+ if (i2c_tx_buffer.length == 0) { -+ i2c_tx_buffer.length = -+ I2C_BUFFER_SIZE; -+ i2c_tx_buffer.tx_index = 0; -+ } -+ -+ /* Master was reading from slave - -+ * Set Transmit Mode. -+ */ -+ MCF_I2CR |= MCF_I2CR_MTX; -+ -+ /* Write data to MBDR. */ -+ tmp_index = i2c_tx_buffer.tx_index++; -+ MCF_I2DR = i2c_tx_buffer.buf[tmp_index]; -+ i2c_tx_buffer.length--; -+ -+ #ifdef DEBUG -+ printk(KERN_INFO "Arbitration Lost: " -+ "Addressed as slave - " -+ "TX mode.\n"); -+ #endif -+ } else { -+ /* Set rx_index to 0 */ -+ i2c_rx_buffer.rx_index = 0; -+ -+ /* Master was writing to slave - -+ Set Receive Mode. */ -+ MCF_I2CR &= ~MCF_I2CR_MTX; -+ -+ /* Dummy read from MBDR, to clear -+ the ICF bit. */ -+ dummy_read = MCF_I2DR; -+ -+ #ifdef DEBUG -+ printk(KERN_INFO "Arbitration Lost: " -+ "Addressed as slave - " -+ "RX mode.\n"); -+ #endif -+ } -+ } -+ -+ } else { -+ /* Arbitration Not Lost - Check if data byte is this -+ devices's Slave Address byte. */ -+ if (MCF_I2SR & MCF_I2SR_IAAS) { -+ /* Data byte is Slave Address byte - -+ Check Slave Read/Write bit. */ -+ if (MCF_I2SR & MCF_I2SR_SRW) { -+ /* Set tx_index to 0 */ -+ if (i2c_tx_buffer.length == 0) { -+ i2c_tx_buffer.length = -+ I2C_BUFFER_SIZE; -+ i2c_tx_buffer.tx_index = 0; -+ } -+ -+ /* Master was reading from slave - -+ Set Transmit Mode. */ -+ MCF_I2CR |= MCF_I2CR_MTX; -+ -+ /* Write data to MBDR. */ -+ tmp_index = i2c_tx_buffer.tx_index++; -+ MCF_I2DR = i2c_tx_buffer.buf[tmp_index]; -+ i2c_tx_buffer.length--; -+ -+ #ifdef DEBUG -+ tmp_index = i2c_tx_buffer.tx_index - 1; -+ printk(KERN_INFO "Slave TX: First byte" -+ " - 0x%02X\n", -+ i2c_tx_buffer.buf[tmp_index]); -+ #endif -+ } else { -+ /* Master has specified Slave Receive -+ Mode. Set Receive Mode. (Writing to -+ MBCR clears IAAS.) */ -+ -+ /* Set rx_index to 0 */ -+ i2c_rx_buffer.rx_index = 0; -+ -+ MCF_I2CR &= ~MCF_I2CR_MTX; -+ -+ /* Dummy read from MBDR, to clear -+ the ICF bit. */ -+ dummy_read = MCF_I2DR; -+ -+ #ifdef DEBUG -+ printk(KERN_INFO "Slave RX: Receive " -+ "address.\n"); -+ #endif -+ } -+ } else { -+ /* Data byte received is not Slave Address byte -+ Check if this device is in Transmit or -+ Receive Mode. */ -+ if (MCF_I2CR & MCF_I2CR_MTX) { -+ /* Last byte received? */ -+ if (MCF_I2SR & MCF_I2SR_RXAK) { -+ MCF_I2CR &= ~MCF_I2CR_MTX; -+ dummy_read = MCF_I2DR; -+ -+ #ifdef DEBUG -+ printk(KERN_INFO "Slave TX: " -+ "Last byte has been " -+ "sent.\n"); -+ #endif -+ } else { -+ /* Write data to MBDR. */ -+ tmp_index = -+ i2c_tx_buffer.tx_index++; -+ MCF_I2DR = -+ i2c_tx_buffer.buf[tmp_index]; -+ i2c_tx_buffer.length--; -+ -+ if (i2c_tx_buffer.length == 0) { -+ i2c_tx_buffer.length = -+ I2C_BUFFER_SIZE; -+ i2c_tx_buffer.tx_index = -+ 0; -+ } -+ -+ } -+ } else { -+ /* Receive Mode - Read data from -+ MBDR and store it. */ -+ tmp_index = i2c_rx_buffer.rx_index++; -+ i2c_rx_buffer.buf[tmp_index] = MCF_I2DR; -+ i2c_rx_buffer.length++; -+ } -+ } -+ } -+ return IRQ_HANDLED; -+ } -+} -+ -+#ifdef CONFIG_PROC_FS -+ -+/* -+ * Info exported via "/proc/driver/i2c". -+ */ -+ -+static int gen_i2c_proc_output(char *buf) -+{ -+ char *p; -+ -+ p = buf; -+ p += sprintf(p, -+ "I2CR: 0x%x\n" -+ "I2SR: 0x%x\n" -+ "I2DR: 0x%x\n", -+ MCF_I2CR, MCF_I2SR, MCF_I2DR); -+ -+ return p - buf; -+} -+ -+static int gen_i2c_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = gen_i2c_proc_output(page); -+ if (len <= off+count) -+ *eof = 1; -+ *start = page + off; -+ len -= off; -+ if (len > count) -+ len = count; -+ if (len < 0) -+ len = 0; -+ return len; -+} -+ -+static int __init gen_i2c_proc_init(void) -+{ -+ struct proc_dir_entry *r; -+ -+ r = create_proc_read_entry("driver/i2c-adaptor-register", 0, NULL, -+ gen_i2c_read_proc, NULL); -+ if (!r) -+ return -ENOMEM; -+ return 0; -+} -+#else -+static inline int gen_i2c_proc_init(void) { return 0; } -+#endif /* CONFIG_PROC_FS */ -+ -+/* -+ * Initalize I2C module -+ */ -+static int __init i2c_coldfire_init(void) -+{ -+ int retval; -+ u8 dummy_read; -+ -+#ifdef DEBUG -+ printk(KERN_INFO "init i2c adaptor slave mode!\n"); -+#endif -+ -+ /* Initialize the tx buffer */ -+ strcpy((char *)&i2c_tx_buffer.buf, (const char *)tx_string); -+ i2c_tx_buffer.length = I2C_BUFFER_SIZE; -+ -+#if defined(CONFIG_M5445X) -+ /* -+ * Initialize the GPIOs for I2C -+ */ -+ MCF_GPIO_PAR_FECI2C |= (0 -+ | MCF_GPIO_PAR_FECI2C_PAR_SDA(3) -+ | MCF_GPIO_PAR_FECI2C_PAR_SCL(3)); -+#endif -+ -+ /* Set transmission frequency 0x19 = ~100kHz */ -+ MCF_I2FDR = 0x19; -+ -+ /* set the I2C slave address */ -+ MCF_I2AR = 0x6A; -+ -+ /* Enable I2C module and if IBB is set, do the special initialzation */ -+ /* procedures as are documented */ -+ -+ if ((MCF_I2SR & MCF_I2SR_IBB) == 1) { -+ printk(KERN_INFO "%s - do special I2C init procedures\n", -+ __func__); -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0xA0; -+ dummy_read = MCF_I2DR; -+ MCF_I2SR = 0x00; -+ MCF_I2CR = 0x00; -+ } -+ -+ MCF_I2CR |= (MCF_I2CR_IEN | MCF_I2CR_IIEN); -+ -+ /* default I2C mode is - slave and receive */ -+ MCF_I2CR &= ~(MCF_I2CR_MSTA | MCF_I2CR_MTX); -+ -+ retval = request_irq(IRQ, i2c_slave_handler, IRQF_DISABLED, -+ SLAVE_HANDLER_NAME, NULL); -+ if (retval < 0) -+ printk(KERN_INFO "request_irq for i2c slave mode failed!\n"); -+ -+ retval = gen_i2c_proc_init(); -+ -+ if (retval < 0) -+ printk(KERN_INFO "gen /proc/i2c-adaptor-register for i2c slave mode failed!\n"); -+ -+ return retval; -+}; -+ -+/* -+ * I2C module exit function -+ */ -+ -+static void __exit i2c_coldfire_exit(void) -+{ -+ /* disable I2C and Interrupt */ -+ MCF_I2CR &= ~(MCF_I2CR_IEN | MCF_I2CR_IIEN); -+ free_irq(IRQ, NULL); -+ -+}; -+ -+MODULE_DESCRIPTION("MCF5445x I2C adaptor slave mode support"); -+MODULE_LICENSE("GPL"); -+ -+module_init(i2c_coldfire_init); -+module_exit(i2c_coldfire_exit); ---- /dev/null -+++ b/drivers/i2c/busses/i2c-mcf.c -@@ -0,0 +1,698 @@ -+/* -+ * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. -+ * Lanttor.Guo@freescale.com -+ * -+ * I2C bus driver on mcfv4/mcfv4e platform -+ * -+ * 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; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+#include <linux/i2c.h> -+#include "i2c-algo-mcf.h" -+ -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/platform_device.h> -+#include <linux/sched.h> -+#include <linux/interrupt.h> -+#include <linux/io.h> -+#include <linux/proc_fs.h> -+ -+#include <asm/coldfire.h> -+#include <asm/mcfi2c.h> -+ -+#if defined(CONFIG_M547X_8X) -+#include <asm/m5485sim.h> -+#elif defined(CONFIG_M5445X) || defined(CONFIG_M5441X) -+#include <asm/mcfsim.h> -+#endif -+ -+#define get_clock(adap) (clock) -+#define get_own(adap) (own) -+ -+#if defined(CONFIG_M547X_8X) -+static int clock = 0x3b; -+#elif defined(CONFIG_M5445X) || defined(CONFIG_M5441X) -+static int clock = 0x19; -+#endif -+module_param(clock, int, 0); -+MODULE_PARM_DESC(clock, -+ "Set I2C clock in kHz: 400=fast mode (default == 100khz)"); -+ -+static int own = 0x78; -+module_param(own, int, 0); -+MODULE_PARM_DESC(clock, "Set I2C Master controller address"); -+ -+static struct i2c_algo_mcf_data i2c_mcf_board_data = { -+ .timeout = 10000, -+}; -+ -+static struct i2c_adapter i2c_mcf_board_adapter = { -+ .owner = THIS_MODULE, -+ .name = "mcf i2c adapter", -+ .algo_data = &i2c_mcf_board_data, -+ .class = I2C_CLASS_HWMON, -+ .timeout = 100, -+ .retries = 2 -+}; -+/* -+ * static void i2c_start() -+ * -+ * Generates START signal -+ */ -+static void -+i2c_start( -+ struct i2c_algo_mcf_data *adap -+) { -+ MCF_I2CR |= MCF_I2CR_MSTA; -+} -+ -+ -+/* -+ * static void i2c_stop() -+ * -+ * Generates STOP signal -+ */ -+static void -+i2c_stop( -+ struct i2c_algo_mcf_data *adap -+) { -+ MCF_I2CR &= ~MCF_I2CR_MSTA; -+} -+ -+static int -+i2c_getack( -+ struct i2c_algo_mcf_data *adap -+) { -+ return !(MCF_I2SR & MCF_I2SR_RXAK); -+} -+ -+/* -+ * static void wait_for_bb() -+ * -+ * Wait for bus idle state -+ */ -+static int -+wait_for_bb( -+ struct i2c_algo_mcf_data *adap -+) { -+ int i; -+ for (i = 0; i < adap->timeout; i++) { -+ if (!(MCF_I2SR & MCF_I2SR_IBB)) -+ return 0; -+ udelay(100); -+ } -+ printk(KERN_ERR "%s: timeout", __func__); -+ return -ETIMEDOUT; -+} -+ -+/* -+ * static void wait_for_not_bb() -+ * -+ * Wait for bus busy state -+ */ -+static int -+wait_for_not_bb( -+ struct i2c_algo_mcf_data *adap -+) { -+ int i; -+ for (i = 0; i < adap->timeout; i++) { -+ if (MCF_I2SR & MCF_I2SR_IBB) -+ return 0; -+ udelay(100); -+ } -+ printk(KERN_ERR "%s: timeout", __func__); -+ return -ETIMEDOUT; -+} -+ -+/* -+ * static void wait_xfer_done() -+ * -+ * Wait for transfer to complete -+ */ -+static int -+wait_xfer_done( -+ struct i2c_algo_mcf_data *adap -+) { -+ int i; -+ -+ for (i = 0; i < adap->timeout; i++) { -+ if (MCF_I2SR & MCF_I2SR_IIF) { -+ MCF_I2SR &= ~MCF_I2SR_IIF; -+ return 0; -+ } -+ udelay(10); -+ } -+ printk(KERN_ERR "%s: timeout", __func__); -+ return -ETIMEDOUT; -+} -+ -+ -+/* -+ * static void i2c_set_addr() -+ * -+ * Sets slave address to communicate -+ */ -+static int -+i2c_set_addr( -+ struct i2c_algo_mcf_data *adap, -+ struct i2c_msg *msg, -+ int retries -+) { -+ unsigned short flags = msg->flags; -+ unsigned char addr; -+ MCF_I2CR |= MCF_I2CR_MTX; -+ if ((flags & I2C_M_TEN)) { -+ /* 10 bit address not supported yet */ -+ return -EIO; -+ } else { -+ /* normal 7bit address */ -+ addr = (msg->addr << 1); -+ if (flags & I2C_M_RD) -+ addr |= 1; -+ if (flags & I2C_M_REV_DIR_ADDR) -+ addr ^= 1; -+ -+ MCF_I2DR = addr; -+ } -+ return 0; -+} -+ -+ -+/* -+ * static void mcf_i2c_init() -+ * -+ * Perform ColdFire i2c initialization -+ */ -+static void -+mcf_i2c_init(struct i2c_algo_mcf_data *adap) -+{ -+ u8 dummy; -+ -+ /* Setup GPIO lines */ -+#if defined(CONFIG_M547X_8X) -+ MCF_PAR_FECI2CIRQ |= MCF_PAR_SDA; -+ MCF_PAR_FECI2CIRQ |= MCF_PAR_SCL; -+#elif defined(CONFIG_M5445X) -+ MCF_GPIO_PAR_FECI2C |= (0 -+ | MCF_GPIO_PAR_FECI2C_PAR_SDA(3) -+ | MCF_GPIO_PAR_FECI2C_PAR_SCL(3)); -+#elif defined(CONFIG_M5441X) -+ MCF_GPIO_PAR_CANI2C = -+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_I2C0SCL_MASK) | -+ MCF_GPIO_PAR_CANI2C_I2C0SCL_I2C0SCL; -+ MCF_GPIO_PAR_CANI2C = -+ (MCF_GPIO_PAR_CANI2C & MCF_GPIO_PAR_CANI2C_I2C0SDA_MASK) | -+ MCF_GPIO_PAR_CANI2C_I2C0SDA_I2C0SDA; -+#endif -+ -+ /* Ensure slaves are in idle state */ -+ if (MCF_I2SR & MCF_I2SR_IBB) { -+#if defined(CONFIG_M547X_8X) -+ MCF_I2ICR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0x0A; -+ dummy = MCF_I2DR; -+ MCF_I2SR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2ICR = 0x01; -+#elif defined(CONFIG_M5445X) || defined(CONFIG_M5441X) -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0xA0; -+ dummy = MCF_I2DR; -+ MCF_I2SR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0x80; -+#endif -+ } -+ -+ /* setup SCL clock */ -+ MCF_I2FDR = get_clock(adap); -+ -+ /* set slave address */ -+ MCF_I2AR = get_own(adap); -+ -+ /* enable I2C module */ -+#if defined(CONFIG_M5441X) -+ MCF_I2CR = (MCF_I2CR_IEN | MCF_I2CR_IIEN); -+#else -+ MCF_I2CR = MCF_I2CR_IEN; -+#endif -+} -+ -+static int i2c_outb( -+ struct i2c_adapter *i2c_adap, -+ char c -+) { -+ -+ struct i2c_algo_mcf_data *adap = i2c_adap->algo_data; -+ int timeout; -+ /* Put data to be sent */ -+ MCF_I2DR = c; -+ /* Wait for xfer completed*/ -+ timeout = wait_xfer_done(adap); -+ if (timeout) { -+ i2c_stop(adap); -+ wait_for_bb(adap); -+ printk(KERN_ERR "i2c-algo-mcf: %s i2c_write: " -+ "error - timeout.\n", i2c_adap->name); -+ return -EREMOTEIO; /* got a better one ?? */ -+ } -+ -+ return 0; -+} -+ -+ -+/* -+ * static void mcf_sendbytes() -+ * -+ * Perform tx data transfer -+ */ -+static int -+mcf_sendbytes( -+ struct i2c_adapter *i2c_adap, -+ const char *buf, -+ int count, int last -+) { -+ struct i2c_algo_mcf_data *adap = i2c_adap->algo_data; -+ int ret, i; -+ -+ /* Set master TX mode */ -+ MCF_I2CR |= MCF_I2CR_MTX; -+ -+ for (i = 0; i < count; ++i) { -+ printk(KERN_DEBUG "i2c-algo-mcf: %s i2c_write: writing %2.2X\n", -+ i2c_adap->name, buf[i]&0xff); -+ ret = i2c_outb(i2c_adap, buf[i]); -+ if (ret < 0) -+ return ret; -+ } -+ if (last) { -+ i2c_stop(adap); -+ wait_for_bb(adap); -+ } else { -+ /* i2c_repstart(adap);*/ -+ } -+ -+ return i; -+} -+ -+ -+/* -+ * static void mcf_readbytes() -+ * -+ * Perform rx data transfer -+ */ -+static int -+mcf_readbytes( -+ struct i2c_adapter *i2c_adap, -+ char *buf, -+ int count, int last -+) { -+ int i; -+ struct i2c_algo_mcf_data *adap = i2c_adap->algo_data; -+ u8 dummy; -+ -+ /* Set master RX mode */ -+ MCF_I2CR &= ~MCF_I2CR_MTX; -+ MCF_I2CR &= ~MCF_I2CR_TXAK; -+ dummy = MCF_I2DR; -+ -+ for (i = 0; i < count-1; i++) { -+ if (wait_xfer_done(adap)) { -+ i2c_stop(adap); -+ wait_for_bb(adap); -+ printk(KERN_DEBUG -+ "i2c-algo-mcf: mcf_readbytes timed out.\n"); -+ return -1; -+ } -+ -+ /* store next data byte */ -+ buf[i] = MCF_I2DR; -+ } -+ -+ if (wait_xfer_done(adap)) { -+ i2c_stop(adap); -+ wait_for_bb(adap); -+ printk(KERN_DEBUG "i2c-algo-mcf: mcf_readbytes timed out.\n"); -+ return -1; -+ } -+ -+ /* Disable acknowlege (set I2CR.TXAK) */ -+ MCF_I2CR |= MCF_I2CR_TXAK; -+ buf[i] = MCF_I2DR; -+ if (wait_xfer_done(adap)) { -+ i2c_stop(adap); -+ wait_for_bb(adap); -+ printk(KERN_DEBUG "i2c-algo-mcf: mcf_readbytes timed out.\n"); -+ return -1; -+ } -+ -+ if (last) { -+ i2c_stop(adap); -+ wait_for_bb(adap); -+ } else { -+ /* i2c_repstart(adap);*/ -+ } -+ -+ return i+1; -+} -+ -+ -+/* -+ * static void mcf_xfer() -+ * -+ * Perform master data I/O transfer -+ */ -+static int -+mcf_xfer( -+ struct i2c_adapter *i2c_adap, -+ struct i2c_msg *msgs, -+ int num) -+{ -+ struct i2c_algo_mcf_data *adap = i2c_adap->algo_data; -+ struct i2c_msg *pmsg; -+ int i; -+ int ret = 0, timeout; -+ -+ /* Skip own address */ -+ if (get_own(adap) == (msgs[0].addr << 1)) -+ return -EIO; -+ -+ /* Ensure slaves are in idle state */ -+ if (MCF_I2SR & MCF_I2SR_IBB) { -+#if defined(CONFIG_M547X_8X) -+ MCF_I2ICR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0x0A; -+ timeout = MCF_I2DR; -+ MCF_I2SR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2ICR = 0x01; -+#elif defined(CONFIG_M5445X) || defined(CONFIG_M5441X) -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0xA0; -+ timeout = MCF_I2DR; -+ MCF_I2SR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0x80; -+#endif -+ } -+ -+ /* setup SCL clock */ -+ MCF_I2FDR = get_clock(adap); -+ /* set slave address */ -+ MCF_I2AR = get_own(adap); -+ /* enable I2C module */ -+#if defined(CONFIG_M5441X) -+ MCF_I2CR = (MCF_I2CR_IEN | MCF_I2CR_IIEN); -+#else -+ MCF_I2CR = MCF_I2CR_IEN; -+#endif -+ MCF_I2CR |= MCF_I2CR_TXAK; -+ -+ /* Check for bus busy */ -+ wait_for_bb(adap); -+ -+ for (i = 0; ret >= 0 && i < num; i++) { -+ if (MCF_I2SR & MCF_I2SR_IBB) { -+#if defined(CONFIG_M547X_8X) -+ MCF_I2ICR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0x0A; -+ timeout = MCF_I2DR; -+ MCF_I2SR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2ICR = 0x01; -+#elif defined(CONFIG_M5445X) || defined(CONFIG_M5441X) -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0xA0; -+ timeout = MCF_I2DR; -+ MCF_I2SR = 0x00; -+ MCF_I2CR = 0x00; -+ MCF_I2CR = 0x80; -+#endif -+ } -+ /* setup SCL clock */ -+ MCF_I2FDR = get_clock(adap); -+ /* set slave address */ -+ MCF_I2AR = get_own(adap); -+ /* enable I2C module */ -+#if defined(CONFIG_M5441X) -+ MCF_I2CR = (MCF_I2CR_IEN | MCF_I2CR_IIEN); -+#else -+ MCF_I2CR = MCF_I2CR_IEN; -+#endif -+ MCF_I2CR |= MCF_I2CR_TXAK; -+ -+ /* Check for bus busy */ -+ wait_for_bb(adap); -+ -+ pmsg = &msgs[i]; -+ -+ printk(KERN_DEBUG "i2c-algo-mcf: Doing %s %d bytes " -+ "to 0x%02x - %d of %d messages\n", -+ pmsg->flags & I2C_M_RD ? "read" : "write", -+ pmsg->len, pmsg->addr, i + 1, num); -+ -+ /* Send START */ -+ /*if (i == 0)*/ -+ i2c_start(adap); -+ -+ /* Wait for Bus Busy */ -+ wait_for_not_bb(adap); -+ -+ MCF_I2CR |= MCF_I2CR_MTX; -+ -+ ret = i2c_set_addr(adap, pmsg, i2c_adap->retries); -+ if (ret < 0) -+ return ret; -+ -+ /* Wait for address transfer completion */ -+ wait_xfer_done(adap); -+ -+ /* Check for ACK */ -+ if (!i2c_getack(adap)) { -+ i2c_stop(adap); -+ wait_for_bb(adap); -+ printk(KERN_DEBUG "i2c-algo-mcf: No ack after " -+ "send address in mcf_xfer\n"); -+ return -EREMOTEIO; -+ } -+ -+ printk(KERN_DEBUG "i2c-algo-mcf: Msg %d, " -+ "addr = 0x%x, flags = 0x%x, len = %d\n", -+ i, msgs[i].addr, msgs[i].flags, msgs[i].len); -+ /* Read */ -+ if (pmsg->flags & I2C_M_RD) { -+ /* read bytes into buffer*/ -+ ret = mcf_readbytes(i2c_adap, pmsg->buf, pmsg->len, -+ (i + 1 == num)); -+ -+ if (ret != pmsg->len) { -+ printk(KERN_DEBUG "i2c-algo-mcf: fail: " -+ "only read %d bytes.\n", ret); -+ } else { -+ printk(KERN_DEBUG "i2c-algo-mcf: " -+ "read %d bytes.\n", ret); -+ } -+ } else { -+ /* write bytes into buffer*/ -+ ret = mcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len, -+ (i + 1 == num)); -+ if (ret != pmsg->len) { -+ printk(KERN_DEBUG "i2c-algo-mcf: fail: " -+ "only wrote %d bytes.\n", ret); -+ } else { -+ printk(KERN_DEBUG "i2c-algo-mcf: wrote" -+ "%d bytes.\n", ret); -+ } -+ } -+ MCF_I2CR = 0; -+ } -+ -+ /* Disable I2C module */ -+ MCF_I2CR = 0; -+ return i; -+} -+ -+ -+/* -+ * static void mcf_func() -+ * -+ * Return algorithm funtionality -+ */ -+static u32 -+mcf_func( -+ struct i2c_adapter *i2c_adap -+) { -+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; -+} -+ -+/* -+ * ColdFire bus algorithm callbacks -+ */ -+static struct i2c_algorithm mcf_algo = { -+ .master_xfer = mcf_xfer, -+ .functionality = mcf_func, -+}; -+ -+/***********************************************************/ -+struct coldfire_i2c { -+ void __iomem *base; -+ struct resource *irqarea; -+ struct resource *ioarea; -+ u32 irq; -+ struct i2c_adapter *adap; -+ u32 flags; -+}; -+ -+/* -+ * registering functions to load algorithms at runtime -+ */ -+int i2c_mcf_add_bus(struct i2c_adapter *adap) -+{ -+ struct i2c_algo_mcf_data *mcf_adap = adap->algo_data; -+ -+ /*adap->id |= mcf_algo.id;*/ -+ adap->algo = &mcf_algo; -+ adap->timeout = 100; -+ -+ mcf_i2c_init(mcf_adap); -+ -+ i2c_add_numbered_adapter(adap); -+ -+ return 0; -+} -+ -+static int mcf_i2c_probe(struct platform_device *pdev) -+{ -+ struct coldfire_i2c *i2c; -+ int rc = 0; -+ -+ /************************************************************/ -+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); -+ if (!i2c) { -+ printk(KERN_ERR "%s kzalloc coldfire_i2c faile\n", -+ __func__); -+ return -ENOMEM; -+ } -+ /****************************************************************/ -+ platform_set_drvdata(pdev, i2c); -+ -+ i2c->adap = &i2c_mcf_board_adapter; -+ i2c->adap->dev.parent = &pdev->dev; -+ i2c->adap->nr = pdev->id; -+ rc = i2c_mcf_add_bus(i2c->adap); -+ if (rc < 0) { -+ printk(KERN_ERR "%s - failed to add adapter\n", __func__); -+ rc = -ENODEV; -+ goto fail_add; -+ } -+ -+ printk(KERN_INFO "i2c-algo-mcf.o: I2C ColdFire algorithm" -+ " module is loaded.\n"); -+ return rc; -+ -+fail_add: -+ kfree(i2c); -+ return rc; -+}; -+ -+static int mcf_i2c_remove(struct platform_device *pdev) -+{ -+ struct coldfire_i2c *i2c = platform_get_drvdata(pdev); -+ -+ i2c_del_adapter(i2c->adap); -+ platform_set_drvdata(pdev, NULL); -+ iounmap(i2c->base); -+ kfree(i2c); -+ return 0; -+}; -+ -+/* Structure for a device driver */ -+static struct platform_driver mcf_i2c_driver = { -+ .probe = mcf_i2c_probe, -+ .remove = mcf_i2c_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "mcf-i2c", -+ }, -+}; -+ -+#ifdef CONFIG_PROC_FS -+ -+/* -+ * Info exported via "/proc/driver/i2c". -+ */ -+ -+static int gen_i2c_proc_output(char *buf) -+{ -+ char *p; -+ -+ p = buf; -+ p += sprintf(p, -+ "I2CR: 0x%x\n" -+ "I2SR: 0x%x\n" -+ "I2DR: 0x%x\n", -+ MCF_I2CR, MCF_I2SR, MCF_I2DR); -+ -+ return p - buf; -+} -+ -+static int gen_i2c_read_proc(char *page, char **start, off_t off, -+ int count, int *eof, void *data) -+{ -+ int len = gen_i2c_proc_output(page); -+ if (len <= off+count) -+ *eof = 1; -+ *start = page + off; -+ len -= off; -+ if (len > count) -+ len = count; -+ if (len < 0) -+ len = 0; -+ return len; -+} -+ -+static int __init gen_i2c_proc_init(void) -+{ -+ struct proc_dir_entry *r; -+ -+ r = create_proc_read_entry("driver/i2c-adaptor-register", 0, NULL, -+ gen_i2c_read_proc, NULL); -+ if (!r) -+ return -ENOMEM; -+ return 0; -+} -+#else -+static inline int gen_i2c_proc_init(void) { return 0; } -+#endif /* CONFIG_PROC_FS */ -+ -+static int __init coldfire_i2c_init(void) -+{ -+ int retval; -+ -+ retval = gen_i2c_proc_init(); -+ if (retval < 0) -+ printk(KERN_INFO "generate /proc/i2c-adaptor-register " -+ "for i2c master mode failed!\n"); -+ -+ return platform_driver_register(&mcf_i2c_driver); -+} -+ -+static void __exit coldfire_i2c_exit(void) -+{ -+ platform_driver_unregister(&mcf_i2c_driver); -+} -+ -+module_init(coldfire_i2c_init); -+module_exit(coldfire_i2c_exit); -+ -+MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>"); -+MODULE_DESCRIPTION("I2C-Bus adapter for MCFV4/MCFV4E processors"); -+MODULE_LICENSE("GPL"); |