I2C bus driver for IMX
Subsystems (5)
PATCH v4 1/1 I2C bus driver for IMX
Changes from previous version:
1. Used i2c_add_numbered_adapter() instead i2c_add_adapter()
2. Added i2c_imx->adapter.class = I2C_CLASS_HWMON;
---
arch/arm/mach-imx/mx1ads.c +21 -0
@@ -109,10 +109,31 @@ static struct platform_device imx_uart2_ } }; +static struct resource imx_i2c_resources[] = { + [0 ] = { + .start =0x00217000 , + .end =0x00217010 , + .flags =IORESOURCE_MEM , + }, + [1 ] = { + .start =I2C_INT , + .end =I2C_INT , + .flags =IORESOURCE_IRQ , + }, +}; + +static struct platform_device imx_i2c_device = { + .name ="imx-i2c" , + .id =0 , + .resource = imx_i2c_resources, + .num_resources =ARRAY_SIZE (imx_i2c_resources), +}; +static struct platform_device *devices[]__initdata = { &cs89x0_device, &imx_uart1_device, &imx_uart2_device, + &imx_i2c_device, };#ifdef CONFIG_MMC_IMX
drivers/i2c/busses/i2c-imx.c new file +612 -0
612 lines not on this page · raw message
drivers/i2c/busses/Kconfig +10 -0
@@ -257,6 +257,16 @@ config I2C_IBM_IIC This driver can also be built as a module. If so, the module will be called i2c-ibm_iic. +config I2C_IMX + tristate "IMX I2C interface" + depends on ARCH_IMX + help + Say Y here if you want to use the IIC bus controller on + the Freescale i.MXL and i.MX1 processors. + + This driver can also be built as a module. If so, the module + will be called i2c-imx. + config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
drivers/i2c/busses/Makefile +1 -0
@@ -18,6 +18,7 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_I810) += i2c-i810.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o +obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
include/asm-arm/arch-imx/imx-regs.h +25 -0
@@ -479,4 +479,29 @@#define LCDISR_EOF (1<<1)#define LCDISR_BOF (1<<0) +/* +* I2C +*/ + +#define IMX_I2C_IADR 0x00/* i2c slave address */ +#define IMX_I2C_IFDR 0x04/* i2c frequency divider */ +#define IMX_I2C_I2CR 0x08/* i2c control */ +#define IMX_I2C_I2SR 0x0C/* i2c status */ +#define IMX_I2C_I2DR 0x10/* i2c transfer data */ + +#define I2SR_RXAK 0x01 +#define I2SR_IIF 0x02 +#define I2SR_SRW 0x04 +#define I2SR_IAL 0x10 +#define I2SR_IBB 0x20 +#define I2SR_IAAS 0x40 +#define I2SR_ICF 0x80 + +#define I2CR_RSTA 0x04 +#define I2CR_TXAK 0x08 +#define I2CR_MTX 0x10 +#define I2CR_MSTA 0x20 +#define I2CR_IIEN 0x40 +#define I2CR_IEN 0x80 +#endif // _IMX_REGS_H
_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c
Quoted 7 lines · Darius
Changes from previous version:
1. Usedi2c_add_numbered_adapter()insteadi2c_add_adapter()
2. Addedi2c_imx->adapter.class=I2C_CLASS_HWMON;Signed-off-by Darius Augulis <[email protected]>---
As noted in previous email, this part of the patch really is for information purposes only wrt to the drivers/i2c, and should be submitted via RMK's patch queue.
Quoted 124 lines
Index:
linux-2.6.26-rc1/arch/arm/mach-imx/mx1ads.c
===================================================================arch/arm/mach-imx/mx1ads.c +21
-0@@ -109,10 +109,31 @@ static struct platform_device imx_uart2_ } }; +static struct resource imx_i2c_resources[] = { + [0 ] = { + .start =0x00217000 , + .end =0x00217010 , + .flags =IORESOURCE_MEM , + }, + [1 ] = { + .start =I2C_INT , + .end =I2C_INT , + .flags =IORESOURCE_IRQ , + }, +}; + +static struct platform_device imx_i2c_device = { + .name ="imx-i2c" , + .id =0 , + .resource = imx_i2c_resources, + .num_resources =ARRAY_SIZE (imx_i2c_resources), +}; +static struct platform_device *devices[]__initdata = { &cs89x0_device, &imx_uart1_device, &imx_uart2_device, + &imx_i2c_device, };#ifdef CONFIG_MMC_IMX Index:
linux-2.6.26-rc1/drivers/i2c/busses/i2c-imx.c
===================================================================drivers/i2c/busses/i2c-imx.c new file +83
-0@@ -0,0 +1,612 @@ +/* +* Copyright (C) 2002 Motorola GSG-China +* +* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +* USA. +* +* File Name: i2c-imx.c +* +* Author: Darius Augulis, Teltonika Inc. +* +* Desc.: Implementation of I2C Adapter/Algorithm Driver +* Driver for I2C Bus integrated in i.MXL, i.MX1 +* +* module parameters: +* - clkfreq: +* Sets the desired clock rate +* The default value is 100000 +* Max value is 400000 +* - imxslave: +* IMX slave I2C address in decimal format +* The default value is 0xAC in hex +* +* Derived from Motorola GSG China I2C example driver +* +* Copyright (C) 2002 Motorola GSG-China +* Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de +* Portions: +* Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de +* Copyright (C) 2007 RightHand Technologies, Inc. <adyer at righthandtech.com> +* Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt> +* +*/ + +/** Includes ******************************************************************* +*******************************************************************************/ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> + +#include <asm/arch/irqs.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> + +#include <asm/arch/imx-regs.h> + +/** Defines ******************************************************************** +*******************************************************************************/ + +/* This will be the driver name the kernel reports */ +#define DRIVER_NAME "imx-i2c" + +/* Default values of module parameters */ +#define IMX_I2C_SLAVE_ADDR 0xAC +#define IMX_I2C_BIT_RATE 100000/* 100kHz */ + +/* Timeouts */ +#define I2C_IMX_TIME_BUSY 2000/* loop count */ +#define I2C_IMX_TIME_ACK 2000/* loop count */ +#define I2C_IMX_TIME_TRX 5/* seconds */ + +/* Error numbers */ +#define I2C_IMX_ERR_BUSY 1 +#define I2C_IMX_ERR_TX_TIMEOUT 2
drivers/i2c/busses/i2c-imx.c line 93
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+#define I2C_IMX_ERR_RX_TIMEOUT 3 +#define I2C_IMX_ERR_RX_NO_ACK 4 + +/* Macros */ +#define print_err(f,x...) printk(KERN_ERR f, ##x) +#ifdef CONFIG_I2C_DEBUG_BUS +#define print_dbg(f,x...) printk(KERN_DEBUG f, ##x) +#else +#define print_dbg(f,x...) ((void)0) +#endif
do you really need to invent a new debugging type here? why not use dev_dbg() to do the work, and ensure that your debug output is also tagged with the device-id of the device it is being done for.
drivers/i2c/busses/i2c-imx.c line 101
Quoted 7 lines
drivers/i2c/busses/i2c-imx.c new file +7
-0+/** Function prototypes ******************************************************** +*******************************************************************************/ + +static int i2c_imx_xfer (struct i2c_adapter *adapter,struct i2c_msg *msgs,int num); +static u32 i2c_imx_func (struct i2c_adapter *adapter); +static int __init i2c_imx_probe (struct platform_device *pdev); +static int i2c_imx_remove (struct platform_device *pdev);
this is wrapping, how about not indenting. I do not belive yoy need to use __init in the forward decleration of these functions.
Quoted 54 lines
drivers/i2c/busses/i2c-imx.c new file +54
-0+ +/** Variables ****************************************************************** +*******************************************************************************/ + +static unsigned int clkfreq =IMX_I2C_BIT_RATE ; +static unsigned int imxslave =IMX_I2C_SLAVE_ADDR ; +static unsigned int disable_delay =0 ;/* Dummy delay. Default value - 0 (no delay) */ + +/* +* sorted list of clock divider, register value pairs +* taken from table 26-5, p.26-9, Freescale i.MX +* Integrated Portable System Processor Reference Manual +* Document Number: MC9328MXLRM, Rev. 5.1, 06/2007 +* +* Duplicated divider values removed from list +*/ + +static int __initdata i2c_imx_clk_divider [50 ] [2 ] = { + {22 ,0x20 },{24 ,0x21 },{26 ,0x22 },{28 ,0x23 },{30 ,0x00 }, + {32 ,0x24 },{36 ,0x25 },{40 ,0x26 },{42 ,0x03 },{44 ,0x27 }, + {48 ,0x28 },{52 ,0x05 },{56 ,0x29 },{60 ,0x06 },{64 ,0x2A }, + {72 ,0x2B },{80 ,0x2C },{88 ,0x09 },{96 ,0x2D },{104 ,0x0A }, + {112 ,0x2E },{128 ,0x2F },{144 ,0x0C },{160 ,0x30 },{192 ,0x31 }, + {224 ,0x32 },{240 ,0x0F },{256 ,0x33 },{288 ,0x10 },{320 ,0x34 }, + {384 ,0x35 },{448 ,0x36 },{480 ,0x13 },{512 ,0x37 },{576 ,0x14 }, + {640 ,0x38 },{768 ,0x39 },{896 ,0x3A },{960 ,0x17 },{1024 ,0x3B }, + {1152 ,0x18 },{1280 ,0x3C },{1536 ,0x3D },{1792 ,0x3E },{1920 ,0x1B }, + {2048 ,0x3F },{2304 ,0x1C },{2560 ,0x1D },{3072 ,0x1E },{3840 ,0x1F } +}; + +static struct platform_driver i2c_imx_driver = { + .probe = i2c_imx_probe, + .remove = i2c_imx_remove, + .driver = { + .name =DRIVER_NAME , + .owner =THIS_MODULE , + } +}; + +static struct i2c_algorithm i2c_imx_algo = { + .master_xfer = i2c_imx_xfer, + .functionality = i2c_imx_func, +}; + +struct imx_i2c_struct { +struct i2c_adapter adapter; +struct resource *res; +void __iomem *base; +int irq; +wait_queue_head_t queue; +unsigned long i2csr; +}; + +/** Functions for IMX I2C adapter driver ***************************************
drivers/i2c/busses/i2c-imx.c line 165
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+*******************************************************************************/ + +static int i2c_imx_bus_busy (struct imx_i2c_struct *i2c_imx) { + +unsigned int i =0 ; + +print_dbg ("I2C: <i2c_imx_bus_busy>\n" ); + +/* wait for bus not busy */ +for (i=0 ; i<I2C_IMX_TIME_BUSY ; i++) {
spacing in here: for (i = 0; i < I2C_IMX_TIME_BUSY; i++)
Quoted 67 lines
drivers/i2c/busses/i2c-imx.c new file +67
-0+if (!(readb (i2c_imx->base +IMX_I2C_I2SR ) & (I2SR_IBB |I2SR_IAL ))) +return 0 ; +udelay (1 ); + } +print_dbg ("I2C: <i2c_imx_bus_busy> I2C bus is busy!\n" ); +return -I2C_IMX_ERR_BUSY ; +} + +static int i2c_imx_trx_complete (struct imx_i2c_struct *i2c_imx) { + +int result; + +print_dbg ("I2C: <i2c_imx_trx_complete>\n" ); + result =wait_event_interruptible_timeout (i2c_imx->queue, + (i2c_imx->i2csr &I2SR_IIF ),I2C_IMX_TIME_TRX *HZ ); + +if (unlikely (result <0 )) { +print_dbg ("I2C: <i2c_imx_trx_complete> result < 0!\n" ); +return result; + } +else if (unlikely (!(i2c_imx->i2csr &I2SR_IIF ))) { +print_dbg ("I2C: <i2c_imx_trx_complete> Timeout!\n" ); +return -I2C_IMX_ERR_TX_TIMEOUT ; + } +print_dbg ("I2C: <i2c_imx_trx_complete> TRX complete!\n" ); + i2c_imx->i2csr =0 ; +return 0 ; +} + +static int i2c_imx_acked (struct imx_i2c_struct *i2c_imx) { + +unsigned int i =0 ; + +print_dbg ("I2C: <i2c_imx_acked>\n" ); +for (i=0 ; i<I2C_IMX_TIME_ACK ; i++) { +if (!(readb (i2c_imx->base +IMX_I2C_I2SR ) &I2SR_RXAK )) { +print_dbg ("I2C: <i2c_imx_acked> ACK received\n" ); +return 0 ; + } +udelay (1 ); + } +print_dbg ("I2C: <i2c_imx_acked> No ACK!\n" ); +return -I2C_IMX_ERR_RX_NO_ACK ;/* No ACK */ +} + +static void i2c_imx_enable (struct imx_i2c_struct *i2c_imx) { +print_dbg ("I2C: <i2c_imx_enable>\n" ); +writeb (I2CR_IEN , i2c_imx->base +IMX_I2C_I2CR ); +} + +static void i2c_imx_disable (struct imx_i2c_struct *i2c_imx) { + +print_dbg ("I2C: <i2c_imx_disable>\n" ); + +/* setup chip registers to defaults */ +writeb (I2CR_IEN , i2c_imx->base +IMX_I2C_I2CR ); +writeb (0 , i2c_imx->base +IMX_I2C_I2SR ); +/* This delay caused by i.MXL hardware bug. If no (or to short) delay, no "STOP" bit will be generated */ +udelay (disable_delay); +writeb (0 , i2c_imx->base +IMX_I2C_I2CR ); +} + +static void i2c_imx_start (struct imx_i2c_struct *i2c_imx) { + +unsigned int temp =0 ; + +print_dbg ("I2C: <i2c_imx_start>\n" );
drivers/i2c/busses/i2c-imx.c line 242
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+ temp =readb ( i2c_imx->base +IMX_I2C_I2CR ); + temp |=I2CR_MSTA ; +writeb (temp, i2c_imx->base +IMX_I2C_I2CR ); + temp |= (I2CR_IIEN |I2CR_MTX |I2CR_TXAK ); +writeb (temp, i2c_imx->base +IMX_I2C_I2CR ); + + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); +print_dbg ("I2C: <i2c_imx_start> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n" , + (temp&I2CR_IEN ?1 :0 ),(temp&I2CR_IIEN ?1 :0 ),(temp&I2CR_MSTA ?1 :0 ),(temp&I2CR_MTX ?1 :0 ), + (temp&I2CR_TXAK ?1 :0 ),(temp&I2CR_RSTA ?1 :0 ));
spacing in here, (temp & I2CR_IEN) ? 1 : 0
drivers/i2c/busses/i2c-imx.c line 247
Quoted 5 lines
drivers/i2c/busses/i2c-imx.c new file +5
-0+ temp =readb (i2c_imx->base +IMX_I2C_I2SR ); +print_dbg ("I2C: <i2c_imx_start> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n" , + (temp&I2SR_ICF ?1 :0 ),(temp&I2SR_IAAS ?1 :0 ),(temp&I2SR_IBB ?1 :0 ),(temp&I2SR_IAL ?1 :0 ), + (temp&I2SR_SRW ?1 :0 ),(temp&I2SR_IIF ?1 :0 ),(temp&I2SR_RXAK ?1 :0 )); +}
given the amount of times these get used, an inline function would have made it easier to write this.
Quoted 18 lines
drivers/i2c/busses/i2c-imx.c new file +18
-0+static void i2c_imx_stop (struct imx_i2c_struct *i2c_imx) { + +unsigned int temp =0 ; + +print_dbg ("I2C: <i2c_imx_stop>\n" ); + temp =readb ( i2c_imx->base +IMX_I2C_I2CR ); + temp &= ~I2CR_MSTA ; +writeb (temp, i2c_imx->base +IMX_I2C_I2CR ); + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); +print_dbg ("I2C: <i2c_imx_stop> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n" , + (temp&I2CR_IEN ?1 :0 ),(temp&I2CR_IIEN ?1 :0 ),(temp&I2CR_MSTA ?1 :0 ),(temp&I2CR_MTX ?1 :0 ), + (temp&I2CR_TXAK ?1 :0 ),(temp&I2CR_RSTA ?1 :0 )); + temp =readb (i2c_imx->base +IMX_I2C_I2SR ); +print_dbg ("I2C: <i2c_imx_stop> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n" , + (temp&I2SR_ICF ?1 :0 ),(temp&I2SR_IAAS ?1 :0 ),(temp&I2SR_IBB ?1 :0 ),(temp&I2SR_IAL ?1 :0 ), + (temp&I2SR_SRW ?1 :0 ),(temp&I2SR_IIF ?1 :0 ),(temp&I2SR_RXAK ?1 :0 )); +} +
drivers/i2c/busses/i2c-imx.c line 276
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+static int __init i2c_imx_set_clk (struct imx_i2c_struct *i2c_imx,unsigned int rate) { + +unsigned int hclk, sysclk; +unsigned int desired_div; +int i; + +print_dbg ("I2C: <i2c_imx_set_clk>\n" ); + sysclk =imx_get_system_clk (); + hclk =imx_get_hclk (); + desired_div = hclk / rate;
really, is there not a decent clk_xxx() API support to get the system and HCLK values?
drivers/i2c/busses/i2c-imx.c line 283
Quoted 7 lines
drivers/i2c/busses/i2c-imx.c new file +7
-0+if (desired_div &0x01 ) + desired_div++; +if (desired_div <22 ) + desired_div =22 ; +if (desired_div >3840 ) + desired_div =3840 ; +for (i=0 ; i<50 ; i++) {
ARRAY_SIZE() is applicable here.
Quoted 82 lines
drivers/i2c/busses/i2c-imx.c new file +82
-0+if (i2c_imx_clk_divider[i][0 ] >= desired_div) +break ; + } + +/* +* There dummy delay is calculated. It should be about one I2C clock period long +* This delay is used in I2C bus disable function to fix chip hardware bug. +*/ + + disable_delay = (1000000 / (hclk / i2c_imx_clk_divider[i][0 ])) +1 ; + +print_dbg ("I2C: <i2c_imx_set_clk> SYSCLK=%d, HCLK=%d, REQ DIV=%d\n" , sysclk, hclk, desired_div); +print_dbg ("I2C: <i2c_imx_set_clk> IFDR[IC]=0x%x, REAL DIV=%d\n" , i2c_imx_clk_divider[i][1 ], i2c_imx_clk_divider[i][0 ]); +writeb (i2c_imx_clk_divider[i][1 ], i2c_imx->base +IMX_I2C_IFDR ); +return 0 ; +} + +static irqreturn_t i2c_imx_isr (int irq,void *dev_id) { + +struct imx_i2c_struct *i2c_imx = dev_id; +unsigned int temp; + +print_dbg ("I2C: <i2c_imx_isr>\n" ); + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); +print_dbg ("I2C: <i2c_imx_isr> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n" , + (temp&I2CR_IEN ?1 :0 ),(temp&I2CR_IIEN ?1 :0 ),(temp&I2CR_MSTA ?1 :0 ),(temp&I2CR_MTX ?1 :0 ), + (temp&I2CR_TXAK ?1 :0 ),(temp&I2CR_RSTA ?1 :0 )); + temp =readb (i2c_imx->base +IMX_I2C_I2SR ); +print_dbg ("I2C: <i2c_imx_isr> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n" , + (temp&I2SR_ICF ?1 :0 ),(temp&I2SR_IAAS ?1 :0 ),(temp&I2SR_IBB ?1 :0 ),(temp&I2SR_IAL ?1 :0 ), + (temp&I2SR_SRW ?1 :0 ),(temp&I2SR_IIF ?1 :0 ),(temp&I2SR_RXAK ?1 :0 )); + + temp =readb (i2c_imx->base +IMX_I2C_I2SR ); +if (temp &I2SR_IIF ) { +/* save status register */ + i2c_imx->i2csr = temp; + temp &= ~I2SR_IIF ; +writeb (temp, i2c_imx->base +IMX_I2C_I2SR ); +wake_up_interruptible (&i2c_imx->queue); + } +return IRQ_HANDLED ; +} + +static int i2c_imx_write (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs) { + +int i; + +print_dbg ("I2C: <i2c_imx_write>\n" ); +print_dbg ("I2C: <i2c_imx_write> write slave address: addr=0x%x\n" , (msgs->addr<<1 )); + +/* write slave address */ +writeb ((msgs->addr<<1 ), i2c_imx->base +IMX_I2C_I2DR ); +if (i2c_imx_trx_complete (i2c_imx)) +return -I2C_IMX_ERR_TX_TIMEOUT ; +if (i2c_imx_acked (i2c_imx)) +return -I2C_IMX_ERR_RX_NO_ACK ; +print_dbg ("I2C: <i2c_imx_write> write data\n" ); + +/* write data */ +for (i =0 ; i<msgs->len; i++) { +print_dbg ("I2C: <i2c_imx_write> write byte: %d, b=0x%x\n" , i, msgs->buf[i]); +writeb (msgs->buf[i], i2c_imx->base +IMX_I2C_I2DR ); +if (i2c_imx_trx_complete (i2c_imx)) +return -I2C_IMX_ERR_TX_TIMEOUT ; +if (i2c_imx_acked (i2c_imx)) +return -I2C_IMX_ERR_RX_NO_ACK ; + } +return 0 ; +} + +static int i2c_imx_read (struct imx_i2c_struct *i2c_imx,struct i2c_msg *msgs) { + +int i; +unsigned int temp; + +print_dbg ("I2C: <i2c_imx_read>\n" ); +print_dbg ("I2C: <i2c_imx_read> write slave address: addr=0x%x\n" , (msgs->addr<<1 )); + +/* write slave address */ +writeb ((msgs->addr<<1 )|0x01 , i2c_imx->base +IMX_I2C_I2DR ); +if (i2c_imx_trx_complete (i2c_imx)) +return -I2C_IMX_ERR_TX_TIMEOUT ;
drivers/i2c/busses/i2c-imx.c line 375
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+if (i2c_imx_acked (i2c_imx)) +return -I2C_IMX_ERR_RX_NO_ACK ; + +print_dbg ("I2C: <i2c_imx_read> setup bus\n" ); + +/* setup bus to read data */ + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); + temp &= ~I2CR_MTX ; +if (msgs->len-1 ) + temp &= ~I2CR_TXAK ;
indentation here.. completely unreadable.
Quoted 9 lines
drivers/i2c/busses/i2c-imx.c new file +9
-0+writeb (temp, i2c_imx->base +IMX_I2C_I2CR ); + +print_dbg ("I2C: <i2c_imx_read> dummy read\n" ); +readb (i2c_imx->base +IMX_I2C_I2DR );/* dummy read */ + +print_dbg ("I2C: <i2c_imx_read> read data\n" ); + +/* read data */ +for (i=0 ; i < msgs->len; i++) {
drivers/i2c/busses/i2c-imx.c line 394
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+ +if (i2c_imx_trx_complete (i2c_imx)) +return -I2C_IMX_ERR_RX_TIMEOUT ; + +if (i==(msgs->len-1 )) { +print_dbg ("I2C: <i2c_imx_read> clear MSTA\n" ); + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); + temp &= ~I2CR_MSTA ; +writeb (temp, i2c_imx->base +IMX_I2C_I2CR ); + }
no line break needed
Quoted 44 lines
drivers/i2c/busses/i2c-imx.c new file +44
-0+else if (i==(msgs->len-2 )) { +print_dbg ("I2C: <i2c_imx_read> set TXAK\n" ); + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); + temp |=I2CR_TXAK ; +writeb (temp, i2c_imx->base +IMX_I2C_I2CR ); + } +print_dbg ("I2C: <i2c_imx_read> read byte B%d\n" , i); + msgs->buf[i] =readb (i2c_imx->base +IMX_I2C_I2DR ); + } +return 0 ; +} + +static int i2c_imx_xfer (struct i2c_adapter *adapter,struct i2c_msg *msgs,int num) { + +int i, temp; +int err =0 ; +struct imx_i2c_struct *i2c_imx =i2c_get_adapdata (adapter); + +print_dbg ("I2C: <i2c_imx_xfer>\n" ); + +/* Check or i2c bus is not busy */ + err =i2c_imx_bus_busy (i2c_imx); +if (err) + goto fail0; + +/* Enable i2c */ +i2c_imx_enable (i2c_imx); + +/* Start I2C transfer */ +i2c_imx_start (i2c_imx); + + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); +print_dbg ("I2C: <i2c_imx_xfer> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n" , + (temp&I2CR_IEN ?1 :0 ),(temp&I2CR_IIEN ?1 :0 ),(temp&I2CR_MSTA ?1 :0 ),(temp&I2CR_MTX ?1 :0 ), + (temp&I2CR_TXAK ?1 :0 ),(temp&I2CR_RSTA ?1 :0 )); + temp =readb (i2c_imx->base +IMX_I2C_I2SR ); +print_dbg ("I2C: <i2c_imx_xfer> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n" , + (temp&I2SR_ICF ?1 :0 ),(temp&I2SR_IAAS ?1 :0 ),(temp&I2SR_IBB ?1 :0 ),(temp&I2SR_IAL ?1 :0 ), + (temp&I2SR_SRW ?1 :0 ),(temp&I2SR_IIF ?1 :0 ),(temp&I2SR_RXAK ?1 :0 )); + +/* read/write data */ +for (i=0 ; i<num; i++) { +if (i) { +print_dbg ("I2C: <i2c_imx_read> repeated start\n" );
drivers/i2c/busses/i2c-imx.c line 448
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+ temp =readb (i2c_imx->base +IMX_I2C_I2CR ); + temp |=I2CR_RSTA ; +writeb (temp, i2c_imx->base +IMX_I2C_I2CR ); + } +print_dbg ("I2C: <i2c_imx_xfer> transfer message: %d\n" , i); +/* write/read data */ +if (!(msgs[i].flags &I2C_M_RD )) + err =i2c_imx_write (i2c_imx, &msgs[i]); +else + err =i2c_imx_read (i2c_imx, &msgs[i]);
keeping a pointer to the current message would have been more efficient here, ie:
ptr = msgs;
for (i = 0; i < num; i++, ptr++) {
....
}Quoted 20 lines
drivers/i2c/busses/i2c-imx.c new file +20
-0+ } + +fail0: +/* Stop bus */ +i2c_imx_stop (i2c_imx); +/* disable i2c bus */ +i2c_imx_disable (i2c_imx); +print_dbg ("I2C: <i2c_imx_xfer> exit with: %s: %d\n" , (err <0 )?"error" :"success msg" , (err <0 )?err:num); +return (err <0 ) ? err : num; +} + +static u32 i2c_imx_func (struct i2c_adapter *adapter) { +return (I2C_FUNC_I2C |I2C_FUNC_SMBUS_EMUL ); +} + +static int __init i2c_imx_probe (struct platform_device *pdev) { + +struct imx_i2c_struct *i2c_imx; +struct resource *res; +void __iomem *base;
drivers/i2c/busses/i2c-imx.c line 478
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+int irq; +int res_size; +int ret; + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); + irq =platform_get_irq (pdev,0 ); +if (!res) { +print_err ("I2C: can't get device resources!\n" ); +return -ENODEV ; + }
use dev_err() here, and some line spacing wouldn't go amiss either.
drivers/i2c/busses/i2c-imx.c line 483
Quoted 6 lines
drivers/i2c/busses/i2c-imx.c new file +5
-0+if (irq <0 ) { +print_err ("I2C: can't get irq number!\n" ); +return -ENODEV ; + } + res_size = (res->end) - (res->start) +1 ;
are the brackets necessary?
Quoted 119 lines
drivers/i2c/busses/i2c-imx.c new file +119
-0+if (!request_mem_region (res->start, res_size, res->name)) { +print_err ("I2C: can't allocate %d bytes at %d address!\n" , res_size, res->start); +return -ENOMEM ; + } + base =ioremap (res->start, res_size); +if (!base) { +print_err ("I2C: ioremap failed!\n" ); + ret = -EIO ; + goto fail0; + } + i2c_imx =kzalloc (sizeof (struct imx_i2c_struct ),GFP_KERNEL ); +if (!i2c_imx) { +print_err ("I2C: can't allocate interface!\n" ); + ret = -ENOMEM ; + goto fail1; + } + +/* Setup i2c_imx driver structure */ +strcpy (i2c_imx->adapter.name, pdev->name); + i2c_imx->adapter.owner =THIS_MODULE ; + i2c_imx->adapter.algo = &i2c_imx_algo; + i2c_imx->adapter.dev.parent = &pdev->dev; + i2c_imx->adapter.class =I2C_CLASS_HWMON ; + i2c_imx->adapter.nr = pdev->id; + i2c_imx->irq = irq; + i2c_imx->base = base; + i2c_imx->res = res; + +init_waitqueue_head (&i2c_imx->queue); + +/* Set up platform driver data */ +platform_set_drvdata (pdev, i2c_imx); + + ret =request_irq (i2c_imx->irq, i2c_imx_isr,IRQF_DISABLED , pdev->name, i2c_imx); +if (ret) { +print_err ("I2C: %s: cannot claim irq %d !\n" , i2c_imx->adapter.dev.bus_id, i2c_imx->irq); + goto fail2; + } + +/* Set up clock divider */ +i2c_imx_set_clk (i2c_imx, clkfreq); + +/* Set up IMX I2C slave address */ +writeb (imxslave, i2c_imx->base +IMX_I2C_IADR ); + +/* Set up I/O pins for I2C*/ +imx_gpio_mode (PA15_PF_I2C_SDA ); +imx_gpio_mode (PA16_PF_I2C_SCL ); + +/* Set up chip registers to defaults */ +writeb (0 , i2c_imx->base +IMX_I2C_I2CR ); +writeb (0 , i2c_imx->base +IMX_I2C_I2SR ); + +/* Set up adapter data */ +i2c_set_adapdata (&i2c_imx->adapter, i2c_imx); + +/* Add I2C adapter */ + ret =i2c_add_numbered_adapter (&i2c_imx->adapter); +if (ret <0 ) { +print_err ("I2C: %s: registration failed\n" , i2c_imx->adapter.dev.bus_id); + goto fail3; + } + +print_dbg ("I2C: %s: claimed irq %d\n" , i2c_imx->adapter.dev.bus_id, i2c_imx->irq); +print_dbg ("I2C: %s: device resources from 0x%x to 0x%x\n" , i2c_imx->adapter.dev.bus_id, i2c_imx->res->start, i2c_imx->res->end); +print_dbg ("I2C: %s: allocated %d bytes at 0x%x \n" , i2c_imx->adapter.dev.bus_id, res_size, i2c_imx->res->start); +print_dbg ("I2C: %s: adapter name: \"%s\"\n" , i2c_imx->adapter.dev.bus_id, i2c_imx->adapter.name); +print_dbg ("I2C: adapter \"%s\" associated with driver \"%s\"\n" , i2c_imx->adapter.dev.bus_id, i2c_imx_driver.driver.name); +print_dbg ("I2C: %s: IMX I2C adapter registered\n" , i2c_imx->adapter.dev.bus_id); +return 0 ;/* Return OK */ + +fail3: +free_irq (i2c_imx->irq, i2c_imx); +fail2: +platform_set_drvdata (pdev,NULL ); +kfree (i2c_imx); +fail1: +iounmap (i2c_imx->base); +fail0: +release_mem_region (res->start, res_size); +return ret;/* Return error number */ +} + +static int i2c_imx_remove (struct platform_device *pdev) { + +struct imx_i2c_struct *i2c_imx =platform_get_drvdata (pdev); + +/* remove adapter */ +print_dbg ("I2C: adapter removed\n" ); +i2c_del_adapter (&i2c_imx->adapter); +platform_set_drvdata (pdev,NULL ); + +/* free interrupt */ +free_irq (i2c_imx->irq, i2c_imx); + +/* setup chip registers to defaults */ +writeb (0 , i2c_imx->base +IMX_I2C_IADR ); +writeb (0 , i2c_imx->base +IMX_I2C_IFDR ); +writeb (0 , i2c_imx->base +IMX_I2C_I2CR ); +writeb (0 , i2c_imx->base +IMX_I2C_I2SR ); + +/* release memory */ +release_mem_region (i2c_imx->res->start, (i2c_imx->res->end - i2c_imx->res->start) +1 ); +iounmap (i2c_imx->base); +kfree (i2c_imx); +return 0 ; +} + +static int __init i2c_adap_imx_init (void ) { +return platform_driver_register (&i2c_imx_driver); +} + +static void __exit i2c_adap_imx_exit (void) { +platform_driver_unregister (&i2c_imx_driver); +return ; +} + +module_init (i2c_adap_imx_init); +module_exit (i2c_adap_imx_exit);
drivers/i2c/busses/i2c-imx.c line 612
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c new file +10
-0+ +MODULE_AUTHOR ("Darius Augulis" ); +MODULE_DESCRIPTION ("I2C adapter driver for IMX I2C bus" ); +MODULE_LICENSE ("GPL" ); + +module_param (clkfreq, uint,S_IRUGO ); +MODULE_PARM_DESC (clkfreq,"desired IMX I2C Clock Rate in Hz" ); + +module_param (imxslave, uint,S_IRUGO ); +MODULE_PARM_DESC (imxslave,"desired IMX I2C slave address" );
you've miseed the MODULE_ALIAS() for the platform device.
Quoted 57 lines
Index: linux-2.6.26-rc1/drivers/i2c/busses/Kconfig
===================================================================drivers/i2c/busses/Kconfig +10
-0@@ -257,6 +257,16 @@ config I2C_IBM_IIC This driver can also be built as a module. If so, the module will be called i2c-ibm_iic. +config I2C_IMX + tristate "IMX I2C interface" + depends on ARCH_IMX + help + Say Y here if you want to use the IIC bus controller on + the Freescale i.MXL and i.MX1 processors. + + This driver can also be built as a module. If so, the module + will be called i2c-imx. + config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XXIndex: linux-2.6.26-rc1/drivers/i2c/busses/Makefile
===================================================================drivers/i2c/busses/Makefile +1
-0@@ -18,6 +18,7 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_I810) += i2c-i810.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o +obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.oIndex:
linux-2.6.26-rc1/include/asm-arm/arch-imx/imx-regs.h
===================================================================include/asm-arm/arch-imx/imx-regs.h +16
-0@@ -479,4 +479,29 @@#define LCDISR_EOF (1<<1)#define LCDISR_BOF (1<<0) +/* +* I2C +*/ + +#define IMX_I2C_IADR 0x00/* i2c slave address */ +#define IMX_I2C_IFDR 0x04/* i2c frequency divider */ +#define IMX_I2C_I2CR 0x08/* i2c control */ +#define IMX_I2C_I2SR 0x0C/* i2c status */ +#define IMX_I2C_I2DR 0x10/* i2c transfer data */ + +#define I2SR_RXAK 0x01 +#define I2SR_IIF 0x02 +#define I2SR_SRW 0x04 +#define I2SR_IAL 0x10 +#define I2SR_IBB 0x20 +#define I2SR_IAAS 0x40
include/asm-arm/arch-imx/imx-regs.h line 507
Quoted 10 lines
include/asm-arm/arch-imx/imx-regs.h +9
-0+#define I2SR_ICF 0x80 + +#define I2CR_RSTA 0x04 +#define I2CR_TXAK 0x08 +#define I2CR_MTX 0x10 +#define I2CR_MSTA 0x20 +#define I2CR_IIEN 0x40 +#define I2CR_IEN 0x80 +#endif // _IMX_REGS_H
yeurk, put these in a seperate header file, or place them near the driver. The "One Big Register File" is horrible, and hopefully is going the same way as the Dodo.
Signature · 8 lines
Ben ([email protected], http://www.fluff.org/) 'a smiley only costs 4 bytes' _______________________________________________ i2c mailing list [email protected] http://lists.lm-sensors.org/mailman/listinfo/i2c
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 4 lines
do you really need to invent a new debugging type here? why not use
dev_dbg()to do the work, and ensure that your debug output is also tagged with the device-id of the device it is being done for.
ok, there was some problems using dev_dbg(), but I'll change it.
Quoted 2 lines
this is wrapping, how about not indenting. I do not belive yoy need to use
__initin the forward decleration of these functions.
ok, changed.
Quoted 4 lines
drivers/i2c/busses/i2c-imx.c line 165
Quoted 1 line
drivers/i2c/busses/i2c-imx.c new file +1
-0+for (i=0 ; i<I2C_IMX_TIME_BUSY ; i++) {spacing in here: for (i = 0; i <
I2C_IMX_TIME_BUSY; i++)
what is there wrong with spacing?
Quoted 1 line
spacing in here, (temp &
I2CR_IEN) ? 1 : 0
I really should add dummy spaces...?
Quoted 3 lines
given the amount of times these get used, an inline function would have made it easier to write this.
yes, now I removed it form most places, because it was not very useful debug info. Only in ISR is leaved.
Quoted 9 lines
drivers/i2c/busses/i2c-imx.c line 276
Quoted 5 lines
drivers/i2c/busses/i2c-imx.c new file +5
-0+ +print_dbg ("I2C: <i2c_imx_set_clk>\n" ); + sysclk =imx_get_system_clk (); + hclk =imx_get_hclk (); + desired_div = hclk / rate;really, is there not a decent
clk_xxx()API support to get the system and HCLK values?
there are two API functions to get SYSCLK and HCLK: imx_get_system_clk (); and imx_get_hclk();
And they are used there. Where is a problem?
Quoted 10 lines
drivers/i2c/busses/i2c-imx.c line 283
Quoted 7 lines
drivers/i2c/busses/i2c-imx.c new file +7
-0+if (desired_div &0x01 ) + desired_div++; +if (desired_div <22 ) + desired_div =22 ; +if (desired_div >3840 ) + desired_div =3840 ; +for (i=0 ; i<50 ; i++) {
ARRAY_SIZE()is applicable here.
ok, changed.
Quoted 8 lines
drivers/i2c/busses/i2c-imx.c line 375
Quoted 6 lines
drivers/i2c/busses/i2c-imx.c new file +6
-0+ +/* setup bus to read data */ + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); + temp &= ~I2CR_MTX ; +if (msgs->len-1 ) + temp &= ~I2CR_TXAK ;indentation here.. completely unreadable.
strange, because only one 'tab' symbol used. For me and others all seems
ok.
Quoted 8 lines
drivers/i2c/busses/i2c-imx.c line 394
Quoted 6 lines
drivers/i2c/busses/i2c-imx.c new file +6
-0+if (i==(msgs->len-1 )) { +print_dbg ("I2C: <i2c_imx_read> clear MSTA\n" ); + temp =readb (i2c_imx->base +IMX_I2C_I2CR ); + temp &= ~I2CR_MSTA ; +writeb (temp, i2c_imx->base +IMX_I2C_I2CR ); + }no line break needed
where do you see line break?
Quoted 7 lines
keeping a pointer to the current message would have been more efficient here, ie:
ptr = msgs; for (i = 0; i < num; i++, ptr++) { .... }
what is meaning of this pointer? there I need only count messages, nothing else...
Quoted 2 lines
use
dev_err()here, and some line spacing wouldn't go amiss either.
ok. I'll change all debug prints.
Quoted 3 lines
drivers/i2c/busses/i2c-imx.c line 483
Quoted 1 line
drivers/i2c/busses/i2c-imx.c new file +1
-0+ res_size = (res->end) - (res->start) +1 ;are the brackets necessary?
maybe it is strange, but, for example, if I remove brakets from there (first parameter):writeb(((msgs->addr<<1)|0x01), i2c_imx->base + IMX_I2C_I2DR); address is sent without LSB bit cleared. Therefore I've added brakets. I think it does not make damage:)
Quoted 2 lines
you've miseed the
MODULE_ALIAS()for the platform device.
ok, added.
Quoted 5 lines
yeurk, put these in a seperate header file, or place them near the driver. The "One Big Register File" is horrible, and hopefully is going the same way as the Dodo.
please, read this:
news://news.gmane.org:119/c166aa9f0803140300n75f6790enee3f28bdebeba945-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org (03/14/2008 12:00 PM post from Andrew Dyer)
seems, everybody has her own opinion. Is there somebody one, who can say how that should be? Because I have already two times changed that... I'm only beginner, so ambiguous comments are very unwanted... As I know, Jean Delvare is responsible for I2C drivers. So, his word is welcome:)
_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c
Quoted 6 lines · Darius
Quoted 2 lines
drivers/i2c/busses/i2c-imx.c line 165
Quoted 1 line
drivers/i2c/busses/i2c-imx.c new file +1
-0+for (i=0 ; i<I2C_IMX_TIME_BUSY ; i++) {spacing in here: for (i = 0; i <
I2C_IMX_TIME_BUSY; i++)what is there wrong with spacing?
Quoted 1 line
spacing in here, (temp &
I2CR_IEN) ? 1 : 0I really should add dummy spaces...?
Please do. Documentation/CodingStyle recommends it. While personal opinions on ceratin topics may vary, I think it is indeed helpful, if all kernel sources look somewhat similar.
Quoted 6 lines
Quoted 2 lines
yeurk, put these in a seperate header file, or place them near the driver. The "One Big Register File" is horrible, and hopefully
seems, everybody has her own opinion. Is there somebody one, who can say how that should be? Because I have already two times changed that... I'm only beginner, so ambiguous comments are very unwanted... As I know, Jean Delvare is responsible for I2C drivers. So, his word is welcome:)
He suggested the same (= no register file) to me in January for the PCA9564-driver.
All the best,
Wolfram
Signature · 2 lines
Dipl.-Ing. Wolfram Sang | http://www.pengutronix.de Pengutronix - Linux Solutions for Science and Industry
_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c
Quoted 4 lines · Darius
seems, everybody has her own opinion. Is there somebody one, who can say how that should be? Because I have already two times changed that... I'm only beginner, so ambiguous comments are very unwanted... As I know, Jean Delvare is responsible for I2C drivers. So, his word is welcome:)
Actually Ben is responsible for the embedded i2c drivers now. It would be written in MAINTAINERS already if said Ben had acked the patch adding his name there [1], but I am still waiting for that ack. Ben, please?
[1] http://lists.lm-sensors.org/pipermail/i2c/2008-March/003199.html
Signature · 6 lines
Jean Delvare _______________________________________________ i2c mailing list [email protected] http://lists.lm-sensors.org/mailman/listinfo/i2c
PATCH v5 1/1 I2C bus driver for IMX
In reply to a message not in the archiveAll Ben comments accepted, coding style fixed, checked with checkpatch.pl. Only 5 warnings about line over 80 characters.
Tested on MXLADS V2.0 board with 2.6.26-rc1 kernel.
---
arch/arm/mach-imx/mx1ads.c +21 -0
@@ -109,10 +109,31 @@ static struct platform_device imx_uart2_ } }; +static struct resource imx_i2c_resources[] = { + [0 ] = { + .start =0x00217000 , + .end =0x00217010 , + .flags =IORESOURCE_MEM , + }, + [1 ] = { + .start =I2C_INT , + .end =I2C_INT , + .flags =IORESOURCE_IRQ , + }, +}; + +static struct platform_device imx_i2c_device = { + .name ="imx-i2c" , + .id =0 , + .resource = imx_i2c_resources, + .num_resources =ARRAY_SIZE (imx_i2c_resources), +}; +static struct platform_device *devices[]__initdata = { &cs89x0_device, &imx_uart1_device, &imx_uart2_device, + &imx_i2c_device, };#ifdef CONFIG_MMC_IMX
drivers/i2c/busses/i2c-imx.c new file +652 -0
652 lines not on this page · raw message
drivers/i2c/busses/Kconfig +10 -0
@@ -257,6 +257,16 @@ config I2C_IBM_IIC This driver can also be built as a module. If so, the module will be called i2c-ibm_iic. +config I2C_IMX + tristate "IMX I2C interface" + depends on ARCH_IMX + help + Say Y here if you want to use the IIC bus controller on + the Freescale i.MXL and i.MX1 processors. + + This driver can also be built as a module. If so, the module + will be called i2c-imx. + config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
drivers/i2c/busses/Makefile +1 -0
@@ -18,6 +18,7 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_I810) += i2c-i810.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o +obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c
Quoted 4 lines · Darius
All Ben comments accepted, coding style fixed, checked with checkpatch.pl. Only 5 warnings about line over 80 characters.
Tested on MXLADS V2.0 board with 2.6.26-rc1 kernel.
+static int __initdata i2c_imx_clk_divider [50] [2] = {
This should be unsigned. Maybe u16 to save space?
+ dev_dbg(&i2c_imx->adapter.dev, "<i2c_imx_bus_busy>\n");
You could write dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
The same with all the other places you have the function name. Makes it easier if you rename a function or move code around. Also lets you do some sort of macro:
#define dprintk(dev, fmt, args...) dev_dbg(dev, "<%s> " fmt, __func__, ## args)
or
#define dprintk(fmt, args...) dev_dbg(&i2c_imx->adapter.dev, "<%s> " fmt, __func__, ## args)
A lot people won't like the hidden variable use of the latter, though there is a lot of code that does this for debug printing.
+ * This delay caused by [an] i.MXL hardware bug.
+ * If no (or to short) delay, no "STOP" bit will be generated.
"too short"
+static int __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, unsigned int rate) +{
+
+ unsigned int hclk, sysclk;
if CONFIG_I2C_DEBUG_BUS isn't defined, then sysclk won't be used in this function. Better to stick the imx_get_system_clk() call inside the ifdef'ed code.
+ unsigned int desired_div;
+ int i;
+
+ sysclk = imx_get_system_clk();
+ hclk = imx_get_hclk();
+ desired_div = hclk / rate;
You probably want to round up, instead of down, in this calculation. Like this:
desired_div = (hclk + rate - 1) / rate;
Rounding downs means you'll get a higher clock than requested, which is usually worse than a lower clock.
+ if (desired_div & 0x01)
+ desired_div++;
Why is this code necessary? I see that all the supported dividers are even, but it makes no difference to your code that finds the actual divider if desired_div is even or odd.
+ if (desired_div < 22)
+ desired_div = 22;
+ if (desired_div > 3840)
+ desired_div = 3840;
+ for (i = 0; i < ARRAY_SIZE(i2c_imx_clk_divider); i++) {
+ if (i2c_imx_clk_divider[i][0] >= desired_div)
+ break;
+ }
Since you know the lowest and highest dividers are at the ends of the table, you can avoid duplicating them.
if (desired_div >
i2c_imx_clk_divider[ARRAY_SIZE(i2c_imx_clk_divider)-1][0]) {
i = ARRAY_SIZE(i2c_imx_clk_divider) - 1;
...print warning that clock will be too fast...
} else if (desired_div < i2c_imx_clk_divider[0][0]) {
/* print warning that clock will be too slow? */
i = 0;
} else
for (i = 0; i2c_imx_clk_divider[i][0] < desired_div; i++) ;+
+ /*
+ * There dummy delay is calculated.
+ * It should be about one I2C clock period long.
+ * This delay is used in I2C bus disable function
+ * to fix chip hardware bug.
+ */
+
+ disable_delay = (1000000 / (hclk / i2c_imx_clk_divider[i][0])) + 1;
This is a more accurate way to calculate one clock period in us.
disable_delay = (500000U * i2c_imx_clk_divider[i][0] + hclk/2 - 1) / (hclk/2);
+static irqreturn_t i2c_imx_isr(int irq, void *dev_id) +{
+ struct imx_i2c_struct *i2c_imx = dev_id;
+ unsigned int temp;
+
+ temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<i2c_imx_isr> CONTROL: IEN=%d, IIEN=%d, "
+ "MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n",
+ (temp&I2CR_IEN ? 1 : 0), (temp&I2CR_IIEN ? 1 : 0),
+ (temp&I2CR_MSTA ? 1 : 0), (temp&I2CR_MTX ? 1 : 0),
+ (temp&I2CR_TXAK ? 1 : 0), (temp&I2CR_RSTA ? 1 : 0));
+ temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<i2c_imx_isr> STATUS: ICF=%d, IAAS=%d, IBB=%d, "
+ "IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n",
+ (temp&I2SR_ICF ? 1 : 0), (temp&I2SR_IAAS ? 1 : 0),
+ (temp&I2SR_IBB ? 1 : 0), (temp&I2SR_IAL ? 1 : 0),
+ (temp&I2SR_SRW ? 1 : 0), (temp&I2SR_IIF ? 1 : 0),
+ (temp&I2SR_RXAK ? 1 : 0));
If one doesn't have DEBUG defined, then don't the two above readb()s end up being pointless? Or is it necessary to read them even if the result is never used?
_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c
A message that is not in the archive (sent off-list or not yet received): Pine.LNX.4.58.0805161003320.23876-13q4cmjDBaTP3RPoUHIrnuTW4wlIGRCZ@public.gmane.org
Quoted 5 lines
Also lets you do some
sort of macro:
#definedprintk(dev, fmt, args...)dev_dbg(dev, "<%s> " fmt, __func__, ## args)
or
#definedprintk(fmt, args...)dev_dbg(&i2c_imx->adapter.dev, "<%s> " fmt, __func__, ## args)
Thank you (and all others) for all comments and for help writing this driver. Regarding such macros, I think it is pointless. Because there is opinion, that all kernel drivers should look similar, and dev_dbg() is used in most drivers.
It is macro itself, therefore I think in the future would be easier to read and debug this driver with standard debug macro.
BR,
Darius
_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c