OMAP: I2C: reprogram OCP_SYSCONFIG after device reset
Subsystems (4)
cover OMAP: I2C: reprogram OCP_SYSCONFIG after device reset
Hello,
This patch set programs the I2C controller OCP_SYSCONFIG register after the driver resets the device. It is derived from the changes mentioned by Richard Woodruff <[email protected]> at
however, the CLOCKACTIVITY change on clk_enable()/clk_disable() in that code currently seems pointless, so it has been excluded until more information is available from TI or until problems are encountered.
This patchset should only change behavior on OMAP2x30 and OMAP3xxx devices.
Boot-tested on 2430SDP and 3430SDP; compile-tested with the 5912OSK (OMAP1) defconfig. Comments welcome,
- Paul
---
text data bss dec hex filename
3472584 160600 105760 3738944 390d40 vmlinux.3430sdp.orig 3472616 160600 105760 3738976 390d60 vmlinux.3430sdp
drivers/i2c/busses/i2c-omap.c | 65 ++++++++++++++++++++++++++++++++--------- 1 files changed, 50 insertions(+), 15 deletions(-)
PATCH 1/2 OMAP: I2C: convert 'rev1' flag to generic 'rev' u8
i2c-omap discriminates only between "revision 1" or "greater than revision 1." A following patch introduces code that must also discriminate between rev2.x, rev3.6, and rev3.12 controllers. Support this by storing the full revision data from the I2C_REV register, rather than just a single bit.
The revision definitions may need to be extended for other ES levels that aren't currently available here. rev3.6 is what's present on the 2430SDP here (unknown ES revision); rev3.12 is used on the 3430ES2 here.
--- drivers/i2c/busses/i2c-omap.c | 25 ++++++++++++++++--------- 1 files changed, 16 insertions(+), 9 deletions(-)
drivers/i2c/busses/i2c-omap.c +16 -9
@@ -38,6 +38,13 @@#include <linux/clk.h> #include <linux/io.h> +/* I2C controller revisions */ +#define OMAP_I2C_REV_2 0x20 + +/* I2C controller revisions present on specific hardware */ +#define OMAP_I2C_REV_ON_2430 0x36 +#define OMAP_I2C_REV_ON_3430 0x3C +/* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -139,7 +146,7 @@ struct omap_i2c_dev {* fifo_size==0 implies no fifo * if set, should be trsh+1 */ - unsigned rev1:1; +u8 rev; unsigned b_hw:1; /* bad h/w fixes */ unsigned idle:1;u16 iestate;/* Saved interrupt register */
@@ -220,7 +227,7 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev) dev->iestate =omap_i2c_read_reg (dev,OMAP_I2C_IE_REG );omap_i2c_write_reg (dev,OMAP_I2C_IE_REG ,0 ); -if (dev->rev1) +if (dev->rev <OMAP_I2C_REV_2 ) iv =omap_i2c_read_reg (dev,OMAP_I2C_IV_REG );/* Read clears */ else omap_i2c_write_reg (dev,OMAP_I2C_STAT_REG , dev->iestate);
@@ -244,7 +251,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)unsigned long timeout;unsigned long internal_clk =0 ; -if (!dev->rev1) { +if (dev->rev >=OMAP_I2C_REV_2 ) {omap_i2c_write_reg (dev,OMAP_I2C_SYSC_REG ,OMAP_I2C_SYSC_SRST );/* For some reason we need to set the EN bit before the * reset done bit gets set. */
@@ -718,6 +725,7 @@ omap_i2c_probe(struct platform_device *pdev)struct omap_i2c_dev *dev;struct i2c_adapter *adap;struct resource *mem, *irq, *ioarea; +void *isr;int r;u32 *speed =NULL ;
@@ -769,8 +777,7 @@ omap_i2c_probe(struct platform_device *pdev)omap_i2c_unidle (dev); -if (cpu_is_omap15xx ()) - dev->rev1 =omap_i2c_read_reg (dev,OMAP_I2C_REV_REG ) <0x20 ; + dev->rev =omap_i2c_read_reg (dev,OMAP_I2C_REV_REG ) &0xff ;if (cpu_is_omap2430 () ||cpu_is_omap34xx ()) {u16 s;
@@ -791,16 +798,16 @@ omap_i2c_probe(struct platform_device *pdev)/* reset ASAP, clearing any IRQs */ omap_i2c_init (dev); - r =request_irq (dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr, -0 , pdev->name, dev); + isr = (dev->rev <OMAP_I2C_REV_2 ) ? omap_i2c_rev1_isr : omap_i2c_isr; + r =request_irq (dev->irq, isr,0 , pdev->name, dev);if (r) {dev_err (dev->dev,"failure requesting irq %i\n" , dev->irq); goto err_unuse_clocks; } - r =omap_i2c_read_reg (dev,OMAP_I2C_REV_REG ) &0xff ; +dev_info (dev->dev,"bus %d rev%d.%d at %d kHz\n" , - pdev->id, r >>4 , r &0xf , dev->speed); + pdev->id, dev->rev >>4 , dev->rev &0xf , dev->speed);omap_i2c_idle (dev);
PATCH 2/2 OMAP2/3 I2C: reprogram OCP_SYSCONFIG register after reset
In reply to Paul WalmsleyThe I2C controller clears its OCP_SYSCONFIG register after an OCP soft reset. Reprogram OCP_SYSCONFIG for maximum power savings on rev3.6 controllers and beyond. On 2430, this involves setting the module AUTOIDLE bit. On 3430, this includes module AUTOIDLE, wakeup enable, slave smart-idle, and considers only the module functional clock state for idle-ack.
Boot-tested on 2430SDP and 3430SDP.
--- drivers/i2c/busses/i2c-omap.c | 40 ++++++++++++++++++++++++++++++++++------ 1 files changed, 34 insertions(+), 6 deletions(-)
drivers/i2c/busses/i2c-omap.c +34 -6
@@ -123,11 +123,19 @@#define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ #endif -/* I2C System Status register (OMAP_I2C_SYSS): */ -#define OMAP_I2C_SYSS_RDONE (1 << 0)/* Reset Done */ +/* OCP_SYSSTATUS bit definitions */ +#define SYSS_RESETDONE_MASK (1 << 0) + +/* OCP_SYSCONFIG bit definitions */ +#define SYSC_CLOCKACTIVITY_MASK (0x3 << 8) +#define SYSC_SIDLEMODE_MASK (0x3 << 3) +#define SYSC_ENAWAKEUP_MASK (1 << 2) +#define SYSC_SOFTRESET_MASK (1 << 1) +#define SYSC_AUTOIDLE_MASK (1 << 0) + +#define SYSC_IDLEMODE_SMART 0x2 +#define SYSC_CLOCKACTIVITY_FCLK 0x2 -/* I2C System Configuration Register (OMAP_I2C_SYSC): */ -#define OMAP_I2C_SYSC_SRST (1 << 1)/* Soft Reset */ struct omap_i2c_dev {struct device *dev;
@@ -252,13 +260,13 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)unsigned long internal_clk =0 ;if (dev->rev >=OMAP_I2C_REV_2 ) { -omap_i2c_write_reg (dev,OMAP_I2C_SYSC_REG ,OMAP_I2C_SYSC_SRST ); +omap_i2c_write_reg (dev,OMAP_I2C_SYSC_REG ,SYSC_SOFTRESET_MASK );/* For some reason we need to set the EN bit before the * reset done bit gets set. */ timeout = jiffies +OMAP_I2C_TIMEOUT ;omap_i2c_write_reg (dev,OMAP_I2C_CON_REG ,OMAP_I2C_CON_EN );while (!(omap_i2c_read_reg (dev,OMAP_I2C_SYSS_REG ) & -OMAP_I2C_SYSS_RDONE )) { +SYSS_RESETDONE_MASK )) {if (time_after (jiffies, timeout)) {dev_warn (dev->dev,"timeout waiting " "for controller reset\n" );
@@ -266,6 +274,26 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) }msleep (1 ); } + +/* SYSC register is cleared by the reset; rewrite it */ +if (dev->rev ==OMAP_I2C_REV_ON_2430 ) { + +omap_i2c_write_reg (dev,OMAP_I2C_SYSC_REG , +SYSC_AUTOIDLE_MASK ); + + }else if (dev->rev >=OMAP_I2C_REV_ON_3430 ) { +u32 v; + + v =SYSC_AUTOIDLE_MASK ; + v |=SYSC_ENAWAKEUP_MASK ; + v |= (SYSC_IDLEMODE_SMART << +__ffs (SYSC_SIDLEMODE_MASK )); + v |= (SYSC_CLOCKACTIVITY_FCLK << +__ffs (SYSC_CLOCKACTIVITY_MASK )); + +omap_i2c_write_reg (dev,OMAP_I2C_SYSC_REG , v); + + } }omap_i2c_write_reg (dev,OMAP_I2C_CON_REG ,0 );
RE: [PATCH 2/2] OMAP2/3 I2C: reprogram OCP_SYSCONFIG register after reset
Quoted 3 lines
From: Paul Walmsley [mailto:[email protected]]
Sent: Tuesday, October 14, 2008 7:20 AM
From a quick glance that looks ok.
I'll restate old news posted here before:
For OMAP2 the smart-idle handshake for I2C did not make it to the module and was tied off at prcm level. This required a hack to ensure data was not lost if effective power management was in use. McBSP also had this issue.
On OMAP3 it is all hooked up as expected so modifying handshakes does what is expected.
The OMAP2 errata did mention this.
Regards,
Richard W.
Quoted 3 lines
however, the CLOCKACTIVITY change on clk_enable()/clk_disable() in that code currently seems pointless, so it has been excluded until more information is available from TI or until problems are encountered.
IIRC CLOCKACTIVITY settings mainly had to do with if I2C was master or slave. Part of TI patch set allows slave mode. Seems like some GPS chip needed to be master or something along those lines. One of the TI-ASP groups needed it.
Guidance was you should treat internal clocks differently at ocp-segment-idle-request time if you were the one generating the clock or it was coming in from the outside world. It was reported not doing this correctly would result in possible data being lost.
McBSP and audio have a similar relationship when you do master/slave and your sample clock comes from the outside.
------------
GPTIMER CLOCKACTIVTY is more easily understood. At ocp-segment-idle-request for the system heart beat you want to keep that FCLK running so you set it so. There could be a case with other timers that you just let them be shut down.
Regards,
Richard W.
Tony Lindgren
maintainerQuoted 8 lines · Paul Walmsley
Hello,
This patch set programs the I2C controller
OCP_SYSCONFIGregister after the driver resets the device. It is derived from the changes mentioned by Richard Woodruff <[email protected]> at
Quoted 8 lines
however, the CLOCKACTIVITY change on clk_enable()/clk_disable() in that code currently seems pointless, so it has been excluded until more information is available from TI or until problems are encountered.
This patchset should only change behavior on OMAP2x30 and OMAP3xxx devices.
Boot-tested on 2430SDP and 3430SDP; compile-tested with the 5912OSK (OMAP1) defconfig. Comments welcome,
Pushing both to l-o today, also adding to upstream i2c-omap queue.
Tony
Quoted 17 lines
- Paul
---
text data bss dec hex filename
3472584 160600 105760 3738944 390d40 vmlinux.3430sdp.orig 3472616 160600 105760 3738976 390d60 vmlinux.3430sdpdrivers/i2c/busses/i2c-omap.c | 65 ++++++++++++++++++++++++++++++++--------- 1 files changed, 50 insertions(+), 15 deletions(-)--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html