diff -uprN -X dontdiff-osdl linux-2.6.11.6/drivers/i2c/busses/i2c-mcf5282.c linux_dev/drivers/i2c/busses/i2c-mcf5282.c --- linux-2.6.11.6/drivers/i2c/busses/i2c-mcf5282.c 1969-12-31 19:00:00.000000000 -0500 +++ linux_dev/drivers/i2c/busses/i2c-mcf5282.c 2005-04-13 18:15:12.000000000 -0400 @@ -0,0 +1,414 @@ +/* + i2c-mcf5282.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + + Copyright (c) 2005, Derek CL Cheung + + + 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. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Changes: + v0.1 26 March 2005 + Initial Release - developed on uClinux with 2.6.9 kernel + v0.2 11 April 2005 + Coding style changes + + This I2C adaptor supports the ColdFire 5282 CPU I2C module. Since most + Coldfire CPUs' I2C module use the same register set (e.g., MCF5249), + the code is very portable and re-usable for other Coldfire CPUs. + + The transmission frequency is set at about 100KHz for the 5282Lite CPU + board with 8MHz crystal. If the CPU board uses different system clock + frequency, you should change the following line: + static int __init i2c_mcf5282_init(void) + { + ......... + // Set transmission frequency 0x15 = ~100kHz + *MCF5282_I2C_I2FDR = 0x15; + ........ + } + + Remember to perform a dummy read to set the ColdFire CPU's I2C module before + reading the actual byte from a device on the I2C bus. + + The I2C_SM_BUS_BLOCK_DATA function are not yet ready but most lm_senors + do not care + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-mcf5282.h" + +static struct i2c_algorithm mcf5282_algorithm = { + .name = "MCF5282 I2C algorithm", + .id = I2C_ALGO_SMBUS, + .smbus_xfer = mcf5282_i2c_access, + .functionality = mcf5282_func, +}; + +static struct i2c_adapter mcf5282_adapter = { + .owner = THIS_MODULE, + .class = I2C_CLASS_HWMON, + .algo = &mcf5282_algorithm, + .name = "MCF5282 I2C Adapter", +}; + +/* + * read one byte data from the I2C bus + */ +static int mcf5282_read_data(u8 * const rxData, + const enum I2C_ACK_TYPE ackType) { + + int timeout; + + *MCF5282_I2C_I2CR &= ~MCF5282_I2C_I2CR_MTX; /* master receive mode */ + + if (ackType == NACK) + *MCF5282_I2C_I2CR |= MCF5282_I2C_I2CR_TXAK; /* generate NA */ + else + *MCF5282_I2C_I2CR &= ~MCF5282_I2C_I2CR_TXAK; /* generate ACK */ + + /* read data from the I2C bus */ + *rxData = *MCF5282_I2C_I2DR; + + /* printk(KERN_DEBUG "%s I2DR is %.2x \n", __FUNCTION__, *rxData); */ + + /* wait for data transfer to complete */ + timeout = 500; + while (timeout-- && !(*MCF5282_I2C_I2SR & MCF5282_I2C_I2SR_IIF)) + udelay(1); + if (timeout <= 0) + printk(KERN_WARNING "%s - I2C IIF never set \n", __FUNCTION__); + + /* reset the interrupt bit */ + *MCF5282_I2C_I2SR &= ~MCF5282_I2C_I2SR_IIF; + + if (timeout <= 0) + return -1; + else + return 0; +}; + + +/* + * write one byte data onto the I2C bus + */ +static int mcf5282_write_data(const u8 txData) { + + int timeout; + + timeout = 500; + + *MCF5282_I2C_I2CR |= MCF5282_I2C_I2CR_MTX; /* I2C module into TX mode */ + *MCF5282_I2C_I2DR = txData; /* send the data */ + + /* wait for data transfer to complete + rely on the interrupt handling bit */ + timeout = 500; + while (timeout-- && !(*MCF5282_I2C_I2SR & MCF5282_I2C_I2SR_IIF)) + udelay(1); + if (timeout <= 0) + printk(KERN_DEBUG "%s - I2C IIF never set \n", __FUNCTION__); + + /* reset the interrupt bit */ + *MCF5282_I2C_I2SR &= ~MCF5282_I2C_I2SR_IIF; + + if (timeout <= 0) + return -1; + else + return 0; +}; + + +/* + * Generate I2C start or repeat start signal + * Combine the 7 bit target_address and the R/W bit and put it onto the I2C bus + */ +static int mcf5282_i2c_start(const char read_write, const u16 target_address, + const enum I2C_START_TYPE start_type) { + + int timeout; + + /* printk(KERN_DEBUG ">>> %s START TYPE %s \n", __FUNCTION__, + start_type == FIRST_START ? "FIRST_START" : "REPEAT_START"); */ + + *MCF5282_I2C_I2CR |= MCF5282_I2C_I2CR_IEN; + + if (start_type == FIRST_START) { + /* Make sure the I2C bus is idle */ + timeout = 500; /* 500us timeout */ + while (timeout-- && (*MCF5282_I2C_I2SR & MCF5282_I2C_I2SR_IBB)) + udelay(1); + if (timeout <= 0) { + printk(KERN_WARNING "%s - I2C bus is busy in the \ + past 500us \n", __FUNCTION__); + goto check_rc; + } + /* generate a START & put the I2C module into MASTER TX mode */ + *MCF5282_I2C_I2CR |= (MCF5282_I2C_I2CR_MSTA | + MCF5282_I2C_I2CR_MTX); + + /* wait for bus busy to be set */ + timeout = 500; + while (timeout-- && !(*MCF5282_I2C_I2SR & MCF5282_I2C_I2SR_IBB)) + udelay(1); + if (timeout <= 0) { + printk(KERN_WARNING "%s - I2C bus is never busy after \ + START \n", __FUNCTION__); + goto check_rc; + } + } else { + /* this is repeat START */ + udelay(500); /* need some delay before repeat start */ + *MCF5282_I2C_I2CR |= (MCF5282_I2C_I2CR_MSTA | + MCF5282_I2C_I2CR_RSTA); + } + + /* combine the R/W bit and the 7 bit target address and + put it onto the I2C bus */ + *MCF5282_I2C_I2DR = ((target_address & 0x7F) << 1) | + (read_write == I2C_SMBUS_WRITE ? 0x00 : 0x01); + + /* wait for bus transfer to complete + when one byte transfer is completed, IIF set at the faling edge + of the 9th clock */ + timeout = 500; + while (timeout-- && !(*MCF5282_I2C_I2SR & MCF5282_I2C_I2SR_IIF)) + udelay(1); + if (timeout <= 0) + printk(KERN_WARNING "%s - I2C IIF never set \n", __FUNCTION__); + +check_rc: + /* reset the interrupt bit */ + *MCF5282_I2C_I2SR &= ~MCF5282_I2C_I2SR_IIF; + + if (timeout <= 0) + return -1; + else + return 0; +}; + + +/* + * 5282 SMBUS supporting functions + */ + +static s32 mcf5282_i2c_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + int rc = 0; + u8 rxData, tempRxData[2]; + + switch (size) { + case I2C_SMBUS_QUICK: + /* dev_info(&adap->dev, "size = I2C_SMBUS_QUICK \n"); */ + /* generate an I2C start */ + rc = mcf5282_i2c_start(read_write, addr, FIRST_START); + break; + case I2C_SMBUS_BYTE: + /* dev_info(&adap->dev, "size = I2C_SMBUS_BYTE \n"); */ + rc = mcf5282_i2c_start(read_write, addr, FIRST_START); + /* generate NA */ + *MCF5282_I2C_I2CR |= MCF5282_I2C_I2CR_TXAK; + if (read_write == I2C_SMBUS_WRITE) + rc += mcf5282_write_data(command); + else { + /* dummy read */ + mcf5282_read_data(&rxData, NACK); + rc += mcf5282_read_data(&rxData, NACK); + data->byte = rxData; + } + /* reset the ACK bit */ + *MCF5282_I2C_I2CR &= ~MCF5282_I2C_I2CR_TXAK; + break; + case I2C_SMBUS_BYTE_DATA: + /* dev_info(&adap->dev, "size = I2C_SMBUS_BYTE_DATA \n"); */ + rc = mcf5282_i2c_start(I2C_SMBUS_WRITE, addr, FIRST_START); + rc += mcf5282_write_data(command); + if (read_write == I2C_SMBUS_WRITE) + rc += mcf5282_write_data(data->byte); + else { + /* This is SMBus READ Byte Data Request. + Perform REPEAT START */ + rc += mcf5282_i2c_start(I2C_SMBUS_READ, addr, + REPEAT_START); + /* dummy read */ + mcf5282_read_data(&rxData, ACK); + /* Disable Acknowledge, generate STOP after + next byte transfer */ + rc += mcf5282_read_data(&rxData, NACK); + data->byte = rxData; + } + /* reset to normal ACK */ + *MCF5282_I2C_I2CR &= ~MCF5282_I2C_I2CR_TXAK; + break; + case I2C_SMBUS_PROC_CALL: + /* dev_info(&adap->dev, "size = I2C_SMBUS_PROC_CALL \n"); */ + printk(KERN_WARNING "Not support I2C_SMBUS_PROC_CALL yet \n"); + rc = -2; + break; + case I2C_SMBUS_WORD_DATA: + /* dev_info(&adap->dev, "I2C_SMBUS_WORD_DATA \n"); */ + rc = mcf5282_i2c_start(I2C_SMBUS_WRITE, addr, FIRST_START); + rc += mcf5282_write_data(command); + if (read_write == I2C_SMBUS_WRITE) { + rc += mcf5282_write_data(data->word & 0x00FF); + rc += mcf5282_write_data((data->word & 0x00FF) >> 8); + } else { + /* This is SMBUS READ WORD request. + Peform REPEAT START */ + rc += mcf5282_i2c_start(I2C_SMBUS_READ, addr, + REPEAT_START); + /* dummy read */ + mcf5282_read_data(&rxData, ACK); + /* Disable Acknowledge, generate STOP + after next byte transfer */ + /* read the MS byte from the device */ + rc += mcf5282_read_data(&rxData, NACK); + tempRxData[1] = rxData; + /* read the LS byte from the device */ + rc += mcf5282_read_data(&rxData, NACK); + tempRxData[0] = rxData; + /* the host driver expect little endian + convention. Swap the byte */ + data->word = (tempRxData[0] << 8) | tempRxData[1]; + /* printk(KERN_DEBUG "SMBUS_WORD_DATA %.4x \n", + data->word); */ + } + *MCF5282_I2C_I2CR &= ~MCF5282_I2C_I2CR_TXAK; + break; + case I2C_SMBUS_BLOCK_DATA: +#if NOT_READY_YET + dev_info(&adap->dev, "size = I2C_SMBUS_BLOCK_DATA\n"); + if (read_write == I2C_SMBUS_WRITE) { + dev_info(&adap->dev, "data = %.4x\n", data->word); + len = data->block[0]; + if (len < 0) + len = 0; + if (len > 32) + len = 32; + for (i = 1; i <= len; i++) + dev_info(&adap->dev, "data->block[%d] \ + = %.2x\n", i, data->block[i]); + } +#endif + break; + default: + printk(KERN_WARNING "Unsupported I2C size \n"); + rc = -1; + break; + }; + + /* Generate a STOP and put I2C module into slave mode */ + *MCF5282_I2C_I2CR &= ~MCF5282_I2C_I2CR_MSTA; + + /* restore interrupt */ + *MCF5282_I2C_I2CR |= MCF5282_I2C_I2CR_IIEN; + + return rc; +}; + + +/* + * List the SMBUS functions supported by this I2C adaptor + */ +static u32 mcf5282_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA; +}; + + +/* + * Initalize the 5282 I2C module + * Disable the 5282 I2C interrupt capability. Just use callback + */ + +static int __init i2c_mcf5282_init(void) +{ + int retval; + u8 dummyRead; + + /* Initialize PASP0 and PASP1 to I2C functions - 5282 user guide 26-19 + Port AS Pin Assignment Register (PASPAR) + PASPA1 = 11 = AS1 pin is I2C SDA + PASPA0 = 11 = AS0 pin is I2C SCL */ + /* u16 declaration */ + *MCF5282_GPIO_PASPAR |= 0x000F; + + /* Set transmission frequency 0x15 = ~100kHz */ + *MCF5282_I2C_I2FDR = 0x15; + + /* set the 5282 I2C slave address thought we never use it */ + *MCF5282_I2C_I2ADR = 0x6A; + + /* Enable I2C module and if IBB is set, do the special initialzation + procedures as are documented at the 5282 User Guide page 24-11 */ + *MCF5282_I2C_I2CR |= MCF5282_I2C_I2CR_IEN; + if ((*MCF5282_I2C_I2SR & MCF5282_I2C_I2SR_IBB) == 1) { + /* printk(KERN_DEBUG "5282 I2C init procedures \n"); */ + *MCF5282_I2C_I2CR = 0x00; + *MCF5282_I2C_I2CR = 0xA0; + dummyRead = *MCF5282_I2C_I2DR; + *MCF5282_I2C_I2SR = 0x00; + *MCF5282_I2C_I2CR = 0x00; + } + + /* default I2C mode is - slave and receive */ + *MCF5282_I2C_I2CR &= ~(MCF5282_I2C_I2CR_MSTA | MCF5282_I2C_I2CR_MTX); + + retval = i2c_add_adapter(&mcf5282_adapter); + + if (retval < 0) + printk(KERN_WARNING "%s - return code is: %d \n", __FUNCTION__, + retval); + + return retval; +}; + + +/* + * I2C module exit function + */ + +static void __exit i2c_mcf5282_exit(void) +{ + /* disable I2C and Interrupt */ + *MCF5282_I2C_I2CR &= ~(MCF5282_I2C_I2CR_IEN | MCF5282_I2C_I2CR_IIEN); + i2c_del_adapter(&mcf5282_adapter); +}; + + +MODULE_AUTHOR("Derek CL Cheung "); +MODULE_DESCRIPTION("MCF5282 I2C adaptor"); +MODULE_LICENSE("GPL"); + +module_init(i2c_mcf5282_init); +module_exit(i2c_mcf5282_exit); diff -uprN -X dontdiff-osdl linux-2.6.11.6/drivers/i2c/busses/i2c-mcf5282.h linux_dev/drivers/i2c/busses/i2c-mcf5282.h --- linux-2.6.11.6/drivers/i2c/busses/i2c-mcf5282.h 1969-12-31 19:00:00.000000000 -0500 +++ linux_dev/drivers/i2c/busses/i2c-mcf5282.h 2005-04-12 20:45:00.000000000 -0400 @@ -0,0 +1,46 @@ +/* + i2c-mcf5282.h - header file for i2c-mcf5282.c + + Copyright (c) 2005, Derek CL Cheung + + + 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. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Changes: + v0.1 26 March 2005 + Initial Release - developed on uClinux with 2.6.9 kernel + +*/ + + +#ifndef __I2C_MCF5282_H__ +#define __I2C_MCF5282_H__ + +enum I2C_START_TYPE { FIRST_START, REPEAT_START }; +enum I2C_ACK_TYPE { ACK, NACK }; + +/* Function prototypes */ +static u32 mcf5282_func(struct i2c_adapter *adapter); +static s32 mcf5282_i2c_access(struct i2c_adapter *adap, u16 address, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data); +static int mcf5282_write_data(const u8 data); +static int mcf5282_i2c_start(const char read_write, const u16 target_address, + const enum I2C_START_TYPE i2c_start); +static int mcf5282_read_data(u8 * const rxData, + const enum I2C_ACK_TYPE ackType); + +/********************************************************************/ +#endif /* __I2C_MCF5282_H__ */ diff -uprN -X dontdiff-osdl linux-2.6.11.6/drivers/i2c/busses/Kconfig linux_dev/drivers/i2c/busses/Kconfig --- linux-2.6.11.6/drivers/i2c/busses/Kconfig 2005-03-25 22:28:29.000000000 -0500 +++ linux_dev/drivers/i2c/busses/Kconfig 2005-04-12 20:45:24.000000000 -0400 @@ -39,6 +39,16 @@ config I2C_ALI15X3 This driver can also be built as a module. If so, the module will be called i2c-ali15x3. +config I2C_MCF5282 + tristate "MCF5282" + depends on I2C && EXPERIMENTAL + help + If you say yes to this option, support will be included for the + I2C on the ColdFire MCF5282Lite Development Board + + This driver can also be built as a module. If so, the module + will be called i2c-mcf5282. + config I2C_AMD756 tristate "AMD 756/766/768/8111 and nVidia nForce" depends on I2C && PCI && EXPERIMENTAL diff -uprN -X dontdiff-osdl linux-2.6.11.6/drivers/i2c/busses/Makefile linux_dev/drivers/i2c/busses/Makefile --- linux-2.6.11.6/drivers/i2c/busses/Makefile 2005-03-25 22:28:39.000000000 -0500 +++ linux_dev/drivers/i2c/busses/Makefile 2005-04-13 18:52:03.000000000 -0400 @@ -40,6 +40,7 @@ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o +obj-$(CONFIG_I2C_MCF5282) += i2c-mcf5282.o ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG diff -uprN -X dontdiff-osdl linux-2.6.11.6/include/asm-m68knommu/m528xsim.h linux_dev/include/asm-m68knommu/m528xsim.h --- linux-2.6.11.6/include/asm-m68knommu/m528xsim.h 2005-03-25 22:28:13.000000000 -0500 +++ linux_dev/include/asm-m68knommu/m528xsim.h 2005-04-12 19:49:51.000000000 -0400 @@ -41,5 +41,47 @@ #define MCFSIM_DACR1 0x50 /* SDRAM base address 1 */ #define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */ + +/********************************************************************* +* +* I2C Module +* Derek Cheung - 21 Feb 2005 +* Register definition for ColdFire 5282 +* +*********************************************************************/ +/* set Port AS pin for I2C or UART */ +#define MCF5282_GPIO_PASPAR (volatile u16 *) (MCF_IPSBAR + 0x00100056) + +/* Interrupt Mask Register Register Low */ +#define MCF5282_INTC0_IMRL (volatile u32 *) (MCF_IPSBAR + 0x0C0C) + +/* Interrupt Control Register 7 */ +#define MCF5282_INTC0_ICR17 (volatile u8 *) (MCF_IPSBAR + 0x0C51) + +/********************************************************************* +* Inter-IC (I2C) Module Specify Register definition +*********************************************************************/ +/* Read/Write access macros for general use */ +#define MCF5282_I2C_I2ADR (volatile u8 *) (MCF_IPSBAR + 0x0300) /* Address */ +#define MCF5282_I2C_I2FDR (volatile u8 *) (MCF_IPSBAR + 0x0304) /* F Divider */ +#define MCF5282_I2C_I2CR (volatile u8 *) (MCF_IPSBAR + 0x0308) /* Control */ +#define MCF5282_I2C_I2SR (volatile u8 *) (MCF_IPSBAR + 0x030C) /* Status */ +#define MCF5282_I2C_I2DR (volatile u8 *) (MCF_IPSBAR + 0x0310) /* Data I/O */ + +#define MCF5282_I2C_I2CR_IEN (0x80) /* I2C enable */ +#define MCF5282_I2C_I2CR_IIEN (0x40) /* interrupt enable */ +#define MCF5282_I2C_I2CR_MSTA (0x20) /* master/slave mode */ +#define MCF5282_I2C_I2CR_MTX (0x10) /* transmit/receive mode */ +#define MCF5282_I2C_I2CR_TXAK (0x08) /* transmit acknowledge enable */ +#define MCF5282_I2C_I2CR_RSTA (0x04) /* repeat start */ + +#define MCF5282_I2C_I2SR_ICF (0x80) /* data transfer bit */ +#define MCF5282_I2C_I2SR_IAAS (0x40) /* I2C addressed as a slave */ +#define MCF5282_I2C_I2SR_IBB (0x20) /* I2C bus busy */ +#define MCF5282_I2C_I2SR_IAL (0x10) /* aribitration lost */ +#define MCF5282_I2C_I2SR_SRW (0x04) /* slave read/write */ +#define MCF5282_I2C_I2SR_IIF (0x02) /* I2C interrupt */ +#define MCF5282_I2C_I2SR_RXAK (0x01) /* received acknowledge */ + /****************************************************************************/ #endif /* m528xsim_h */