I2C: OMAP1: OMAP2+: I2C fixes, removal of cpu_is... from driver
Subsystems (7)
cover I2C: OMAP1: OMAP2+: I2C fixes, removal of cpu_is... from driver
The following series removes cpu_...() usage completely from the omap-i2c driver by having decisions about functional implementation choices in the SoC held in cpu-specific hwmod tables that are already established, or for OMAP1 where there is no hwmod, set at OMAP1-specific i2c bus addition time.
Along the way it solves two issues with the existing implementation, that only 16-bit accesses are documented to be allowed to the I2C peripheral unit, and that due to a confusion in the existing driver about whether it is faced with a newer IP version on OMAP3530, currently it writes to a random non-existent I2C register at times on that platform.
The patch series is quite extended from the first try thanks to comments from Benoit Cousson.
This 3rd try is based on 2.6.38-rc8 as requested.
---
Andy Green (18):
I2C: OMAP1/OMAP2+: prepend I2C IP version to probed version shown in dev_info
I2C: OMAP2+: Convert omap I2C driver to use feature implementation flags from platform data
I2C: OMAP1: set i2c unit feature implementation flags in platform data OMAP2+: hwmod data: add correct functionality flags to all omap2plus i2c dev_attr
I2C: OMAP1/OMAP2+: create omap I2C functionality flags for each cpu_... test
I2C: OMAP2+: Pass flags up to omap i2c platform_data as well
I2C: OMAP1/OMAP2+: add flags field to omap i2c platform data
I2C: OMAP2+: increase omap_i2c_dev_attr flags from u8 to u32
I2C: OMAP2+: address confused probed version naming
I2C: OMAP2+: Solve array bounds overflow error on i2c idle
I2C: OMAP2+: use platform_data ip revision to select register map
I2C: OMAP2+: Pass hwmod rev knowledge via platform_data when i2c bus added
I2C: OMAP1: set IP revision in platform data
I2C: OMAP: add rev to omap i2c platform data
I2C: OMAP2+: hwmod data: Tag all OMAP2+ hwmod definitions with I2C IP revision
I2C: OMAP2+: Introduce I2C IP versioning constants
I2C: OMAP2+: Name registers in I2C IP V2 only accordingly
OMAP2+: hwmod data: Set hwmod flags to only allow 16-bit accesses to i2c
arch/arm/mach-omap2/omap_hwmod_2420_data.c | 8 ++ arch/arm/mach-omap2/omap_hwmod_2430_data.c | 6 ++ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 13 ++++ arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 19 ++++- arch/arm/plat-omap/i2c.c | 27 ++++++++ arch/arm/plat-omap/include/plat/i2c.h | 3 + drivers/i2c/busses/i2c-omap.c | 98 +++++++++++++++------------- include/linux/i2c-omap.h | 29 ++++++++ 8 files changed, 152 insertions(+), 51 deletions(-)
Signature · 1 line
Signature
PATCH 1/18 OMAP2+: hwmod data: Set hwmod flags to only allow 16-bit accesses to i2c
Peter Maydell noticed when running under QEMU he was getting errors reporting 32-bit access to I2C peripheral unit registers that are documented to be 8 or 16-bit only[1][2]
The I2C driver is blameless as it wraps its accesses in a function using __raw_writew and __raw_readw, it turned out it is the hwmod stuff.
However the hwmod code already has a flag to force a peripheral unit to only be accessed using 16-bit operations.
This patch applies the 16-bit only flag to the 2430, OMAP3xxx and OMAP44xx hwmod structs. 2420 was already correctly marked up as 16-bit.
The 2430 change will need testing by TI as arranged in the comments to the previous patch version.
When the 16-bit flag is or-ed with other flags, it is placed first as requested in comments.
[1] OMAP4430 Technical reference manual section 23.1.6.2
[2] OMAP3530 Technical reference manual section 18.6
---
arch/arm/mach-omap2/omap_hwmod_2430_data.c | 2 ++ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 3 +++ arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 8 ++++---- 3 files changed, 9 insertions(+), 4 deletions(-)
arch/arm/mach-omap2/omap_hwmod_2430_data.c +2 -0
@@ -504,6 +504,7 @@ static struct omap_hwmod_ocp_if *omap2430_i2c1_slaves[] = {static struct omap_hwmod omap2430_i2c1_hwmod = { .name ="i2c1" , + .flags =HWMOD_16BIT_REG , .mpu_irqs = i2c1_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (i2c1_mpu_irqs), .sdma_reqs = i2c1_sdma_reqs,
@@ -550,6 +551,7 @@ static struct omap_hwmod_ocp_if *omap2430_i2c2_slaves[] = {static struct omap_hwmod omap2430_i2c2_hwmod = { .name ="i2c2" , + .flags =HWMOD_16BIT_REG , .mpu_irqs = i2c2_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (i2c2_mpu_irqs), .sdma_reqs = i2c2_sdma_reqs,
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +3 -0
@@ -685,6 +685,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_i2c1_slaves[] = {static struct omap_hwmod omap3xxx_i2c1_hwmod = { .name ="i2c1" , + .flags =HWMOD_16BIT_REG , .mpu_irqs = i2c1_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (i2c1_mpu_irqs), .sdma_reqs = i2c1_sdma_reqs,
@@ -727,6 +728,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_i2c2_slaves[] = {static struct omap_hwmod omap3xxx_i2c2_hwmod = { .name ="i2c2" , + .flags =HWMOD_16BIT_REG , .mpu_irqs = i2c2_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (i2c2_mpu_irqs), .sdma_reqs = i2c2_sdma_reqs,
@@ -769,6 +771,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_i2c3_slaves[] = {static struct omap_hwmod omap3xxx_i2c3_hwmod = { .name ="i2c3" , + .flags =HWMOD_16BIT_REG , .mpu_irqs = i2c3_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (i2c3_mpu_irqs), .sdma_reqs = i2c3_sdma_reqs,
arch/arm/mach-omap2/omap_hwmod_44xx_data.c +4 -4
@@ -1150,7 +1150,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c1_slaves[] = {static struct omap_hwmod omap44xx_i2c1_hwmod = { .name ="i2c1" , .class = &omap44xx_i2c_hwmod_class, - .flags =HWMOD_INIT_NO_RESET , + .flags =HWMOD_16BIT_REG |HWMOD_INIT_NO_RESET , .mpu_irqs = omap44xx_i2c1_irqs, .mpu_irqs_cnt =ARRAY_SIZE (omap44xx_i2c1_irqs), .sdma_reqs = omap44xx_i2c1_sdma_reqs,
@@ -1203,7 +1203,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c2_slaves[] = {static struct omap_hwmod omap44xx_i2c2_hwmod = { .name ="i2c2" , .class = &omap44xx_i2c_hwmod_class, - .flags =HWMOD_INIT_NO_RESET , + .flags =HWMOD_16BIT_REG |HWMOD_INIT_NO_RESET , .mpu_irqs = omap44xx_i2c2_irqs, .mpu_irqs_cnt =ARRAY_SIZE (omap44xx_i2c2_irqs), .sdma_reqs = omap44xx_i2c2_sdma_reqs,
@@ -1256,7 +1256,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c3_slaves[] = {static struct omap_hwmod omap44xx_i2c3_hwmod = { .name ="i2c3" , .class = &omap44xx_i2c_hwmod_class, - .flags =HWMOD_INIT_NO_RESET , + .flags =HWMOD_16BIT_REG |HWMOD_INIT_NO_RESET , .mpu_irqs = omap44xx_i2c3_irqs, .mpu_irqs_cnt =ARRAY_SIZE (omap44xx_i2c3_irqs), .sdma_reqs = omap44xx_i2c3_sdma_reqs,
@@ -1309,7 +1309,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c4_slaves[] = {static struct omap_hwmod omap44xx_i2c4_hwmod = { .name ="i2c4" , .class = &omap44xx_i2c_hwmod_class, - .flags =HWMOD_INIT_NO_RESET , + .flags =HWMOD_16BIT_REG |HWMOD_INIT_NO_RESET , .mpu_irqs = omap44xx_i2c4_irqs, .mpu_irqs_cnt =ARRAY_SIZE (omap44xx_i2c4_irqs), .sdma_reqs = omap44xx_i2c4_sdma_reqs,
PATCH 2/18 I2C: OMAP2+: Name registers in I2C IP V2 only accordingly
In reply to Andy GreenThe OMAP I2C driver dynamically chooses between two register sets of differing sizes depending on the cpu type it finds itself on.
It has been observed that the existing code references non-existing registers on OMAP3530, because while it correctly chose the smaller register layout based on cpu type, the code uses the probed register ID to decide if to execute code referencing an extra register, and both register layout devices on OMAP3530 and OMAP4430 report the same probed ID of 0x40.
This patch changes the extended register names only found on IP V2 of the I2C peripheral unit accordingly to help show up errors in usage.
---
drivers/i2c/busses/i2c-omap.c | 23 ++++++++++++----------- 1 files changed, 12 insertions(+), 11 deletions(-)
drivers/i2c/busses/i2c-omap.c +12 -11
@@ -72,11 +72,12 @@ enum {OMAP_I2C_SCLH_REG ,OMAP_I2C_SYSTEST_REG ,OMAP_I2C_BUFSTAT_REG , -OMAP_I2C_REVNB_LO , -OMAP_I2C_REVNB_HI , -OMAP_I2C_IRQSTATUS_RAW , -OMAP_I2C_IRQENABLE_SET , - OMAP_I2C_IRQENABLE_CLR, +/* only on OMAP4430 */ +OMAP_I2C_IP_V2_REVNB_LO , +OMAP_I2C_IP_V2_REVNB_HI , +OMAP_I2C_IP_V2_IRQSTATUS_RAW , +OMAP_I2C_IP_V2_IRQENABLE_SET , + OMAP_I2C_IP_V2_IRQENABLE_CLR, };/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
@@ -244,11 +245,11 @@ const static u8 omap4_reg_map[] = { [OMAP_I2C_SCLH_REG] = 0xb8, [OMAP_I2C_SYSTEST_REG] = 0xbC, [OMAP_I2C_BUFSTAT_REG] = 0xc0, - [OMAP_I2C_REVNB_LO] = 0x00, - [OMAP_I2C_REVNB_HI] = 0x04, - [OMAP_I2C_IRQSTATUS_RAW] = 0x24, - [OMAP_I2C_IRQENABLE_SET] = 0x2c, - [OMAP_I2C_IRQENABLE_CLR] = 0x30, + [OMAP_I2C_IP_V2_REVNB_LO] = 0x00, + [OMAP_I2C_IP_V2_REVNB_HI] = 0x04, + [OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24, + [OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c, + [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, }; static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
@@ -309,7 +310,7 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev) dev->iestate =omap_i2c_read_reg (dev,OMAP_I2C_IE_REG );if (dev->rev >=OMAP_I2C_REV_ON_4430 ) -omap_i2c_write_reg (dev,OMAP_I2C_IRQENABLE_CLR ,1 ); +omap_i2c_write_reg (dev,OMAP_I2C_IP_V2_IRQENABLE_CLR ,1 );else omap_i2c_write_reg (dev,OMAP_I2C_IE_REG ,0 );
PATCH 3/18 I2C: OMAP2+: Introduce I2C IP versioning constants
In reply to Andy GreenThese represent the two kinds of (incompatible) OMAP I2C peripheral unit in use so far.
The constants are in linux/i2c-omap.h so the omap i2c driver can have them too.
---
arch/arm/plat-omap/include/plat/i2c.h | 1 + include/linux/i2c-omap.h | 12 ++++++++++++ 2 files changed, 13 insertions(+), 0 deletions(-)
arch/arm/plat-omap/include/plat/i2c.h +1 -0
@@ -22,6 +22,7 @@#define __ASM__ARCH_OMAP_I2C_H#include <linux/i2c.h> +#include <linux/i2c-omap.h> #if defined(CONFIG_I2C_OMAP ) || defined(CONFIG_I2C_OMAP_MODULE ) extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
include/linux/i2c-omap.h +12 -0
@@ -3,6 +3,18 @@#include <linux/platform_device.h> +/* +* Version 2 of the I2C peripheral unit has a different register +* layout and extra registers. The ID register in the V2 peripheral +* unit on the OMAP4430 reports the same ID as the V1 peripheral +* unit on the OMAP3530, so we must inform the driver which IP +* version we know it is running on from platform / cpu-specific +* code using these constants in the hwmod class definition. +*/ + +#define OMAP_I2C_IP_VERSION_1 1 +#define OMAP_I2C_IP_VERSION_2 2 +struct omap_i2c_bus_platform_data {u32 clkrate;void (*set_mpu_wkup_lat)(struct device *dev,long set);
PATCH 4/18 I2C: OMAP2+: hwmod data: Tag all OMAP2+ hwmod definitions with I2C IP revision
In reply to Andy GreenSince we cannot trust (or even reliably find) the OMAP I2C peripheral unit's own revision register, we must inform the OMAP I2C driver of which IP version it is running on. We do this by tagging the omap_hwmod_class for I2C on all the OMAP2+ platform / cpu specific hwmod init and passing it up to the driver (next patches).
---
arch/arm/mach-omap2/omap_hwmod_2420_data.c | 1 + arch/arm/mach-omap2/omap_hwmod_2430_data.c | 1 + arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 1 + arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 1 + 4 files changed, 4 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +1 -0
@@ -482,6 +482,7 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = {static struct omap_hwmod_class i2c_class = { .name ="i2c" , .sysc = &i2c_sysc, + .rev =OMAP_I2C_IP_VERSION_1 , };static struct omap_i2c_dev_attr i2c_dev_attr;
arch/arm/mach-omap2/omap_hwmod_2430_data.c +1 -0
@@ -481,6 +481,7 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = {static struct omap_hwmod_class i2c_class = { .name ="i2c" , .sysc = &i2c_sysc, + .rev =OMAP_I2C_IP_VERSION_1 , };static struct omap_i2c_dev_attr i2c_dev_attr = {
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +1 -0
@@ -662,6 +662,7 @@ static struct omap_hwmod omap3xxx_uart4_hwmod = {static struct omap_hwmod_class i2c_class = { .name ="i2c" , .sysc = &i2c_sysc, + .rev =OMAP_I2C_IP_VERSION_1 , };/* I2C1 */
arch/arm/mach-omap2/omap_hwmod_44xx_data.c +1 -0
@@ -1111,6 +1111,7 @@ static struct omap_hwmod_class_sysconfig omap44xx_i2c_sysc = {static struct omap_hwmod_class omap44xx_i2c_hwmod_class = { .name ="i2c" , .sysc = &omap44xx_i2c_sysc, + .rev =OMAP_I2C_IP_VERSION_2 , };/* i2c1 */
PATCH 5/18 I2C: OMAP: add rev to omap i2c platform data
In reply to Andy GreenWe need to pass the I2C IP revision from the hwmod class up into the OMAP I2C driver, which does not have direct access to it.
This adds a member to the platform data the OMAP I2C driver does use already to hold the I2C IP revision.
---
include/linux/i2c-omap.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
include/linux/i2c-omap.h +1 -0
@@ -17,6 +17,7 @@struct omap_i2c_bus_platform_data {u32 clkrate; +u32 rev;void (*set_mpu_wkup_lat)(struct device *dev,long set);int (*device_enable) (struct platform_device *pdev);int (*device_shutdown) (struct platform_device *pdev);
PATCH 6/18 I2C: OMAP1: set IP revision in platform data
In reply to Andy GreenAll OMAP1 are using "IP revision 1" in terms of register layout. We set this information in omap1_i2c_add_bus() so we don't have to use cpu_is_xxx() any more in the omap i2c driver.
---
arch/arm/plat-omap/i2c.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
arch/arm/plat-omap/i2c.c +3 -0
@@ -108,6 +108,9 @@ static inline int omap1_i2c_add_bus(int bus_id) res[1 ].start =INT_I2C ; pdata = &i2c_pdata[bus_id -1 ]; +/* all OMAP1 have IP version 1 register set */ + pdata->rev =OMAP_I2C_IP_VERSION_1 ; +return platform_device_register (pdev); }
PATCH 7/18 I2C: OMAP2+: Pass hwmod rev knowledge via platform_data when i2c bus added
In reply to Andy GreenMark each OMAP I2C bus with the hwmod's knowledge of which I2C IP version is in the chip we're running on.
---
arch/arm/plat-omap/i2c.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
arch/arm/plat-omap/i2c.c +6 -0
@@ -155,6 +155,12 @@ static inline int omap2_i2c_add_bus(int bus_id) pdata = &i2c_pdata[bus_id -1 ];/* +* pass the hwmod class's CPU-specific knowledge of I2C IP revision in +* use up to the OMAP I2C driver via platform data +*/ + pdata->rev = oh->class->rev; + +/* * When waiting for completion of a i2c transfer, we need to * set a wake up latency constraint for the MPU. This is to * ensure quick enough wakeup from idle, when transfer
PATCH 8/18 I2C: OMAP2+: use platform_data ip revision to select register map
In reply to Andy GreenChange the register map names to reflect the IP revision they are representing, and use the platform_data IP revision index to select between them at init time.
Eliminates 1 of 17 cpu_...() calls in the driver.
---
drivers/i2c/busses/i2c-omap.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-)
drivers/i2c/busses/i2c-omap.c +5 -5
@@ -205,7 +205,7 @@ struct omap_i2c_dev {u16 errata; }; -const static u8 reg_map[] = { +const static u8 reg_map_ip_v1[] = { [OMAP_I2C_REV_REG ] =0x00 , [OMAP_I2C_IE_REG ] =0x01 , [OMAP_I2C_STAT_REG ] =0x02 ,
@@ -226,7 +226,7 @@ const static u8 reg_map[] = { [OMAP_I2C_BUFSTAT_REG] = 0x10, }; -const static u8 omap4_reg_map[] = { +const static u8 reg_map_ip_v2[] = { [OMAP_I2C_REV_REG ] =0x04 , [OMAP_I2C_IE_REG ] =0x2c , [OMAP_I2C_STAT_REG ] =0x28 ,
@@ -1037,10 +1037,10 @@ omap_i2c_probe(struct platform_device *pdev)else dev->reg_shift =2 ; -if (cpu_is_omap44xx ()) - dev->regs = (u8 *) omap4_reg_map; +if (pdata->rev ==OMAP_I2C_IP_VERSION_2 ) + dev->regs = (u8 *)reg_map_ip_v2;else - dev->regs = (u8 *) reg_map; + dev->regs = (u8 *)reg_map_ip_v1;pm_runtime_enable (&pdev->dev);omap_i2c_unidle (dev);
PATCH 9/18 I2C: OMAP2+: Solve array bounds overflow error on i2c idle
In reply to Andy GreenThis solves the main problem the patch series is about. Prior to this patch on OMAP3530 the driver wrongly interprets the I2C peripheral unit's own reported revision as meaning it is running on an IP V2 device and must use the extended registers.
In fact OMAP3530 is IP V1 with the smaller register set, the reason for the confusion is that the hardware does in fact report having the same IP revision index as is found on an OMAP4430, which really is IP V2 and has the extended registers.
This corrects the test for which registers to use so that it decides using hwmod knowledge found in the platform_data.
---
drivers/i2c/busses/i2c-omap.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/i2c/busses/i2c-omap.c +1 -1
@@ -309,7 +309,7 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev) pdata = pdev->dev.platform_data; dev->iestate =omap_i2c_read_reg (dev,OMAP_I2C_IE_REG ); -if (dev->rev >=OMAP_I2C_REV_ON_4430 ) +if (pdata->rev ==OMAP_I2C_IP_VERSION_2 )omap_i2c_write_reg (dev,OMAP_I2C_IP_V2_IRQENABLE_CLR ,1 );else omap_i2c_write_reg (dev,OMAP_I2C_IE_REG ,0 );
PATCH 10/18 I2C: OMAP2+: address confused probed version naming
In reply to Andy GreenThe driver reflects the confusion that probed I2C revision from the hardware of 0x40 means it is on an OMAP4430.
However, you will probe the same 0x40 ID on an OMAP3530. So this patch changes the name to reflect that.
It also clarifies that the original name OMAP_I2C_REV_2 is referring to some ancient OMAP1 revision number, not to be confused with the IP revisions this patch series introduces.
Similarly the term "rev" is used in the ancient OMAP1 ISR, the term is changed to use omap1 instead.
---
drivers/i2c/busses/i2c-omap.c | 19 ++++++++++--------- 1 files changed, 10 insertions(+), 9 deletions(-)
drivers/i2c/busses/i2c-omap.c +10 -9
@@ -42,12 +42,12 @@#include <linux/pm_runtime.h> /* I2C controller revisions */ -#define OMAP_I2C_REV_2 0x20 +#define OMAP_I2C_OMAP1_REV_2 0x20/* I2C controller revisions present on specific hardware */ #define OMAP_I2C_REV_ON_2430 0x36#define OMAP_I2C_REV_ON_3430 0x3C -#define OMAP_I2C_REV_ON_4430 0x40 +#define OMAP_I2C_REV_ON_3530_4430 0x40/* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -314,7 +314,7 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)else omap_i2c_write_reg (dev,OMAP_I2C_IE_REG ,0 ); -if (dev->rev <OMAP_I2C_REV_2 ) { +if (dev->rev <OMAP_I2C_OMAP1_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);
@@ -336,7 +336,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)unsigned long internal_clk =0 ;struct clk *fclk; -if (dev->rev >=OMAP_I2C_REV_2 ) { +if (dev->rev >=OMAP_I2C_OMAP1_REV_2 ) {/* Disable I2C controller before soft reset */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
@@ -379,7 +379,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)* REVISIT: Some wkup sources might not be needed. */ dev->westate =OMAP_I2C_WE_ALL ; -if (dev->rev <OMAP_I2C_REV_ON_4430 ) +if (dev->rev <OMAP_I2C_REV_ON_3530_4430 )omap_i2c_write_reg (dev,OMAP_I2C_WE_REG , dev->westate); }
@@ -723,7 +723,7 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat)#ifdef CONFIG_ARCH_OMAP15XX static irqreturn_t -omap_i2c_rev1_isr (int this_irq,void *dev_id) +omap_i2c_omap1_isr (int this_irq,void *dev_id) {struct omap_i2c_dev *dev = dev_id;u16 iv, w;
@@ -777,7 +777,7 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id) return IRQ_HANDLED; }#else -#define omap_i2c_rev1_isr NULL +#define omap_i2c_omap1_isr NULL#endif /*
@@ -1062,7 +1062,7 @@ omap_i2c_probe(struct platform_device *pdev)* size. This is to ensure that we can handle the status on int * call back latencies. */ -if (dev->rev >=OMAP_I2C_REV_ON_4430 ) { +if (dev->rev >=OMAP_I2C_REV_ON_3530_4430 ) { dev->fifo_size =0 ; dev->b_hw =0 ;/* Disable hardware fixes */ }else {
@@ -1078,7 +1078,8 @@ omap_i2c_probe(struct platform_device *pdev)/* reset ASAP, clearing any IRQs */ omap_i2c_init (dev); - isr = (dev->rev <OMAP_I2C_REV_2 ) ? omap_i2c_rev1_isr : omap_i2c_isr; + isr = (dev->rev <OMAP_I2C_OMAP1_REV_2 ) ? omap_i2c_omap1_isr : + omap_i2c_isr; r =request_irq (dev->irq, isr,0 , pdev->name, dev);if (r) {
PATCH 11/18 I2C: OMAP2+: increase omap_i2c_dev_attr flags from u8 to u32
In reply to Andy GreenAs part of removing cpu_...() from the OMAP I2C driver, we need to convert the CPU tests into functionality flags that are set by hwmod class in the same way the IP revision is.
More flags are needed than will fit in the existing u8 flags member of omap_i2c_dev_attr.
These flags can refer to options inside the IP block but they are most needed for information about cpu implementation specific options that are not part of the IP block itself. For example, how the CPU data bus is wired to the IP block databus differs between OMAP cpus and affects how you must shift the address in the IP block, but is not a feature of the IP block itself.
---
arch/arm/plat-omap/include/plat/i2c.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
arch/arm/plat-omap/include/plat/i2c.h +1 -1
@@ -47,7 +47,7 @@ static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,*/ struct omap_i2c_dev_attr {u8 fifo_depth; -u8 flags; +u32 flags; };void __init omap1_i2c_mux_pins (int bus_id);
PATCH 12/18 I2C: OMAP1/OMAP2+: add flags field to omap i2c platform data
In reply to Andy GreenOMAP I2C driver can access the configuration flags through its platform data.
---
include/linux/i2c-omap.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
include/linux/i2c-omap.h +1 -0
@@ -18,6 +18,7 @@struct omap_i2c_bus_platform_data {u32 clkrate;u32 rev; +u32 flags;void (*set_mpu_wkup_lat)(struct device *dev,long set);int (*device_enable) (struct platform_device *pdev);int (*device_shutdown) (struct platform_device *pdev);
PATCH 13/18 I2C: OMAP2+: Pass flags up to omap i2c platform_data as well
In reply to Andy GreenThis is how the driver can find the flags for its implementation functionality in its platform_data
---
arch/arm/plat-omap/i2c.c | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-)
arch/arm/plat-omap/i2c.c +6 -1
@@ -141,6 +141,7 @@ static inline int omap2_i2c_add_bus(int bus_id)struct omap_device *od;char oh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN ];struct omap_i2c_bus_platform_data *pdata; +struct omap_i2c_dev_attr *dev_attr;omap2_i2c_mux_pins (bus_id);
@@ -156,10 +157,14 @@ static inline int omap2_i2c_add_bus(int bus_id) pdata = &i2c_pdata[bus_id -1 ];/* * pass the hwmod class's CPU-specific knowledge of I2C IP revision in -* use up to the OMAP I2C driver via platform data +* use, and functionality implementation flags, up to the OMAP I2C +* driver via platform data */ pdata->rev = oh->class->rev; + dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr; + pdata->flags = dev_attr->flags; +/* * When waiting for completion of a i2c transfer, we need to * set a wake up latency constraint for the MPU. This is to
PATCH 14/18 I2C: OMAP1/OMAP2+: create omap I2C functionality flags for each cpu_... test
In reply to Andy GreenThese represent the 8 kinds of implementation functionality that up until now were inferred by the 16 remaining cpu_...() tests in the omap i2c driver.
Changed to use BIT() as suggested by Balaji T Krishnamoorthy.
---
include/linux/i2c-omap.h | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-)
include/linux/i2c-omap.h +15 -0
@@ -15,6 +15,21 @@#define OMAP_I2C_IP_VERSION_1 1#define OMAP_I2C_IP_VERSION_2 2 +/* struct omap_i2c_bus_platform_data .flags meanings */ + +#define OMAP_I2C_FLAG_NO_FIFO BIT(0) +#define OMAP_I2C_FLAG_SIMPLE_CLOCK BIT(1) +#define OMAP_I2C_FLAG_16BIT_DATA_REG BIT(2) +#define OMAP_I2C_FLAG_RESET_REGS_POSTIDLE BIT(3) +#define OMAP_I2C_FLAG_APPLY_ERRATA_I207 BIT(4) +#define OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK BIT(5) +#define OMAP_I2C_FLAG_FORCE_19200_INT_CLK BIT(6) +/* how the CPU address bus must be translated for I2C unit access */ +#define OMAP_I2C_FLAG_BUS_SHIFT_NONE 0 +#define OMAP_I2C_FLAG_BUS_SHIFT_1 BIT(7) +#define OMAP_I2C_FLAG_BUS_SHIFT_2 BIT(8) +#define OMAP_I2C_FLAG_BUS_SHIFT__SHIFT 7 +struct omap_i2c_bus_platform_data {u32 clkrate;u32 rev;
PATCH 15/18 OMAP2+: hwmod data: add correct functionality flags to all omap2plus i2c dev_attr
In reply to Andy GreenFrom: Andy Green <[email protected]>
This adds the new functionality flags for OMAP i2c unit to all OMAP2+ hwmod definitions.
[b-cousson at ti.com: Move dev_attr to stick to
hwmod template, update the subject]
---
arch/arm/mach-omap2/omap_hwmod_2420_data.c | 7 ++++++- arch/arm/mach-omap2/omap_hwmod_2430_data.c | 3 +++ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 9 +++++++++ arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 10 ++++++++++ 4 files changed, 28 insertions(+), 1 deletions(-)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +6 -1
@@ -485,7 +485,12 @@ static struct omap_hwmod_class i2c_class = { .rev = OMAP_I2C_IP_VERSION_1, }; -static struct omap_i2c_dev_attr i2c_dev_attr; +static struct omap_i2c_dev_attr i2c_dev_attr = { + .flags =OMAP_I2C_FLAG_NO_FIFO | +OMAP_I2C_FLAG_SIMPLE_CLOCK | +OMAP_I2C_FLAG_16BIT_DATA_REG | +OMAP_I2C_FLAG_BUS_SHIFT_2 , +};/* I2C1 */
arch/arm/mach-omap2/omap_hwmod_2430_data.c +3 -0
@@ -486,6 +486,9 @@ static struct omap_hwmod_class i2c_class = {static struct omap_i2c_dev_attr i2c_dev_attr = { .fifo_depth =8 ,/* bytes */ + .flags =OMAP_I2C_FLAG_APPLY_ERRATA_I207 | +OMAP_I2C_FLAG_BUS_SHIFT_2 | +OMAP_I2C_FLAG_FORCE_19200_INT_CLK , };/* I2C1 */
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +9 -0
@@ -669,6 +669,9 @@ static struct omap_hwmod_class i2c_class = {static struct omap_i2c_dev_attr i2c1_dev_attr = { .fifo_depth =8 ,/* bytes */ + .flags =OMAP_I2C_FLAG_APPLY_ERRATA_I207 | +OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | +OMAP_I2C_FLAG_BUS_SHIFT_2 , };static struct omap_hwmod_irq_info i2c1_mpu_irqs[] = {
@@ -712,6 +715,9 @@ static struct omap_hwmod omap3xxx_i2c1_hwmod = {static struct omap_i2c_dev_attr i2c2_dev_attr = { .fifo_depth =8 ,/* bytes */ + .flags =OMAP_I2C_FLAG_APPLY_ERRATA_I207 | +OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | +OMAP_I2C_FLAG_BUS_SHIFT_2 , };static struct omap_hwmod_irq_info i2c2_mpu_irqs[] = {
@@ -755,6 +761,9 @@ static struct omap_hwmod omap3xxx_i2c2_hwmod = {static struct omap_i2c_dev_attr i2c3_dev_attr = { .fifo_depth =64 ,/* bytes */ + .flags =OMAP_I2C_FLAG_APPLY_ERRATA_I207 | +OMAP_I2C_FLAG_RESET_REGS_POSTIDLE | +OMAP_I2C_FLAG_BUS_SHIFT_2 , };static struct omap_hwmod_irq_info i2c3_mpu_irqs[] = {
arch/arm/mach-omap2/omap_hwmod_44xx_data.c +10 -0
@@ -24,6 +24,7 @@#include <plat/cpu.h> #include <plat/gpio.h> #include <plat/dma.h> +#include <plat/i2c.h> #include "omap_hwmod_common_data.h"
@@ -1114,6 +1115,11 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = { .rev = OMAP_I2C_IP_VERSION_2, }; +/* i2c dev_attr */ +static struct omap_i2c_dev_attr i2c_dev_attr = { + .flags =OMAP_I2C_FLAG_BUS_SHIFT_NONE , +}; +/* i2c1 */ static struct omap_hwmod omap44xx_i2c1_hwmod;static struct omap_hwmod_irq_info omap44xx_i2c1_irqs[] = {
@@ -1162,6 +1168,7 @@ static struct omap_hwmod omap44xx_i2c1_hwmod = { .clkctrl_reg = OMAP4430_CM_L4PER_I2C1_CLKCTRL, }, }, + .dev_attr = &i2c_dev_attr, .slaves = omap44xx_i2c1_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_i2c1_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -1215,6 +1222,7 @@ static struct omap_hwmod omap44xx_i2c2_hwmod = { .clkctrl_reg = OMAP4430_CM_L4PER_I2C2_CLKCTRL, }, }, + .dev_attr = &i2c_dev_attr, .slaves = omap44xx_i2c2_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_i2c2_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -1268,6 +1276,7 @@ static struct omap_hwmod omap44xx_i2c3_hwmod = { .clkctrl_reg = OMAP4430_CM_L4PER_I2C3_CLKCTRL, }, }, + .dev_attr = &i2c_dev_attr, .slaves = omap44xx_i2c3_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_i2c3_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
@@ -1321,6 +1330,7 @@ static struct omap_hwmod omap44xx_i2c4_hwmod = { .clkctrl_reg = OMAP4430_CM_L4PER_I2C4_CLKCTRL, }, }, + .dev_attr = &i2c_dev_attr, .slaves = omap44xx_i2c4_slaves, .slaves_cnt = ARRAY_SIZE(omap44xx_i2c4_slaves), .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
PATCH 16/18 I2C: OMAP1: set i2c unit feature implementation flags in platform data
In reply to Andy GreenMost of the OMAP1 implementation flags are set statically, with the exception that omap7xx has its data bus wired up differently.
---
arch/arm/plat-omap/i2c.c | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-)
arch/arm/plat-omap/i2c.c +13 -0
@@ -111,6 +111,19 @@ static inline int omap1_i2c_add_bus(int bus_id)/* all OMAP1 have IP version 1 register set */ pdata->rev =OMAP_I2C_IP_VERSION_1 ; +/* all OMAP1 I2C are implemented like this */ + pdata->flags =OMAP_I2C_FLAG_NO_FIFO | +OMAP_I2C_FLAG_SIMPLE_CLOCK | +OMAP_I2C_FLAG_16BIT_DATA_REG | +OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK ; + +/* how the cpu bus is wired up differs for 7xx only */ + +if (cpu_is_omap7xx ()) + pdata->flags |=OMAP_I2C_FLAG_BUS_SHIFT_1 ; +else + pdata->flags |=OMAP_I2C_FLAG_BUS_SHIFT_2 ; +return platform_device_register (pdev); }
PATCH 17/18 I2C: OMAP2+: Convert omap I2C driver to use feature implementation flags from platform data
In reply to Andy GreenThis patch eliminates all cpu_...() tests from the OMAP I2C driver.
Instead, it uses the functionality flags in the platform data to make the decisions about product variations the driver needs to handle.
---
drivers/i2c/busses/i2c-omap.c | 40 +++++++++++++++++++++++----------------- 1 files changed, 23 insertions(+), 17 deletions(-)
drivers/i2c/busses/i2c-omap.c +23 -17
@@ -277,7 +277,7 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)pm_runtime_get_sync (&pdev->dev); -if (cpu_is_omap34xx ()) { +if (pdata->flags &OMAP_I2C_FLAG_RESET_REGS_POSTIDLE ) {omap_i2c_write_reg (dev,OMAP_I2C_CON_REG ,0 );omap_i2c_write_reg (dev,OMAP_I2C_PSC_REG , dev->pscstate);omap_i2c_write_reg (dev,OMAP_I2C_SCLL_REG , dev->scllstate);
@@ -335,6 +335,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)unsigned long timeout;unsigned long internal_clk =0 ;struct clk *fclk; +struct platform_device *pdev; +struct omap_i2c_bus_platform_data *pdata; + + pdev =to_platform_device (dev->dev); + pdata = pdev->dev.platform_data;if (dev->rev >=OMAP_I2C_OMAP1_REV_2 ) {/* Disable I2C controller before soft reset */
@@ -386,7 +391,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) }omap_i2c_write_reg (dev,OMAP_I2C_CON_REG ,0 ); -if (cpu_class_is_omap1 ()) { +if (pdata->flags &OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK ) {/* * The I2C functional clock is the armxor_ck, so there's * no need to get "armxor_ck" separately. Now, if OMAP2420
@@ -410,7 +415,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate /12000000 ; } -if (!(cpu_class_is_omap1 () ||cpu_is_omap2420 ())) { +if (!(pdata->flags &OMAP_I2C_FLAG_SIMPLE_CLOCK )) {/* * HSI2C controller internal clk rate should be 19.2 Mhz for
@@ -418,7 +423,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)* to get longer filter period for better noise suppression. * The filter is iclk (fclk for HS) period. */ -if (dev->speed >400 ||cpu_is_omap2430 ()) +if (dev->speed >400 || + pdata->flags &OMAP_I2C_FLAG_FORCE_19200_INT_CLK ) internal_clk =19200 ;else if (dev->speed >100 ) internal_clk =9600 ;
@@ -487,7 +493,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) dev->errata =0 ; -if (cpu_is_omap2430 () ||cpu_is_omap34xx ()) +if (pdata->flags &OMAP_I2C_FLAG_APPLY_ERRATA_I207 ) dev->errata |=I2C_OMAP_ERRATA_I207 ;/* Enable interrupts */
@@ -496,7 +502,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) OMAP_I2C_IE_AL) | ((dev->fifo_size) ? (OMAP_I2C_IE_RDR |OMAP_I2C_IE_XDR ) :0 );omap_i2c_write_reg (dev,OMAP_I2C_IE_REG , dev->iestate); -if (cpu_is_omap34xx ()) { +if (pdata->flags &OMAP_I2C_FLAG_RESET_REGS_POSTIDLE ) { dev->pscstate = psc; dev->scllstate = scll; dev->sclhstate = sclh;
@@ -816,6 +822,11 @@ omap_i2c_isr(int this_irq, void *dev_id)u16 bits;u16 stat, w;int err, count =0 ; +struct platform_device *pdev; +struct omap_i2c_bus_platform_data *pdata; + + pdev =to_platform_device (dev->dev); + pdata = pdev->dev.platform_data;if (dev->idle)return IRQ_NONE ;
@@ -884,8 +895,8 @@ complete:* Data reg in 2430, omap3 and * omap4 is 8 bit wide */ -if (cpu_class_is_omap1 () || -cpu_is_omap2420 ()) { +if (pdata->flags & +OMAP_I2C_FLAG_16BIT_DATA_REG ) {if (dev->buf_len) { *dev->buf++ = w >>8 ; dev->buf_len--;
@@ -927,8 +938,8 @@ complete:* Data reg in 2430, omap3 and * omap4 is 8 bit wide */ -if (cpu_class_is_omap1 () || -cpu_is_omap2420 ()) { +if (pdata->flags & +OMAP_I2C_FLAG_16BIT_DATA_REG ) {if (dev->buf_len) { w |= *dev->buf++ <<8 ; dev->buf_len--;
@@ -1030,12 +1041,7 @@ omap_i2c_probe(struct platform_device *pdev)platform_set_drvdata (pdev, dev); -if (cpu_is_omap7xx ()) - dev->reg_shift =1 ; -else if (cpu_is_omap44xx ()) - dev->reg_shift =0 ; -else - dev->reg_shift =2 ; + dev->reg_shift = (pdata->flags >>OMAP_I2C_FLAG_BUS_SHIFT__SHIFT ) &3 ;if (pdata->rev ==OMAP_I2C_IP_VERSION_2 ) dev->regs = (u8 *)reg_map_ip_v2;
@@ -1050,7 +1056,7 @@ omap_i2c_probe(struct platform_device *pdev)if (dev->rev <=OMAP_I2C_REV_ON_3430 ) dev->errata |=I2C_OMAP3_1P153 ; -if (!(cpu_class_is_omap1 () ||cpu_is_omap2420 ())) { +if (!(pdata->flags &OMAP_I2C_FLAG_NO_FIFO )) {u16 s;/* Set up the fifo size - Get total size */
PATCH 18/18 I2C: OMAP1/OMAP2+: prepend I2C IP version to probed version shown in dev_info
In reply to Andy GreenThe IP version is prepended to the existing printed probed version as an "epoch" version.
---
drivers/i2c/busses/i2c-omap.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/i2c/busses/i2c-omap.c +2 -2
@@ -1093,8 +1093,8 @@ omap_i2c_probe(struct platform_device *pdev) goto err_unuse_clocks; } -dev_info (dev->dev,"bus %d rev%d.%d at %d kHz\n" , - pdev->id, dev->rev >>4 , dev->rev &0xf , dev->speed); +dev_info (dev->dev,"bus %d rev%d.%d.%d at %d kHz\n" , pdev->id, + pdata->rev, dev->rev >>4 , dev->rev &0xf , dev->speed);omap_i2c_idle (dev);
Tony Lindgren
maintainercover I2C: OMAP1: OMAP2+: I2C fixes, removal of cpu_is... from driver
In reply to Andy GreenHi,
Quoted 5 lines · Andy Green
The following series removes cpu_...() usage completely from the omap-i2c driver by having decisions about functional implementation choices in the SoC held in cpu-specific hwmod tables that are already established, or for OMAP1 where there is no hwmod, set at OMAP1-specific i2c bus addition time.
You should send this to the i2c list with Ben Cc'd.
Tony
cover I2C: OMAP1: OMAP2+: I2C fixes, removal of cpu_is... from driver
Quoted 10 lines · Somebody in the thread at some point
Hi,
Quoted 5 lines · Andy Green
The following series removes cpu_...() usage completely from the omap-i2c driver by having decisions about functional implementation choices in the SoC held in cpu-specific hwmod tables that are already established, or for OMAP1 where there is no hwmod, set at OMAP1-specific i2c bus addition time.
You should send this to the i2c list with Ben Cc'd.
Done... sorry for the fumble. Ben is already CC'd, sorry for spamming his mailbox too.
-Andy