i2c: SuperH Mobile I2C Bus Controller V3
Subsystems (3)
PATCH 1/1 i2c: SuperH Mobile I2C Bus Controller V3
This is V3 of the SuperH Mobile I2C Controller Driver. A simple Master only driver for the I2C block included in processors such as sh7343, sh7722 and sh7723. Tested on a sh7722 MigoR using a rs5c372b rtc.
Changes since V2:
- dev_xxx() use
- Kill off superfluous ioarea resource
- Add SMBus emulation
Changes since V1:
- Use clk_get()/clk_put()/clk_get_rate() to get peripheral clock rate.
- Use pdev->dev.bus_id instead of dev->name
Verified with the rtc-rs5c372 SMBus conversion patches currently in -mm.
---
drivers/i2c/busses/Kconfig | 9 drivers/i2c/busses/Makefile | 1 drivers/i2c/busses/i2c-sh_mobile.c | 504 +++++++++++++++++++++++++++++++++++++ 3 files changed, 513 insertions(+)
drivers/i2c/busses/Kconfig +9 -0
@@ -684,4 +684,13 @@ config I2C_PMCMSP This driver can also be built as module. If so, the module will be called i2c-pmcmsp. +config I2C_SH_MOBILE + tristate "SuperH Mobile I2C Controller" + help + If you say yes to this option, support will be included for the + built-in I2C interface on the Renesas SH-Mobile processor. + + This driver can also be built as a module. If so, the module + will be called i2c-sh_mobile. + endmenu
drivers/i2c/busses/Makefile +1 -0
@@ -53,6 +53,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_SH_MOBILE) += i2c-sh_mobile.o ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG
drivers/i2c/busses/i2c-sh_mobile.c new file +497 -0
497 lines not on this page · raw message
Quoted 5 lines · On Tue, 25 Mar 2008 19:55:59 +0900 Paul Mundt <[email protected]> wrote:
This is V3 of the SuperH Mobile I2C Controller Driver. A simple Master only driver for the I2C block included in processors such as sh7343, sh7722 and sh7723. Tested on a sh7722 MigoR using a rs5c372b rtc.
+#include <
asm/io.h>
please use checkpatch.
Quoted 29 lines
drivers/i2c/busses/i2c-sh_mobile.c new file +29
-0+static unsigned char i2c_op (struct sh_mobile_i2c_data *pd, +int op,unsigned char data) +{ +unsigned char ret =0 ; + +dev_dbg (pd->dev,"op %d, data in 0x%02x\n" , op, data); + +spin_lock_irq (&pd->lock); + +switch (op) { +case OP_START : +iowrite8 (0x94 ,ICCR (pd)); +break ; +case OP_TX_ONLY : +iowrite8 (data,ICDR (pd)); +break ; +case OP_TX_STOP : +iowrite8 (data,ICDR (pd)); +iowrite8 (0x90 ,ICCR (pd)); +iowrite8 (ICIC_ALE |ICIC_TACKE ,ICIC (pd)); +break ; +case OP_TX_TO_RX : +iowrite8 (data,ICDR (pd)); +iowrite8 (0x81 ,ICCR (pd)); +break ; +case OP_RX_ONLY : + ret =ioread8 (ICDR (pd)); +break ; +case OP_RX_STOP :
drivers/i2c/busses/i2c-sh_mobile.c line 159
Quoted 10 lines
drivers/i2c/busses/i2c-sh_mobile.c new file +10
-0+ ret =ioread8 (ICDR (pd)); +iowrite8 (0xc0 ,ICCR (pd)); +break ; + } + +spin_unlock_irq (&pd->lock); + +dev_dbg (pd->dev,"op %d, data out 0x%02x\n" , op, ret); +return ret; +}
I'd be a bit concerned about reenabling interrupts...
Quoted 13 lines
drivers/i2c/busses/i2c-sh_mobile.c new file +13
-0+static irqreturn_t sh_mobile_i2c_isr (int irq,void *dev_id) +{ +struct platform_device *dev = dev_id; +struct sh_mobile_i2c_data *pd =platform_get_drvdata (dev); +struct i2c_msg *msg = pd->msg; +unsigned char data, sr; +int wakeup =0 ; + + sr =ioread8 (ICSR (pd)); + pd->sr |= sr; + + dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, + (msg->flags & I2C_M_RD) ? "read" : "write",
drivers/i2c/busses/i2c-sh_mobile.c line 183
Quoted 10 lines
drivers/i2c/busses/i2c-sh_mobile.c new file +10
-0+ pd->pos, msg->len); + +if (sr & (ICSR_AL |ICSR_TACK )) { +iowrite8 (0 ,ICIC (pd));/* disable interrupts */ + wakeup =1 ; + goto do_wakeup; + } + +if (pd->pos == msg->len) { +i2c_op (pd,OP_RX_ONLY ,0 );
from the interrupt handler...
drivers/i2c/busses/i2c-sh_mobile.c line 360
Quoted 12 lines
drivers/i2c/busses/i2c-sh_mobile.c new file +12
-0+static int sh_mobile_i2c_hook_irqs (struct platform_device *dev,int hook) +{ +struct resource *res; +int ret = -ENXIO ; +int q, m; +int k =0 ; +int n =0 ; + +while ((res =platform_get_resource (dev,IORESOURCE_IRQ , k))) { +for (n = res->start; hook && n <= res->end; n++) { +if (request_irq (n, sh_mobile_i2c_isr,0 , + dev->dev.bus_id, dev))
even though it isn't using IRQF_DISABLED here,
: int request_irq(unsigned int irq, irq_handler_t handler,
: unsigned long irqflags, const char *devname, void *dev_id)
: {
: struct irqaction *action;
: int retval;
:
: #ifdef CONFIG_LOCKDEP
: /*
: * Lockdep wants atomic interrupt handlers:
: */
: irqflags |= IRQF_DISABLED;
: #endif
it will do so if lockdep is supported.
Quoted 1 line · On Tue, 25 Mar 2008 19:55:59 +0900 Paul Mundt <[email protected]> wrote:
This is V3 of the SuperH Mobile I2C Controller Driver.
i386 allmodconfig:
ERROR: "clk_get_rate" [drivers/i2c/busses/i2c-sh_mobile.ko] undefined!
ERROR: "clk_get" [drivers/i2c/busses/i2c-sh_mobile.ko] undefined!
ERROR: "clk_put" [drivers/i2c/busses/i2c-sh_mobile.ko] undefined!