[PATCH v7] OMAP4:keypad: PM runtime
From: Abraham Arce Enable Runtime PM functionality in OMAP4 driver based on the following assumptions - Runtime PM selected by ARCH_OMAP2PLUS_TYPICAL && ARCH_OMAP2PLUS, which is the default OMAP2+ defconfig including OMAP4 - Runtime PM APIs handles Clock Framework APIs - Do not do the keypadconfig if the irq request fails A minimal pm runtime get/put approach is implemented in probe/remove calls respectively based on: - Keyboard controller in wakeup domain so it is always on and power impact may be minimal - Cutting of clocks will prevent interrupts Signed-off-by: Abraham Arce Cc: Kevin Hilman --- Updating the changelogs as per Kevin's suggestion drivers/input/keyboard/omap4-keypad.c | 11 +-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 45bd097..36239e2 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -239,7 +240,8 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) matrix_keypad_build_keymap(pdata->keymap_data, row_shift, input_dev->keycode, input_dev->keybit); - omap4_keypad_config(keypad_data); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); error = request_irq(keypad_data->irq, omap4_keypad_interrupt, IRQF_TRIGGER_RISING, @@ -255,8 +257,9 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) goto err_free_irq; } - + omap4_keypad_config(keypad_data); platform_set_drvdata(pdev, keypad_data); + return 0; err_free_irq: @@ -278,6 +281,10 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev) struct resource *res; free_irq(keypad_data->irq, keypad_data); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + input_unregister_device(keypad_data->input); iounmap(keypad_data->base); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v7] OMAP4:keypad: PM runtime
From: Abraham Arce Enable Runtime PM functionality in OMAP4 driver based on the following assumptions A minimal pm runtime get/put approach is implemented in probe/remove calls respectively. - Keyboard controller in wakeup domain so it is always on and power impact may be minimal - In OMAP4 the device control is at module/device level and ick/fclk level control is difficult so cutting of clocks will prevent interrupts. Signed-off-by: Abraham Arce Cc: Kevin Hilman --- Updating the changelogs as per Kevin's suggestion drivers/input/keyboard/omap4-keypad.c | 10 +- 1 files changed, 9 insertions(+), 1 deletions(-) diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 45bd097..3d35774 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -239,8 +240,11 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) matrix_keypad_build_keymap(pdata->keymap_data, row_shift, input_dev->keycode, input_dev->keybit); - omap4_keypad_config(keypad_data); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + omap4_keypad_config(keypad_data); + error = request_irq(keypad_data->irq, omap4_keypad_interrupt, IRQF_TRIGGER_RISING, "omap4-keypad", keypad_data); @@ -278,6 +282,10 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev) struct resource *res; free_irq(keypad_data->irq, keypad_data); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + input_unregister_device(keypad_data->input); iounmap(keypad_data->base); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] omap: 4430sdp board support for the the GPIO keys
omap 4430sdp board support for the GPIO keys. The proximity sensor is connected to GPIO and is registered as a GPIO key. - Making the default state of the sensor off at bootup - The init is called before platform_add_devices Signed-off-by: Shubhrajyoti D --- arch/arm/mach-omap2/board-4430sdp.c | 61 +++ 1 files changed, 61 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9447644..f31d68e 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON48 #define ETH_KS8851_QUART 138 +#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 +#define OMAP4_SFH7741_ENABLE_GPIO 188 static struct gpio_led sdp4430_gpio_leds[] = { { @@ -77,11 +80,47 @@ static struct gpio_led sdp4430_gpio_leds[] = { }; +static struct gpio_keys_button sdp4430_gpio_keys[] = { + { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO, + .active_low = 0, + } +}; + static struct gpio_led_platform_data sdp4430_led_data = { .leds = sdp4430_gpio_leds, .num_leds = ARRAY_SIZE(sdp4430_gpio_leds), }; +static int omap_prox_activate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1); + return 0; +} + +static void omap_prox_deactivate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0); +} + +static struct gpio_keys_platform_data sdp4430_gpio_keys_data = { + .buttons= sdp4430_gpio_keys, + .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys), + .enable = omap_prox_activate, + .disable= omap_prox_deactivate, +}; + +static struct platform_device sdp4430_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev= { + .platform_data = &sdp4430_gpio_keys_data, + }, +}; + static struct platform_device sdp4430_leds_gpio = { .name = "leds-gpio", .id = -1, @@ -161,6 +200,7 @@ static struct platform_device sdp4430_lcd_device = { static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, + &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, }; @@ -426,11 +466,32 @@ static int __init omap4_i2c_init(void) omap_register_i2c_bus(4, 400, NULL, 0); return 0; } + +static void __init omap_sfh7741prox_init(void) +{ + int error; + + error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741"); + if (error < 0) { + pr_err("%s:failed to request GPIO %d, error %d\n", + __func__, OMAP4_SFH7741_ENABLE_GPIO, error); + return; + } + + error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 0); + if (error < 0) { + pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n", +__func__, OMAP4_SFH7741_ENABLE_GPIO, error); + gpio_free(OMAP4_SFH7741_ENABLE_GPIO); + } +} + static void __init omap_4430sdp_init(void) { int status; omap4_i2c_init(); + omap_sfh7741prox_init(); platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices)); omap_serial_init(); omap4_twl6030_hsmmc_init(mmc); -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] omap: 4430sdp board support for proximity sensor
omap 4430sdp board support for the proximity sensor via GPIO keys. The proximity sensor is connected to GPIO and is registered as a GPIO key. - Making the default state of the sensor off at bootup - The init is called before platform_add_devices Signed-off-by: Shubhrajyoti D --- arch/arm/mach-omap2/board-4430sdp.c | 61 +++ 1 files changed, 61 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9447644..f31d68e 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON48 #define ETH_KS8851_QUART 138 +#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 +#define OMAP4_SFH7741_ENABLE_GPIO 188 static struct gpio_led sdp4430_gpio_leds[] = { { @@ -77,11 +80,47 @@ static struct gpio_led sdp4430_gpio_leds[] = { }; +static struct gpio_keys_button sdp4430_gpio_keys[] = { + { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO, + .active_low = 0, + } +}; + static struct gpio_led_platform_data sdp4430_led_data = { .leds = sdp4430_gpio_leds, .num_leds = ARRAY_SIZE(sdp4430_gpio_leds), }; +static int omap_prox_activate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1); + return 0; +} + +static void omap_prox_deactivate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0); +} + +static struct gpio_keys_platform_data sdp4430_gpio_keys_data = { + .buttons= sdp4430_gpio_keys, + .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys), + .enable = omap_prox_activate, + .disable= omap_prox_deactivate, +}; + +static struct platform_device sdp4430_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev= { + .platform_data = &sdp4430_gpio_keys_data, + }, +}; + static struct platform_device sdp4430_leds_gpio = { .name = "leds-gpio", .id = -1, @@ -161,6 +200,7 @@ static struct platform_device sdp4430_lcd_device = { static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, + &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, }; @@ -426,11 +466,32 @@ static int __init omap4_i2c_init(void) omap_register_i2c_bus(4, 400, NULL, 0); return 0; } + +static void __init omap_sfh7741prox_init(void) +{ + int error; + + error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741"); + if (error < 0) { + pr_err("%s:failed to request GPIO %d, error %d\n", + __func__, OMAP4_SFH7741_ENABLE_GPIO, error); + return; + } + + error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 0); + if (error < 0) { + pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n", +__func__, OMAP4_SFH7741_ENABLE_GPIO, error); + gpio_free(OMAP4_SFH7741_ENABLE_GPIO); + } +} + static void __init omap_4430sdp_init(void) { int status; omap4_i2c_init(); + omap_sfh7741prox_init(); platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices)); omap_serial_init(); omap4_twl6030_hsmmc_init(mmc); -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] [RFC] Remove the debug print noise
This patch intends to make the i2cdetect more readable. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7674efb..3a97d2c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -626,7 +626,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (r < 0) return r; if (r == 0) { - dev_err(dev->dev, "controller timed out\n"); + dev_dbg(dev->dev, "controller timed out\n"); omap_i2c_init(dev); return -ETIMEDOUT; } -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH] hmc5843: Digital compass board file
The board file changes for the digital compass hmc5843. The interface to the device is i2c. Signed-off-by: Shubhrajyoti D --- arch/arm/mach-omap2/board-4430sdp.c |8 +++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9447644..5b6a48d 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -412,6 +412,11 @@ static struct i2c_board_info __initdata sdp4430_i2c_3_boardinfo[] = { I2C_BOARD_INFO("tmp105", 0x48), }, }; +static struct i2c_board_info __initdata sdp4430_i2c_4_boardinfo[] = { + { + I2C_BOARD_INFO("hmc5843", 0x1e), + }, +}; static int __init omap4_i2c_init(void) { /* @@ -423,7 +428,8 @@ static int __init omap4_i2c_init(void) omap_register_i2c_bus(2, 400, NULL, 0); omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo, ARRAY_SIZE(sdp4430_i2c_3_boardinfo)); - omap_register_i2c_bus(4, 400, NULL, 0); + omap_register_i2c_bus(4, 400, sdp4430_i2c_4_boardinfo, + ARRAY_SIZE(sdp4430_i2c_4_boardinfo)); return 0; } static void __init omap_4430sdp_init(void) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH] Board support for the the GPIO keys
Board support for the GPIO keys. The proximity sensor is connected to GPIO and is registered as a GPIO key. Signed-off-by: Shubhrajyoti D --- arch/arm/mach-omap2/board-4430sdp.c | 56 +++ 1 files changed, 56 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9447644..7f619bf 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,10 @@ #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON48 #define ETH_KS8851_QUART 138 +#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 +#define OMAP4_SFH7741_ENABLE_GPIO 188 +static int omap_prox_activate(struct device *dev); +static void omap_prox_deactivate(struct device *dev); static struct gpio_led sdp4430_gpio_leds[] = { { @@ -76,11 +81,33 @@ static struct gpio_led sdp4430_gpio_leds[] = { }, }; +static struct gpio_keys_button sdp4430_gpio_keys[] = { + { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO, + .active_low = 0, + } +}; static struct gpio_led_platform_data sdp4430_led_data = { .leds = sdp4430_gpio_leds, .num_leds = ARRAY_SIZE(sdp4430_gpio_leds), }; +static struct gpio_keys_platform_data sdp4430_gpio_keys_data = { + .buttons= sdp4430_gpio_keys, + .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys), + .enable = omap_prox_activate, + .disable= omap_prox_deactivate, +}; +static struct platform_device sdp4430_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev= { + .platform_data = &sdp4430_gpio_keys_data, + }, +}; static struct platform_device sdp4430_leds_gpio = { .name = "leds-gpio", @@ -161,6 +188,7 @@ static struct platform_device sdp4430_lcd_device = { static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, + &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, }; @@ -426,6 +454,33 @@ static int __init omap4_i2c_init(void) omap_register_i2c_bus(4, 400, NULL, 0); return 0; } +static int omap_prox_activate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1); + return 0; +} +static void omap_prox_deactivate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0); +} +static void omap_sfh7741prox_init(void) +{ + int error; + + error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741"); + if (error < 0) { + pr_err("failed to request GPIO %d, error %d\n", + OMAP4_SFH7741_ENABLE_GPIO, error); + return; + } + + error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 1); + if (error < 0) { + pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n",\ +__func__, OMAP4_SFH7741_ENABLE_GPIO, error); + gpio_free(OMAP4_SFH7741_ENABLE_GPIO); + } +} static void __init omap_4430sdp_init(void) { int status; @@ -448,6 +503,7 @@ static void __init omap_4430sdp_init(void) spi_register_board_info(sdp4430_spi_board_info, ARRAY_SIZE(sdp4430_spi_board_info)); } + omap_sfh7741prox_init(); } static void __init omap_4430sdp_map_io(void) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] Board changes for gpio-keys
Signed-off-by: Shubhrajyoti D --- arch/arm/mach-omap2/board-4430sdp.c | 64 +++ 1 files changed, 64 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9447644..699620d 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,11 @@ #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON48 #define ETH_KS8851_QUART 138 +#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 +#define OMAP4_SFH7741_ENABLE_GPIO 188 + +static int omap_prox_activate(struct device *dev); +static void omap_prox_deactivate(struct device *dev); static struct gpio_led sdp4430_gpio_leds[] = { { @@ -77,11 +83,36 @@ static struct gpio_led sdp4430_gpio_leds[] = { }; +static struct gpio_keys_button sdp4430_gpio_keys[] = { + { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO, + .active_low = 0, + } +}; + static struct gpio_led_platform_data sdp4430_led_data = { .leds = sdp4430_gpio_leds, .num_leds = ARRAY_SIZE(sdp4430_gpio_leds), }; +static struct gpio_keys_platform_data sdp4430_gpio_keys_data = { + .buttons= sdp4430_gpio_keys, + .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys), + .enable = omap_prox_activate, + .disable= omap_prox_deactivate, +}; + +static struct platform_device sdp4430_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev= { + .platform_data = &sdp4430_gpio_keys_data, + }, +}; + static struct platform_device sdp4430_leds_gpio = { .name = "leds-gpio", .id = -1, @@ -161,6 +192,7 @@ static struct platform_device sdp4430_lcd_device = { static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, + &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, }; @@ -426,6 +458,37 @@ static int __init omap4_i2c_init(void) omap_register_i2c_bus(4, 400, NULL, 0); return 0; } + +static int omap_prox_activate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1); + return 0; +} + +static void omap_prox_deactivate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0); +} + +static void omap_sfh7741prox_init(void) +{ + int error; + + error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741"); + if (error < 0) { + pr_err("failed to request GPIO %d, error %d\n", + OMAP4_SFH7741_ENABLE_GPIO, error); + return; + } + + error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 1); + if (error < 0) { + pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n", +__func__, OMAP4_SFH7741_ENABLE_GPIO, error); + gpio_free(OMAP4_SFH7741_ENABLE_GPIO); + } +} + static void __init omap_4430sdp_init(void) { int status; @@ -448,6 +511,7 @@ static void __init omap_4430sdp_init(void) spi_register_board_info(sdp4430_spi_board_info, ARRAY_SIZE(sdp4430_spi_board_info)); } + omap_sfh7741prox_init(); } static void __init omap_4430sdp_map_io(void) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] omap: 4430sdp board support for the the GPIO keys
omap 4430sdp board support for the GPIO keys. The proximity sensor is connected to GPIO and is registered as a GPIO key. Signed-off-by: Shubhrajyoti D --- arch/arm/mach-omap2/board-4430sdp.c | 64 +++ 1 files changed, 64 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9447644..699620d 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,11 @@ #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON48 #define ETH_KS8851_QUART 138 +#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 +#define OMAP4_SFH7741_ENABLE_GPIO 188 + +static int omap_prox_activate(struct device *dev); +static void omap_prox_deactivate(struct device *dev); static struct gpio_led sdp4430_gpio_leds[] = { { @@ -77,11 +83,36 @@ static struct gpio_led sdp4430_gpio_leds[] = { }; +static struct gpio_keys_button sdp4430_gpio_keys[] = { + { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO, + .active_low = 0, + } +}; + static struct gpio_led_platform_data sdp4430_led_data = { .leds = sdp4430_gpio_leds, .num_leds = ARRAY_SIZE(sdp4430_gpio_leds), }; +static struct gpio_keys_platform_data sdp4430_gpio_keys_data = { + .buttons= sdp4430_gpio_keys, + .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys), + .enable = omap_prox_activate, + .disable= omap_prox_deactivate, +}; + +static struct platform_device sdp4430_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev= { + .platform_data = &sdp4430_gpio_keys_data, + }, +}; + static struct platform_device sdp4430_leds_gpio = { .name = "leds-gpio", .id = -1, @@ -161,6 +192,7 @@ static struct platform_device sdp4430_lcd_device = { static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, + &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, }; @@ -426,6 +458,37 @@ static int __init omap4_i2c_init(void) omap_register_i2c_bus(4, 400, NULL, 0); return 0; } + +static int omap_prox_activate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1); + return 0; +} + +static void omap_prox_deactivate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0); +} + +static void omap_sfh7741prox_init(void) +{ + int error; + + error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741"); + if (error < 0) { + pr_err("failed to request GPIO %d, error %d\n", + OMAP4_SFH7741_ENABLE_GPIO, error); + return; + } + + error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 1); + if (error < 0) { + pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n", +__func__, OMAP4_SFH7741_ENABLE_GPIO, error); + gpio_free(OMAP4_SFH7741_ENABLE_GPIO); + } +} + static void __init omap_4430sdp_init(void) { int status; @@ -448,6 +511,7 @@ static void __init omap_4430sdp_init(void) spi_register_board_info(sdp4430_spi_board_info, ARRAY_SIZE(sdp4430_spi_board_info)); } + omap_sfh7741prox_init(); } static void __init omap_4430sdp_map_io(void) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] omap: 4430sdp board support for the the GPIO keys
omap 4430sdp board support for the GPIO keys. The proximity sensor is connected to GPIO and is registered as a GPIO key. Signed-off-by: Shubhrajyoti D --- arch/arm/mach-omap2/board-4430sdp.c | 64 +++ 1 files changed, 64 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9447644..699620d 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,11 @@ #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON48 #define ETH_KS8851_QUART 138 +#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 +#define OMAP4_SFH7741_ENABLE_GPIO 188 + +static int omap_prox_activate(struct device *dev); +static void omap_prox_deactivate(struct device *dev); static struct gpio_led sdp4430_gpio_leds[] = { { @@ -77,11 +83,36 @@ static struct gpio_led sdp4430_gpio_leds[] = { }; +static struct gpio_keys_button sdp4430_gpio_keys[] = { + { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO, + .active_low = 0, + } +}; + static struct gpio_led_platform_data sdp4430_led_data = { .leds = sdp4430_gpio_leds, .num_leds = ARRAY_SIZE(sdp4430_gpio_leds), }; +static struct gpio_keys_platform_data sdp4430_gpio_keys_data = { + .buttons= sdp4430_gpio_keys, + .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys), + .enable = omap_prox_activate, + .disable= omap_prox_deactivate, +}; + +static struct platform_device sdp4430_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev= { + .platform_data = &sdp4430_gpio_keys_data, + }, +}; + static struct platform_device sdp4430_leds_gpio = { .name = "leds-gpio", .id = -1, @@ -161,6 +192,7 @@ static struct platform_device sdp4430_lcd_device = { static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, + &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, }; @@ -426,6 +458,37 @@ static int __init omap4_i2c_init(void) omap_register_i2c_bus(4, 400, NULL, 0); return 0; } + +static int omap_prox_activate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1); + return 0; +} + +static void omap_prox_deactivate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0); +} + +static void omap_sfh7741prox_init(void) +{ + int error; + + error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741"); + if (error < 0) { + pr_err("failed to request GPIO %d, error %d\n", + OMAP4_SFH7741_ENABLE_GPIO, error); + return; + } + + error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 1); + if (error < 0) { + pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n", +__func__, OMAP4_SFH7741_ENABLE_GPIO, error); + gpio_free(OMAP4_SFH7741_ENABLE_GPIO); + } +} + static void __init omap_4430sdp_init(void) { int status; @@ -448,6 +511,7 @@ static void __init omap_4430sdp_init(void) spi_register_board_info(sdp4430_spi_board_info, ARRAY_SIZE(sdp4430_spi_board_info)); } + omap_sfh7741prox_init(); } static void __init omap_4430sdp_map_io(void) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] omap: 4430sdp board support for the the GPIO keys
omap 4430sdp board support for the GPIO keys. The proximity sensor is connected to GPIO and is registered as a GPIO key. - Making the default state of the sensor off at bootup Signed-off-by: Shubhrajyoti D --- arch/arm/mach-omap2/board-4430sdp.c | 61 +++ 1 files changed, 61 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9447644..85b0e0c 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,8 @@ #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON48 #define ETH_KS8851_QUART 138 +#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 +#define OMAP4_SFH7741_ENABLE_GPIO 188 static struct gpio_led sdp4430_gpio_leds[] = { { @@ -77,11 +80,47 @@ static struct gpio_led sdp4430_gpio_leds[] = { }; +static struct gpio_keys_button sdp4430_gpio_keys[] = { + { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO, + .active_low = 0, + } +}; + static struct gpio_led_platform_data sdp4430_led_data = { .leds = sdp4430_gpio_leds, .num_leds = ARRAY_SIZE(sdp4430_gpio_leds), }; +static int omap_prox_activate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1); + return 0; +} + +static void omap_prox_deactivate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0); +} + +static struct gpio_keys_platform_data sdp4430_gpio_keys_data = { + .buttons= sdp4430_gpio_keys, + .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys), + .enable = omap_prox_activate, + .disable= omap_prox_deactivate, +}; + +static struct platform_device sdp4430_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev= { + .platform_data = &sdp4430_gpio_keys_data, + }, +}; + static struct platform_device sdp4430_leds_gpio = { .name = "leds-gpio", .id = -1, @@ -161,6 +200,7 @@ static struct platform_device sdp4430_lcd_device = { static struct platform_device *sdp4430_devices[] __initdata = { &sdp4430_lcd_device, + &sdp4430_gpio_keys_device, &sdp4430_leds_gpio, }; @@ -426,6 +466,26 @@ static int __init omap4_i2c_init(void) omap_register_i2c_bus(4, 400, NULL, 0); return 0; } + +static void __init omap_sfh7741prox_init(void) +{ + int error; + + error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741"); + if (error < 0) { + pr_err("%s:failed to request GPIO %d, error %d\n", + __func__, OMAP4_SFH7741_ENABLE_GPIO, error); + return; + } + + error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 0); + if (error < 0) { + pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n", +__func__, OMAP4_SFH7741_ENABLE_GPIO, error); + gpio_free(OMAP4_SFH7741_ENABLE_GPIO); + } +} + static void __init omap_4430sdp_init(void) { int status; @@ -448,6 +508,7 @@ static void __init omap_4430sdp_init(void) spi_register_board_info(sdp4430_spi_board_info, ARRAY_SIZE(sdp4430_spi_board_info)); } + omap_sfh7741prox_init(); } static void __init omap_4430sdp_map_io(void) -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 03/13] I2C: OMAP: Remove reset at init
The reset in the driver at init is not needed anymore as the following patch has removed the HWMOD_INIT_NO_RESET flag. 6d3c55f [OMAP: hwmod: fix the i2c-reset timeout during bootup] This patch does the following -removes the reset from the probe and implements a omap_i2c_reset function to reset. - Reset is removed from omap_i2c_init, which was called not only during probe, but also after time out and error handling. omap_i2c_reset is added in those places to effect the reset. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 38 +++--- 1 files changed, 23 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 838a0ae..5da91b5 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -269,15 +269,9 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) (i2c_dev->regs[reg] << i2c_dev->reg_shift)); } -static int omap_i2c_init(struct omap_i2c_dev *dev) +static int omap_i2c_reset(struct omap_i2c_dev *dev) { - u16 psc = 0, scll = 0, sclh = 0, buf = 0; - u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; - unsigned long fclk_rate = 1200; unsigned long timeout; - unsigned long internal_clk = 0; - struct clk *fclk; - if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { /* Disable I2C controller before soft reset */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, @@ -315,16 +309,18 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate); - /* -* Enabling all wakup sources to stop I2C freezing on -* WFI instruction. -* REVISIT: Some wkup sources might not be needed. -*/ - dev->westate = OMAP_I2C_WE_ALL; - omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, - dev->westate); } } +} + +static int omap_i2c_init(struct omap_i2c_dev *dev) +{ + u16 psc = 0, scll = 0, sclh = 0, buf = 0; + u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; + unsigned long fclk_rate = 1200; + unsigned long internal_clk = 0; + struct clk *fclk; + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { @@ -433,6 +429,16 @@ 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 (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { + /* +* Enabling all wakup sources to stop I2C freezing on +* WFI instruction. +* REVISIT: Some wkup sources might not be needed. +*/ + dev->westate = OMAP_I2C_WE_ALL; + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); + } + if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { dev->pscstate = psc; dev->scllstate = scll; @@ -541,6 +547,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, dev->buf_len = 0; if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); + omap_i2c_reset(dev); omap_i2c_init(dev); return -ETIMEDOUT; } @@ -551,6 +558,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, /* We have an error */ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) { + omap_i2c_reset(dev); omap_i2c_init(dev); return -EIO; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 04/13] I2C: OMAP: Recover from Bus Busy condition
From: Vikram Pandita In case a peripheral is driving SDA bus low (ie. a start condition), provide a constant clock output using the test mode of the OMAP I2C controller to try and clear the bus. Soft reset I2C controller after attempting the bus clear to ensure that controller is in a good state. Based upon Vikram Pandita's patch from TI Android 3.0. I acknowledge the contributions and suggestions of Jon and Hemant. A couple differences from the original patch ... 1. Add a new function for bus clear 2. Ensure that the CON.I2C_EN bit is set when using the SYSTEST feature to output a permanent clock. This bit needs to be set and typically it would be set by the unidle function but this is not the case for all OMAP generations. 3. Program the SYSTEST setting only the bits we care about. However, restore SYSTEST registers to there original state as some OMAP generations do not implement perform a soft-reset. 4. Clear the CON register after performing the bus clear, so when we call the init function the controller is disabled and the init function will re-enable later. Original patch can be found here: http://git.omapzoom.org/?p=kernel/omap.git;a=commit;h=a2ab04192ba25e60f95ba1ff3af5601a2d7b5bd1 Signed-off-by: Vikram Pandita Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 33 ++--- 1 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 5da91b5..7ab9fe1 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -148,16 +148,15 @@ enum { #define OMAP_I2C_SCLH_HSSCLH 8 /* I2C System Test Register (OMAP_I2C_SYSTEST): */ -#ifdef DEBUG #define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ #define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */ #define OMAP_I2C_SYSTEST_TMODE_MASK(3 << 12) /* Test mode select */ -#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12)/* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_TEST(2 << 12) /* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_LOOP(3 << 12) /* Test mode select */ #define OMAP_I2C_SYSTEST_SCL_I (1 << 3)/* SCL line sense in */ #define OMAP_I2C_SYSTEST_SCL_O (1 << 2)/* SCL line drive out */ #define OMAP_I2C_SYSTEST_SDA_I (1 << 1)/* SDA line sense in */ #define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ -#endif /* OCP_SYSCONFIG bit definitions */ #define SYSC_CLOCKACTIVITY_MASK(0x3 << 8) @@ -311,6 +310,7 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev) dev->syscstate); } } + return 0; } static int omap_i2c_init(struct omap_i2c_dev *dev) @@ -468,6 +468,31 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) } /* + * Bus Clear + */ +static int omap_i2c_bus_clear(struct omap_i2c_dev *dev) +{ + u16 w; + + /* +* Per the I2C specification, if we are stuck in a bus busy state +* we can attempt a bus clear to try and recover the bus by sending +* at least 9 clock pulses on SCL. Put the I2C in a test mode so it +* will output a continuous clock on SCL. +*/ + w = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, (OMAP_I2C_SYSTEST_ST_EN + | OMAP_I2C_SYSTEST_TMODE_TEST)); + msleep(1); + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, w); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + omap_i2c_reset(dev); + omap_i2c_init(dev); + return omap_i2c_wait_for_bb(dev); +} + +/* * Low level master read/write transaction. */ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, @@ -594,6 +619,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) r = omap_i2c_wait_for_bb(dev); if (r < 0) + r = omap_i2c_bus_clear(dev); + if (r < 0) goto out; if (dev->set_mpu_wkup_lat != NULL) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 02/13] I2C: OMAP: Remove the definition of SYSS_RESETDONE_MASK
Remove the definition of SYSS_RESETDONE_MASK and use the one in omap_hwmod.h. Also fixes the warning CC drivers/i2c/busses/i2c-omap.o drivers/i2c/busses/i2c-omap.c:163: warning: "SYSS_RESETDONE_MASK" redefined Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9a54e88..838a0ae 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -159,9 +159,6 @@ enum { #define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ #endif -/* 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) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 07/13] I2C: OMAP: use devm_* functions
The various devm_* functions allocate memory that is released when a driver detaches. This patch uses devm_kzalloc, devm_request_and_ioremap for data that is allocated in the probe function of a platform device and is only freed in the remove function. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 33 + 1 files changed, 9 insertions(+), 24 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 5c3a299..326b99c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -975,7 +975,7 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq, *ioarea; + struct resource *mem, *irq; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; @@ -994,17 +994,16 @@ omap_i2c_probe(struct platform_device *pdev) return -ENODEV; } - ioarea = request_mem_region(mem->start, resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; + dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "Menory allocation failed\n"); + return -ENOMEM; } - dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - r = -ENOMEM; - goto err_release_region; + dev->base = devm_request_and_ioremap(&pdev->dev, mem); + if (!dev->base) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -ENOMEM; } match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); @@ -1028,11 +1027,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->irq = irq->start; - dev->base = ioremap(mem->start, resource_size(mem)); - if (!dev->base) { - r = -ENOMEM; - goto err_free_mem; - } platform_set_drvdata(pdev, dev); @@ -1127,13 +1121,9 @@ err_free_irq: err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(dev->dev); - iounmap(dev->base); pm_runtime_disable(&pdev->dev); err_free_mem: platform_set_drvdata(pdev, NULL); - kfree(dev); -err_release_region: - release_mem_region(mem->start, resource_size(mem)); return r; } @@ -1141,7 +1131,6 @@ err_release_region: static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); - struct resource *mem; int ret; platform_set_drvdata(pdev, NULL); @@ -1155,10 +1144,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - iounmap(dev->base); - kfree(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); return 0; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 12/13] I2C: OMAP: add blank lines
From: Felipe Balbi trivial patch to aid readability. No functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |5 + 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0e0ab8f..6a79089 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -818,6 +818,7 @@ complete: dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; } + /* * ProDB0017052: Clear ARDY bit twice */ @@ -830,6 +831,7 @@ complete: omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } + if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { u8 num_bytes = 1; @@ -876,6 +878,7 @@ complete: stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); continue; } + if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { u8 num_bytes = 1; if (dev->fifo_size) { @@ -923,10 +926,12 @@ complete: stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); continue; } + if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); dev->cmd_err |= OMAP_I2C_STAT_ROVR; } + if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); dev->cmd_err |= OMAP_I2C_STAT_XUDF; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 00/13] I2C cleanups
The patch series does the following - I2C register restore only if context if the context is lost - Bus busy recovery mechanism. - the reset is not done in init. - Adds a patch to use devm_* functions - Adds a pdata function pointer to do context save restore - Split the omap_i2c_isr to increase readability - Make the i2c use SET_RUNTIME_PM_OPS - Use INIT_COMPLETION instead of init_completion - Dropping a cleanup and taking few patchs Felipe's series as it may not be needed. This applies on Wolfram's i2c-embedded/for-next branch. Functional testing on omap4sdp and omap3sdp. Previous discurssions http://www.spinics.net/lists/linux-i2c/msg07748.html This series mainly is the cleanups rebased on i2c-embedded/for-next branch. The following changes since commit 0f009a914b40be8786fa67b1f4345cacc263b48c: i2c: tegra: make all resource allocation through devm_* (2012-06-13 16:01:38 +0200) are available in the git repository at: git://gitorious.org/linus-tree/linus-tree.git for_next/i2c_omap Felipe Balbi (4): I2C: OMAP: simplify num_bytes handling I2C: OMAP: decrease indentation level on data handling I2C: OMAP: add blank lines I2C: OMAP: simplify omap_i2c_ack_stat() Jon Hunter (1): I2C: OMAP: Correct I2C revision for OMAP3 Shubhrajyoti D (7): I2C: OMAP: I2C register restore only if context is lost I2C: OMAP: Remove the definition of SYSS_RESETDONE_MASK I2C: OMAP: Remove reset at init I2C: OMAP: Optimise the remove code I2C: OMAP: use devm_* functions I2C: OMAP: Use SET_RUNTIME_PM_OPS I2C: OMAP: Do not initialise the completion everytime Vikram Pandita (1): I2C: OMAP: Recover from Bus Busy condition arch/arm/plat-omap/i2c.c |3 + drivers/i2c/busses/i2c-omap.c | 261 +++- include/linux/i2c-omap.h |1 + 3 files changed, 154 insertions(+), 111 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 01/13] I2C: OMAP: I2C register restore only if context is lost
Currently i2c register restore is done always. Adding conditional restore. The i2c register restore is done only if the context is lost or in case of error to be on the safe side. Cc: Kevin Hilman Signed-off-by: Shubhrajyoti D --- arch/arm/plat-omap/i2c.c |3 +++ drivers/i2c/busses/i2c-omap.c | 35 ++- include/linux/i2c-omap.h |1 + 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index db071bc..4ccab07 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -179,6 +179,9 @@ static inline int omap2_i2c_add_bus(int bus_id) */ if (cpu_is_omap34xx()) pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; + + pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; + pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9895fa7..9a54e88 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@ #include #include #include +#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -185,6 +186,7 @@ struct omap_i2c_dev { u32 latency;/* maximum mpu wkup latency */ void(*set_mpu_wkup_lat)(struct device *dev, long latency); + int (*get_context_loss_count)(struct device *dev); u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -207,6 +209,7 @@ struct omap_i2c_dev { u16 syscstate; u16 westate; u16 errata; + int dev_lost_count; }; static const u8 reg_map_ip_v1[] = { @@ -987,6 +990,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->speed = pdata->clkrate; dev->flags = pdata->flags; dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; + dev->get_context_loss_count = pdata->get_context_loss_count; dev->dtrev = pdata->rev; } @@ -1128,12 +1132,26 @@ omap_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_RUNTIME +static void omap_i2c_restore(struct omap_i2c_dev *dev) +{ + 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); + omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate); + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate); + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + +} static int omap_i2c_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); u16 iv; + if (_dev->get_context_loss_count) + _dev->dev_lost_count = _dev->get_context_loss_count(dev); + _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); @@ -1154,16 +1172,15 @@ static int omap_i2c_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); + int loss_cnt; + + if (!(_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE)) + return 0; - if (_dev->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); - omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate); - omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate); - omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate); - omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + if (_dev->get_context_loss_count) { + loss_cnt = _dev->get_context_loss_count(dev); + if (_dev->dev_lost_count != loss_cnt) + omap_i2c_restore(_dev); } /* diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 92a0dc7..c76cbc0 100644 --- a/include/linux/i2c
[PATCHv8 06/13] I2C: OMAP: Correct I2C revision for OMAP3
From: Jon Hunter The OMAP3530 is based upon the same silicon as the OMAP3430 and so the I2C revision is the same for 3430 and 3530. However, the OMAP3630 device has the same I2C revision as OMAP4. Correct the revision definition to reflect this. This patch is based on work done by Jon Hunter Changes from his patch - Update OMAP_I2C_REV_ON_3430 also to reflect that it is same as 3530 Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 10 +- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 691550a..5c3a299 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -50,8 +50,8 @@ /* 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_3530_4430 0x40 +#define OMAP_I2C_REV_ON_3430_3530 0x3C +#define OMAP_I2C_REV_ON_3630_4430 0x40 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -298,7 +298,7 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_AUTOIDLE_MASK); - } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { + } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { dev->syscstate = SYSC_AUTOIDLE_MASK; dev->syscstate |= SYSC_ENAWAKEUP_MASK; dev->syscstate |= (SYSC_IDLEMODE_SMART << @@ -1055,7 +1055,7 @@ omap_i2c_probe(struct platform_device *pdev) if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) dev->errata |= I2C_OMAP_ERRATA_I207; - if (dev->rev <= OMAP_I2C_REV_ON_3430) + if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) dev->errata |= I2C_OMAP_ERRATA_I462; if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { @@ -1073,7 +1073,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) + if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 0; /* Disable hardware fixes */ else dev->b_hw = 1; /* Enable hardware fixes */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 13/13] I2C: OMAP: simplify omap_i2c_ack_stat()
From: Felipe Balbi stat & BIT(1) is the same as BIT(1), so let's simplify things a bit by removing "stat &" from all omap_i2c_ack_stat() calls. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 19 ++- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6a79089..bac6305 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -763,7 +763,7 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); return -ETIMEDOUT; } @@ -824,10 +824,11 @@ complete: */ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, stat & - (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | - OMAP_I2C_STAT_ARDY)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR | + OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR | + OMAP_I2C_STAT_ARDY)); omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } @@ -874,8 +875,8 @@ complete: } } } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR)); continue; } @@ -922,8 +923,8 @@ complete: omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR)); continue; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 11/13] I2C: OMAP: decrease indentation level on data handling
From: Felipe Balbi trivial patch, no functional changes. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 63 - 1 files changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 080193a..0e0ab8f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -845,22 +845,7 @@ complete: >> 8) & 0x3F; } while (num_bytes--) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - if (dev->buf_len) { - *dev->buf++ = w; - dev->buf_len--; - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & -OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } else { + if (!dev->buf_len) { if (stat & OMAP_I2C_STAT_RRDY) dev_err(dev->dev, "RRDY IRQ while no data" @@ -871,6 +856,21 @@ complete: " requested\n"); break; } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } } omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); @@ -887,22 +887,7 @@ complete: & 0x3F; } while (num_bytes--) { - w = 0; - if (dev->buf_len) { - w = *dev->buf++; - dev->buf_len--; - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & -OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; - } - } - } else { + if (!dev->buf_len) { if (stat & OMAP_I2C_STAT_XRDY) dev_err(dev->dev, "XRDY IRQ while no " @@ -914,6 +899,20 @@ complete: break; } + w = *dev->buf++; + dev->buf_len--; + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & +
[PATCHv8 08/13] I2C: OMAP: Use SET_RUNTIME_PM_OPS
Use SET_RUNTIME_PM_OPS macro to set runtime functions. Acked-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |8 +--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 326b99c..6f8e7d9 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1147,6 +1147,7 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM #ifdef CONFIG_PM_RUNTIME static void omap_i2c_restore(struct omap_i2c_dev *dev) { @@ -1208,15 +1209,16 @@ static int omap_i2c_runtime_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_RUNTIME */ static struct dev_pm_ops omap_i2c_pm_ops = { - .runtime_suspend = omap_i2c_runtime_suspend, - .runtime_resume = omap_i2c_runtime_resume, + SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) #else #define OMAP_I2C_PM_OPS NULL -#endif +#endif /* CONFIG_PM */ static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 10/13] I2C: OMAP: simplify num_bytes handling
From: Felipe Balbi trivial patch, no functional changes Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |6 ++ 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index e24eb1f..080193a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -844,8 +844,7 @@ complete: OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); if (dev->buf_len) { *dev->buf++ = w; @@ -887,8 +886,7 @@ complete: OMAP_I2C_BUFSTAT_REG) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = 0; if (dev->buf_len) { w = *dev->buf++; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 05/13] I2C: OMAP: Optimise the remove code
The omap_i2c_remove function may not be needed after device exit so the memory could be freed. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7ab9fe1..691550a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1138,8 +1138,7 @@ err_release_region: return r; } -static int -omap_i2c_remove(struct platform_device *pdev) +static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; @@ -1236,7 +1235,7 @@ static struct dev_pm_ops omap_i2c_pm_ops = { static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, - .remove = omap_i2c_remove, + .remove = __devexit_p(omap_i2c_remove), .driver = { .name = "omap_i2c", .owner = THIS_MODULE, -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv8 09/13] I2C: OMAP: Do not initialise the completion everytime
Use INIT_COMPLETION instead of init_completion in transfer. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6f8e7d9..e24eb1f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -521,7 +521,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); - init_completion(&dev->cmd_complete); + INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -1029,6 +1029,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->irq = irq->start; platform_set_drvdata(pdev, dev); + init_completion(&dev->cmd_complete); dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 5/8] I2C: OMAP: Do not initialise the completion everytime
Use INIT_COMPLETION instead of init_completion in transfer. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ccb2fc4..2a50094 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -493,7 +493,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); - init_completion(&dev->cmd_complete); + INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -997,6 +997,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->irq = irq->start; platform_set_drvdata(pdev, dev); + init_completion(&dev->cmd_complete); dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 6/8] I2C: OMAP: Remove the definition of SYSS_RESETDONE_MASK
Remove the definition of SYSS_RESETDONE_MASK and use the one in omap_hwmod.h. Also fixes the warning CC drivers/i2c/busses/i2c-omap.o drivers/i2c/busses/i2c-omap.c:163: warning: "SYSS_RESETDONE_MASK" redefined Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2a50094..cbf7ecd 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -159,9 +159,6 @@ enum { #define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ #endif -/* 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) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 4/8] I2C: OMAP: Use SET_RUNTIME_PM_OPS
Use SET_RUNTIME_PM_OPS macro to set runtime functions. Acked-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |8 +--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 328a022..ccb2fc4 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1115,6 +1115,7 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM #ifdef CONFIG_PM_RUNTIME static void omap_i2c_restore(struct omap_i2c_dev *dev) { @@ -1176,15 +1177,16 @@ static int omap_i2c_runtime_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_RUNTIME */ static struct dev_pm_ops omap_i2c_pm_ops = { - .runtime_suspend = omap_i2c_runtime_suspend, - .runtime_resume = omap_i2c_runtime_resume, + SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) #else #define OMAP_I2C_PM_OPS NULL -#endif +#endif /* CONFIG_PM */ static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 7/8] I2C: OMAP: Correct I2C revision for OMAP3
From: Jon Hunter The OMAP3530 is based upon the same silicon as the OMAP3430 and so the I2C revision is the same for 3430 and 3530. However, the OMAP3630 device has the same I2C revision as OMAP4. Correct the revision definition to reflect this. This patch is based on work done by Jon Hunter Changes from his patch - Update OMAP_I2C_REV_ON_3430 also to reflect that it is same as 3530 Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 10 +- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index cbf7ecd..a492d93 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -50,8 +50,8 @@ /* 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_3530_4430 0x40 +#define OMAP_I2C_REV_ON_3430_3530 0x3C +#define OMAP_I2C_REV_ON_3630_4430 0x40 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -305,7 +305,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_AUTOIDLE_MASK); - } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { + } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { dev->syscstate = SYSC_AUTOIDLE_MASK; dev->syscstate |= SYSC_ENAWAKEUP_MASK; dev->syscstate |= (SYSC_IDLEMODE_SMART << @@ -1015,7 +1015,7 @@ omap_i2c_probe(struct platform_device *pdev) if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) dev->errata |= I2C_OMAP_ERRATA_I207; - if (dev->rev <= OMAP_I2C_REV_ON_3430) + if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) dev->errata |= I2C_OMAP_ERRATA_I462; if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { @@ -1033,7 +1033,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) + if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 0; /* Disable hardware fixes */ else dev->b_hw = 1; /* Enable hardware fixes */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 3/8] I2C: OMAP: use devm_* functions
The various devm_* functions allocate memory that is released when a driver detaches. This patch uses devm_kzalloc, devm_request_and_ioremap for data that is allocated in the probe function of a platform device and is only freed in the remove function. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 33 + 1 files changed, 9 insertions(+), 24 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index d704f64..328a022 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -943,7 +943,7 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq, *ioarea; + struct resource *mem, *irq; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; @@ -962,17 +962,16 @@ omap_i2c_probe(struct platform_device *pdev) return -ENODEV; } - ioarea = request_mem_region(mem->start, resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; + dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "Menory allocation failed\n"); + return -ENOMEM; } - dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - r = -ENOMEM; - goto err_release_region; + dev->base = devm_request_and_ioremap(&pdev->dev, mem); + if (!dev->base) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -ENOMEM; } match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); @@ -996,11 +995,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->irq = irq->start; - dev->base = ioremap(mem->start, resource_size(mem)); - if (!dev->base) { - r = -ENOMEM; - goto err_free_mem; - } platform_set_drvdata(pdev, dev); @@ -1095,13 +1089,9 @@ err_free_irq: err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(dev->dev); - iounmap(dev->base); pm_runtime_disable(&pdev->dev); err_free_mem: platform_set_drvdata(pdev, NULL); - kfree(dev); -err_release_region: - release_mem_region(mem->start, resource_size(mem)); return r; } @@ -1109,7 +1099,6 @@ err_release_region: static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); - struct resource *mem; int ret; platform_set_drvdata(pdev, NULL); @@ -1123,10 +1112,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - iounmap(dev->base); - kfree(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); return 0; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 0/8] I2C cleanups
The patch series does the following - I2C register restore only if context if the context is lost - Bus busy recovery mechanism. - Adds a patch to use devm_* functions - Adds a pdata function pointer to do context save restore - Split the omap_i2c_isr to increase readability - Make the i2c use SET_RUNTIME_PM_OPS - Use INIT_COMPLETION instead of init_completion - the reset patch is dropped will try to rework it as per the review comments recieved. This applies on Wolfram's i2c-embedded/for-next branch. Functional testing on omap4430 , 4460 panda and omap3sdp. Previous discurssions http://www.spinics.net/lists/linux-i2c/msg07748.html This series mainly is the cleanups rebased on i2c-embedded/for-next branch. The following changes since commit 0f009a914b40be8786fa67b1f4345cacc263b48c: i2c: tegra: make all resource allocation through devm_* (2012-06-13 16:01:38 +0200) are available in the git repository at: git://gitorious.org/linus-tree/linus-tree.git for_next/i2c_minimal_cleanup Jon Hunter (1): I2C: OMAP: Correct I2C revision for OMAP3 Shubhrajyoti D (6): I2C: OMAP: I2C register restore only if context is lost I2C: OMAP: Optimise the remove code I2C: OMAP: use devm_* functions I2C: OMAP: Use SET_RUNTIME_PM_OPS I2C: OMAP: Do not initialise the completion everytime I2C: OMAP: Remove the definition of SYSS_RESETDONE_MASK Vikram Pandita (1): I2C: OMAP: Recover from Bus Busy condition arch/arm/plat-omap/i2c.c |3 + drivers/i2c/busses/i2c-omap.c | 128 include/linux/i2c-omap.h |1 + 3 files changed, 81 insertions(+), 51 deletions(-) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 1/8] I2C: OMAP: I2C register restore only if context is lost
Currently i2c register restore is done always. Adding conditional restore. The i2c register restore is done only if the context is lost or in case of error to be on the safe side. Cc: Kevin Hilman Signed-off-by: Shubhrajyoti D --- arch/arm/plat-omap/i2c.c |3 +++ drivers/i2c/busses/i2c-omap.c | 35 ++- include/linux/i2c-omap.h |1 + 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index db071bc..4ccab07 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -179,6 +179,9 @@ static inline int omap2_i2c_add_bus(int bus_id) */ if (cpu_is_omap34xx()) pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; + + pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; + pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9895fa7..9a54e88 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@ #include #include #include +#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -185,6 +186,7 @@ struct omap_i2c_dev { u32 latency;/* maximum mpu wkup latency */ void(*set_mpu_wkup_lat)(struct device *dev, long latency); + int (*get_context_loss_count)(struct device *dev); u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -207,6 +209,7 @@ struct omap_i2c_dev { u16 syscstate; u16 westate; u16 errata; + int dev_lost_count; }; static const u8 reg_map_ip_v1[] = { @@ -987,6 +990,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->speed = pdata->clkrate; dev->flags = pdata->flags; dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; + dev->get_context_loss_count = pdata->get_context_loss_count; dev->dtrev = pdata->rev; } @@ -1128,12 +1132,26 @@ omap_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_RUNTIME +static void omap_i2c_restore(struct omap_i2c_dev *dev) +{ + 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); + omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate); + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate); + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + +} static int omap_i2c_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); u16 iv; + if (_dev->get_context_loss_count) + _dev->dev_lost_count = _dev->get_context_loss_count(dev); + _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); @@ -1154,16 +1172,15 @@ static int omap_i2c_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); + int loss_cnt; + + if (!(_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE)) + return 0; - if (_dev->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); - omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate); - omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate); - omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate); - omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + if (_dev->get_context_loss_count) { + loss_cnt = _dev->get_context_loss_count(dev); + if (_dev->dev_lost_count != loss_cnt) + omap_i2c_restore(_dev); } /* diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 92a0dc7..c76cbc0 100644 --- a/include/linux/i2c
[PATCHv9 2/8] I2C: OMAP: Optimise the remove code
The omap_i2c_remove function may not be needed after device exit so the memory could be freed. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9a54e88..d704f64 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1106,8 +1106,7 @@ err_release_region: return r; } -static int -omap_i2c_remove(struct platform_device *pdev) +static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; @@ -1204,7 +1203,7 @@ static struct dev_pm_ops omap_i2c_pm_ops = { static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, - .remove = omap_i2c_remove, + .remove = __devexit_p(omap_i2c_remove), .driver = { .name = "omap_i2c", .owner = THIS_MODULE, -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 8/8] I2C: OMAP: Recover from Bus Busy condition
From: Vikram Pandita In case a peripheral is driving SDA bus low (ie. a start condition), provide a constant clock output using the test mode of the OMAP I2C controller to try and clear the bus. Soft reset I2C controller after attempting the bus clear to ensure that controller is in a good state. Based upon Vikram Pandita's patch from TI Android 3.0. I acknowledge the contributions and suggestions of Jon and Hemant. A couple differences from the original patch ... 1. Add a new function for bus clear 2. Ensure that the CON.I2C_EN bit is set when using the SYSTEST feature to output a permanent clock. This bit needs to be set and typically it would be set by the unidle function but this is not the case for all OMAP generations. 3. Program the SYSTEST setting only the bits we care about. However, restore SYSTEST registers to there original state as some OMAP generations do not implement perform a soft-reset. 4. Clear the CON register after performing the bus clear, so when we call the init function the controller is disabled and the init function will re-enable later. Original patch can be found here: http://git.omapzoom.org/?p=kernel/omap.git;a=commit;h=a2ab04192ba25e60f95ba1ff3af5601a2d7b5bd1 Signed-off-by: Vikram Pandita Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 31 --- 1 files changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index a492d93..23c8e78 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -148,16 +148,15 @@ enum { #define OMAP_I2C_SCLH_HSSCLH 8 /* I2C System Test Register (OMAP_I2C_SYSTEST): */ -#ifdef DEBUG #define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ #define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */ #define OMAP_I2C_SYSTEST_TMODE_MASK(3 << 12) /* Test mode select */ -#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12)/* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_TEST(2 << 12) /* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_LOOP(3 << 12) /* Test mode select */ #define OMAP_I2C_SYSTEST_SCL_I (1 << 3)/* SCL line sense in */ #define OMAP_I2C_SYSTEST_SCL_O (1 << 2)/* SCL line drive out */ #define OMAP_I2C_SYSTEST_SDA_I (1 << 1)/* SDA line sense in */ #define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ -#endif /* OCP_SYSCONFIG bit definitions */ #define SYSC_CLOCKACTIVITY_MASK(0x3 << 8) @@ -460,6 +459,29 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) return 0; } +/* + * Bus Clear + */ +static int omap_i2c_bus_clear(struct omap_i2c_dev *dev) +{ + u16 w; + + /* +* Per the I2C specification, if we are stuck in a bus busy state +* we can attempt a bus clear to try and recover the bus by sending +* at least 9 clock pulses on SCL. Put the I2C in a test mode so it +* will output a continuous clock on SCL. +*/ + w = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, (OMAP_I2C_SYSTEST_ST_EN + | OMAP_I2C_SYSTEST_TMODE_TEST)); + msleep(1); + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, w); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + omap_i2c_init(dev); + return omap_i2c_wait_for_bb(dev); +} /* * Low level master read/write transaction. @@ -586,6 +608,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) r = omap_i2c_wait_for_bb(dev); if (r < 0) + r = omap_i2c_bus_clear(dev); + if (r < 0) goto out; if (dev->set_mpu_wkup_lat != NULL) @@ -654,6 +678,7 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) } } + return 0; } /* rev1 devices are apparently only on some 15xx */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv10 3/7] I2C: OMAP: Use SET_RUNTIME_PM_OPS
Use SET_RUNTIME_PM_OPS macro to set runtime functions. Acked-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |8 +--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index d704f64..c771c28 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1130,6 +1130,7 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM #ifdef CONFIG_PM_RUNTIME static void omap_i2c_restore(struct omap_i2c_dev *dev) { @@ -1191,15 +1192,16 @@ static int omap_i2c_runtime_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_RUNTIME */ static struct dev_pm_ops omap_i2c_pm_ops = { - .runtime_suspend = omap_i2c_runtime_suspend, - .runtime_resume = omap_i2c_runtime_resume, + SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) #else #define OMAP_I2C_PM_OPS NULL -#endif +#endif /* CONFIG_PM */ static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv9 0/7] I2C cleanups
The patch series does the following - I2C register restore only if context if the context is lost - Bus busy recovery mechanism. - Adds a pdata function pointer to do context save restore - Split the omap_i2c_isr to increase readability - Make the i2c use SET_RUNTIME_PM_OPS - Use INIT_COMPLETION instead of init_completion - the reset patch is dropped will try to rework it as per the review comments recieved. This applies on Wolfram's i2c-embedded/for-next branch. Functional testing on omap4430 , 4460 panda and omap3sdp. Previous discurssions http://www.spinics.net/lists/linux-i2c/msg07748.html This series mainly is the cleanups rebased on i2c-embedded/for-next branch. Jon Hunter (1): I2C: OMAP: Correct I2C revision for OMAP3 Shubhrajyoti D (5): I2C: OMAP: I2C register restore only if context is lost I2C: OMAP: Optimise the remove code I2C: OMAP: Use SET_RUNTIME_PM_OPS I2C: OMAP: Do not initialise the completion everytime I2C: OMAP: Remove the definition of SYSS_RESETDONE_MASK Vikram Pandita (1): I2C: OMAP: Recover from Bus Busy condition arch/arm/plat-omap/i2c.c |3 + drivers/i2c/busses/i2c-omap.c | 95 + include/linux/i2c-omap.h |1 + 3 files changed, 72 insertions(+), 27 deletions(-) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv10 7/7] I2C: OMAP: Recover from Bus Busy condition
From: Vikram Pandita In case a peripheral is driving SDA bus low (ie. a start condition), provide a constant clock output using the test mode of the OMAP I2C controller to try and clear the bus. Soft reset I2C controller after attempting the bus clear to ensure that controller is in a good state. Based upon Vikram Pandita's patch from TI Android 3.0. I acknowledge the contributions and suggestions of Jon and Hemant. A couple differences from the original patch ... 1. Add a new function for bus clear 2. Ensure that the CON.I2C_EN bit is set when using the SYSTEST feature to output a permanent clock. This bit needs to be set and typically it would be set by the unidle function but this is not the case for all OMAP generations. 3. Program the SYSTEST setting only the bits we care about. However, restore SYSTEST registers to there original state as some OMAP generations do not implement perform a soft-reset. 4. Clear the CON register after performing the bus clear, so when we call the init function the controller is disabled and the init function will re-enable later. Original patch can be found here: http://git.omapzoom.org/?p=kernel/omap.git;a=commit;h=a2ab04192ba25e60f95ba1ff3af5601a2d7b5bd1 Signed-off-by: Vikram Pandita Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 31 --- 1 files changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0557b0d..421dcd7 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -148,16 +148,15 @@ enum { #define OMAP_I2C_SCLH_HSSCLH 8 /* I2C System Test Register (OMAP_I2C_SYSTEST): */ -#ifdef DEBUG #define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ #define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */ #define OMAP_I2C_SYSTEST_TMODE_MASK(3 << 12) /* Test mode select */ -#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12)/* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_TEST(2 << 12) /* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_LOOP(3 << 12) /* Test mode select */ #define OMAP_I2C_SYSTEST_SCL_I (1 << 3)/* SCL line sense in */ #define OMAP_I2C_SYSTEST_SCL_O (1 << 2)/* SCL line drive out */ #define OMAP_I2C_SYSTEST_SDA_I (1 << 1)/* SDA line sense in */ #define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ -#endif /* OCP_SYSCONFIG bit definitions */ #define SYSC_CLOCKACTIVITY_MASK(0x3 << 8) @@ -460,6 +459,29 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) return 0; } +/* + * Bus Clear + */ +static int omap_i2c_bus_clear(struct omap_i2c_dev *dev) +{ + u16 w; + + /* +* Per the I2C specification, if we are stuck in a bus busy state +* we can attempt a bus clear to try and recover the bus by sending +* at least 9 clock pulses on SCL. Put the I2C in a test mode so it +* will output a continuous clock on SCL. +*/ + w = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, (OMAP_I2C_SYSTEST_ST_EN + | OMAP_I2C_SYSTEST_TMODE_TEST)); + msleep(1); + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, w); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + omap_i2c_init(dev); + return omap_i2c_wait_for_bb(dev); +} /* * Low level master read/write transaction. @@ -586,6 +608,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) r = omap_i2c_wait_for_bb(dev); if (r < 0) + r = omap_i2c_bus_clear(dev); + if (r < 0) goto out; if (dev->set_mpu_wkup_lat != NULL) @@ -654,6 +678,7 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) } } + return 0; } /* rev1 devices are apparently only on some 15xx */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv10 6/7] I2C: OMAP: Correct I2C revision for OMAP3
From: Jon Hunter The OMAP3530 is based upon the same silicon as the OMAP3430 and so the I2C revision is the same for 3430 and 3530. However, the OMAP3630 device has the same I2C revision as OMAP4. Correct the revision definition to reflect this. This patch is based on work done by Jon Hunter Changes from his patch - Update OMAP_I2C_REV_ON_3430 also to reflect that it is same as 3530 Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 10 +- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 8344ad030..0557b0d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -50,8 +50,8 @@ /* 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_3530_4430 0x40 +#define OMAP_I2C_REV_ON_3430_3530 0x3C +#define OMAP_I2C_REV_ON_3630_4430 0x40 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -305,7 +305,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_AUTOIDLE_MASK); - } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { + } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { dev->syscstate = SYSC_AUTOIDLE_MASK; dev->syscstate |= SYSC_ENAWAKEUP_MASK; dev->syscstate |= (SYSC_IDLEMODE_SMART << @@ -1021,7 +1021,7 @@ omap_i2c_probe(struct platform_device *pdev) if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) dev->errata |= I2C_OMAP_ERRATA_I207; - if (dev->rev <= OMAP_I2C_REV_ON_3430) + if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) dev->errata |= I2C_OMAP_ERRATA_I462; if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { @@ -1039,7 +1039,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) + if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 0; /* Disable hardware fixes */ else dev->b_hw = 1; /* Enable hardware fixes */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv10 1/7] I2C: OMAP: I2C register restore only if context is lost
Currently i2c register restore is done always. Adding conditional restore. The i2c register restore is done only if the context is lost or in case of error to be on the safe side. Cc: Kevin Hilman Signed-off-by: Shubhrajyoti D --- arch/arm/plat-omap/i2c.c |3 +++ drivers/i2c/busses/i2c-omap.c | 35 ++- include/linux/i2c-omap.h |1 + 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index db071bc..4ccab07 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -179,6 +179,9 @@ static inline int omap2_i2c_add_bus(int bus_id) */ if (cpu_is_omap34xx()) pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat; + + pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; + pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(struct omap_i2c_bus_platform_data), NULL, 0, 0); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9895fa7..9a54e88 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@ #include #include #include +#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -185,6 +186,7 @@ struct omap_i2c_dev { u32 latency;/* maximum mpu wkup latency */ void(*set_mpu_wkup_lat)(struct device *dev, long latency); + int (*get_context_loss_count)(struct device *dev); u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -207,6 +209,7 @@ struct omap_i2c_dev { u16 syscstate; u16 westate; u16 errata; + int dev_lost_count; }; static const u8 reg_map_ip_v1[] = { @@ -987,6 +990,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->speed = pdata->clkrate; dev->flags = pdata->flags; dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; + dev->get_context_loss_count = pdata->get_context_loss_count; dev->dtrev = pdata->rev; } @@ -1128,12 +1132,26 @@ omap_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_RUNTIME +static void omap_i2c_restore(struct omap_i2c_dev *dev) +{ + 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); + omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate); + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate); + omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + +} static int omap_i2c_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); u16 iv; + if (_dev->get_context_loss_count) + _dev->dev_lost_count = _dev->get_context_loss_count(dev); + _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); @@ -1154,16 +1172,15 @@ static int omap_i2c_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); + int loss_cnt; + + if (!(_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE)) + return 0; - if (_dev->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); - omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate); - omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate); - omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate); - omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate); - omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + if (_dev->get_context_loss_count) { + loss_cnt = _dev->get_context_loss_count(dev); + if (_dev->dev_lost_count != loss_cnt) + omap_i2c_restore(_dev); } /* diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 92a0dc7..c76cbc0 100644 --- a/include/linux/i2c
[PATCHv10 5/7] I2C: OMAP: Remove the definition of SYSS_RESETDONE_MASK
Remove the definition of SYSS_RESETDONE_MASK and use the one in omap_hwmod.h. Also fixes the warning CC drivers/i2c/busses/i2c-omap.o drivers/i2c/busses/i2c-omap.c:163: warning: "SYSS_RESETDONE_MASK" redefined Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f1109f4..8344ad030 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -159,9 +159,6 @@ enum { #define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ #endif -/* 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) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv10 2/7] I2C: OMAP: Optimise the remove code
The omap_i2c_remove function may not be needed after device exit so the memory could be freed. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9a54e88..d704f64 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1106,8 +1106,7 @@ err_release_region: return r; } -static int -omap_i2c_remove(struct platform_device *pdev) +static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; @@ -1204,7 +1203,7 @@ static struct dev_pm_ops omap_i2c_pm_ops = { static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, - .remove = omap_i2c_remove, + .remove = __devexit_p(omap_i2c_remove), .driver = { .name = "omap_i2c", .owner = THIS_MODULE, -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv10 4/7] I2C: OMAP: Do not initialise the completion everytime
Use INIT_COMPLETION instead of init_completion in transfer. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index c771c28..f1109f4 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -493,7 +493,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); - init_completion(&dev->cmd_complete); + INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -1003,6 +1003,7 @@ omap_i2c_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, dev); + init_completion(&dev->cmd_complete); dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv11 6/6] i2c: omap: Recover from Bus Busy condition
From: Vikram Pandita In case a peripheral is driving SDA bus low (ie. a start condition), provide a constant clock output using the test mode of the OMAP I2C controller to try and clear the bus. Soft reset I2C controller after attempting the bus clear to ensure that controller is in a good state. Based upon Vikram Pandita's patch from TI Android 3.0. I acknowledge the contributions and suggestions of Jon and Hemant. A couple differences from the original patch ... 1. Add a new function for bus clear 2. Ensure that the CON.I2C_EN bit is set when using the SYSTEST feature to output a permanent clock. This bit needs to be set and typically it would be set by the unidle function but this is not the case for all OMAP generations. 3. Program the SYSTEST setting only the bits we care about. However, restore SYSTEST registers to there original state as some OMAP generations do not implement perform a soft-reset. 4. Clear the CON register after performing the bus clear, so when we call the init function the controller is disabled and the init function will re-enable later. Original patch can be found here: http://git.omapzoom.org/?p=kernel/omap.git;a=commit;h=a2ab04192ba25e60f95ba1ff3af5601a2d7b5bd1 Signed-off-by: Vikram Pandita Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 30 +++--- 1 files changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 5058dfc..2500f19 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -148,16 +148,15 @@ enum { #define OMAP_I2C_SCLH_HSSCLH 8 /* I2C System Test Register (OMAP_I2C_SYSTEST): */ -#ifdef DEBUG #define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ #define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */ #define OMAP_I2C_SYSTEST_TMODE_MASK(3 << 12) /* Test mode select */ -#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12)/* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_TEST(2 << 12) /* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_LOOP(3 << 12) /* Test mode select */ #define OMAP_I2C_SYSTEST_SCL_I (1 << 3)/* SCL line sense in */ #define OMAP_I2C_SYSTEST_SCL_O (1 << 2)/* SCL line drive out */ #define OMAP_I2C_SYSTEST_SDA_I (1 << 1)/* SDA line sense in */ #define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ -#endif /* OCP_SYSCONFIG bit definitions */ #define SYSC_CLOCKACTIVITY_MASK(0x3 << 8) @@ -458,6 +457,29 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) return 0; } +/* + * Bus Clear + */ +static int omap_i2c_bus_clear(struct omap_i2c_dev *dev) +{ + u16 w; + + /* +* Per the I2C specification, if we are stuck in a bus busy state +* we can attempt a bus clear to try and recover the bus by sending +* at least 9 clock pulses on SCL. Put the I2C in a test mode so it +* will output a continuous clock on SCL. +*/ + w = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, (OMAP_I2C_SYSTEST_ST_EN + | OMAP_I2C_SYSTEST_TMODE_TEST)); + msleep(1); + omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, w); + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + omap_i2c_init(dev); + return omap_i2c_wait_for_bb(dev); +} /* * Low level master read/write transaction. @@ -584,6 +606,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) r = omap_i2c_wait_for_bb(dev); if (r < 0) + r = omap_i2c_bus_clear(dev); + if (r < 0) goto out; if (dev->set_mpu_wkup_lat != NULL) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv11 0/6] I2C cleanups
This is a minimal cleanup series. The patch series does the following - Bus busy recovery mechanism. - Make the i2c use SET_RUNTIME_PM_OPS - Use INIT_COMPLETION instead of init_completion - the reset patch is dropped will try to rework it as per the review comments recieved. This applies on Wolfram's i2c-embedded/for-next branch. Functional testing on omap4430 , 4460 panda and omap3sdp. The following changes since commit 0f009a914b40be8786fa67b1f4345cacc263b48c: i2c: tegra: make all resource allocation through devm_* (2012-06-13 16:01:38 +0200) are available in the git repository at: git://gitorious.org/linus-tree/linus-tree.git for_next/omap/minimal_cleanup Jon Hunter (1): i2c: omap: Correct I2C revision for OMAP3 Shubhrajyoti D (4): i2c: omap: Optimise the remove code i2c: omap: Use SET_RUNTIME_PM_OPS i2c: omap: Do not initialise the completion everytime i2c: omap: Remove the definition of SYSS_RESETDONE_MASK Vikram Pandita (1): i2c: omap: Recover from Bus Busy condition drivers/i2c/busses/i2c-omap.c | 60 1 files changed, 42 insertions(+), 18 deletions(-) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv11 1/6] i2c: omap: Optimise the remove code
The omap_i2c_remove function may not be needed after device exit so the memory could be freed. Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9895fa7..b086076 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1102,8 +1102,7 @@ err_release_region: return r; } -static int -omap_i2c_remove(struct platform_device *pdev) +static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); struct resource *mem; @@ -1187,7 +1186,7 @@ static struct dev_pm_ops omap_i2c_pm_ops = { static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, - .remove = omap_i2c_remove, + .remove = __devexit_p(omap_i2c_remove), .driver = { .name = "omap_i2c", .owner = THIS_MODULE, -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv11 5/6] i2c: omap: Correct I2C revision for OMAP3
From: Jon Hunter The OMAP3530 is based upon the same silicon as the OMAP3430 and so the I2C revision is the same for 3430 and 3530. However, the OMAP3630 device has the same I2C revision as OMAP4. Correct the revision definition to reflect this. This patch is based on work done by Jon Hunter Changes from his patch - Update OMAP_I2C_REV_ON_3430 also to reflect that it is same as 3530 Reviewed-by: Felipe Balbi Signed-off-by: Jon Hunter Signed-off-by: Shubhrajyoti D --- - Add Felipe's Reviewed by tag drivers/i2c/busses/i2c-omap.c | 10 +- 1 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 4bbf288..5058dfc 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -50,8 +50,8 @@ /* 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_3530_4430 0x40 +#define OMAP_I2C_REV_ON_3430_3530 0x3C +#define OMAP_I2C_REV_ON_3630_4430 0x40 /* timeout waiting for the controller to respond */ #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) @@ -303,7 +303,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_AUTOIDLE_MASK); - } else if (dev->rev >= OMAP_I2C_REV_ON_3430) { + } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { dev->syscstate = SYSC_AUTOIDLE_MASK; dev->syscstate |= SYSC_ENAWAKEUP_MASK; dev->syscstate |= (SYSC_IDLEMODE_SMART << @@ -1018,7 +1018,7 @@ omap_i2c_probe(struct platform_device *pdev) if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) dev->errata |= I2C_OMAP_ERRATA_I207; - if (dev->rev <= OMAP_I2C_REV_ON_3430) + if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) dev->errata |= I2C_OMAP_ERRATA_I462; if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { @@ -1036,7 +1036,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) + if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 0; /* Disable hardware fixes */ else dev->b_hw = 1; /* Enable hardware fixes */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv11 3/6] i2c: omap: Do not initialise the completion everytime
Use INIT_COMPLETION instead of init_completion in transfer. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- - Add Felipe's reviewed-by tag drivers/i2c/busses/i2c-omap.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b9915bb..6d05f18 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -490,7 +490,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); - init_completion(&dev->cmd_complete); + INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -999,6 +999,7 @@ omap_i2c_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, dev); + init_completion(&dev->cmd_complete); dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv11 2/6] i2c: omap: Use SET_RUNTIME_PM_OPS
Use SET_RUNTIME_PM_OPS macro to set runtime functions. Acked-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |8 +--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index b086076..b9915bb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1126,6 +1126,7 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM #ifdef CONFIG_PM_RUNTIME static int omap_i2c_runtime_suspend(struct device *dev) { @@ -1174,15 +1175,16 @@ static int omap_i2c_runtime_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_RUNTIME */ static struct dev_pm_ops omap_i2c_pm_ops = { - .runtime_suspend = omap_i2c_runtime_suspend, - .runtime_resume = omap_i2c_runtime_resume, + SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) #else #define OMAP_I2C_PM_OPS NULL -#endif +#endif /* CONFIG_PM */ static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv11 4/6] i2c: omap: Remove the definition of SYSS_RESETDONE_MASK
Remove the definition of SYSS_RESETDONE_MASK and use the one in omap_hwmod.h. Reviewed-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- - Add Felipe's reviewed by tag drivers/i2c/busses/i2c-omap.c |4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6d05f18..4bbf288 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@ #include #include #include +#include /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -158,9 +159,6 @@ enum { #define OMAP_I2C_SYSTEST_SDA_O (1 << 0)/* SDA line drive out */ #endif -/* 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) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] I2C: OMAP: fix runtime PM get/put balance on error
ensure pm_runtime_put() is called, on pm_runtime_get_sync() failure. Without this, after a failed call, the runtime PM usecount will have been incremented, but not decremented causing the usecount to never reach zero after a failure. Thanks to Kevin for educating about it. While at it also fix a missing pm_runtime_disable in the probe error path. Cc: Kevin Hilman Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |7 +++ 1 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2500f19..c8e5c76 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1113,10 +1113,10 @@ err_free_irq: free_irq(dev->irq, dev); err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); +err_free_mem: pm_runtime_put(dev->dev); iounmap(dev->base); pm_runtime_disable(&pdev->dev); -err_free_mem: platform_set_drvdata(pdev, NULL); kfree(dev); err_release_region: @@ -1136,10 +1136,9 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); ret = pm_runtime_get_sync(&pdev->dev); - if (IS_ERR_VALUE(ret)) - return ret; + if (!IS_ERR_VALUE(ret)) + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); iounmap(dev->base); -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 02/17] i2c: omap: simplify num_bytes handling
From: Felipe Balbi trivial patch, no functional changes If the fifo is disabled or fifo_size is 0 the num_bytes is set to 1. Else it is set to fifo_size or in case of a draining interrupt the remaining bytes in the buff stat. So the zero check is redundant and can be safely optimised. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |6 ++ 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7ad4efd..1df2bc9 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -831,8 +831,7 @@ complete: OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); if (dev->buf_len) { *dev->buf++ = w; @@ -874,8 +873,7 @@ complete: OMAP_I2C_BUFSTAT_REG) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = 0; if (dev->buf_len) { w = *dev->buf++; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 10/17] i2c: omap: ack IRQ in parts
From: Felipe Balbi According to flow diagrams on OMAP TRMs, we should ACK the IRQ as they happen. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 28 1 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index e4b83af..6e4c2be 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -869,21 +869,19 @@ omap_i2c_isr(int this_irq, void *dev_id) } complete: - /* -* Ack the stat in one go, but [R/X]DR and [R/X]RDY should be -* acked after the data operation is complete. -* Ref: TRM SWPU114Q Figure 18-31 -*/ - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat & - ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - - if (stat & OMAP_I2C_STAT_NACK) + if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; + } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } /* @@ -964,12 +962,18 @@ complete: if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); - dev->cmd_err |= OMAP_I2C_STAT_ROVR; + err |= OMAP_I2C_STAT_ROVR; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); - dev->cmd_err |= OMAP_I2C_STAT_XUDF; + err |= OMAP_I2C_STAT_XUDF; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } } while (stat); -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 17/17] i2c: omap: get rid of the "complete" label
From: Felipe Balbi we can ack stat and complete the command from the errata handling itself. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 16 +--- 1 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ac3bdae..bd8d282 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -794,6 +794,17 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + if (stat & OMAP_I2C_STAT_NACK) { + dev->cmd_err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + } + + if (stat & OMAP_I2C_STAT_AL) { + dev_err(dev->dev, "Arbitration lost\n"); + dev->cmd_err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + } + return -EIO; } @@ -895,7 +906,6 @@ omap_i2c_isr(int this_irq, void *dev_id) goto out; } -complete: if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); @@ -962,7 +972,7 @@ complete: ret = omap_i2c_transmit_data(dev, num_bytes, true); stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) - goto complete; + goto out; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); continue; @@ -978,7 +988,7 @@ complete: ret = omap_i2c_transmit_data(dev, num_bytes, false); stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) - goto complete; + goto out; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); continue; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 15/17] i2c: omap: simplify IRQ exit path
From: Felipe Balbi instead of having multiple return points, use a goto statement to make that clearer. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 20 1 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2cd3b9a..1196417 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -873,24 +873,21 @@ omap_i2c_isr(int this_irq, void *dev_id) dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { dev_warn(dev->dev, "Too much work in one IRQ\n"); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } complete: if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } /* @@ -903,8 +900,7 @@ complete: OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_ARDY)); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_RDR) { @@ -973,19 +969,19 @@ complete: dev_err(dev->dev, "Receive overrun\n"); err |= OMAP_I2C_STAT_ROVR; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); err |= OMAP_I2C_STAT_XUDF; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } } while (stat); +out: + omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 05/17] i2c: omap: simplify omap_i2c_ack_stat()
From: Felipe Balbi stat & BIT(1) is the same as BIT(1), so let's simplify things a bit by removing "stat &" from all omap_i2c_ack_stat() calls. Code snippet (extremely simplified): if (stat & NACK) { ... omap_i2c_ack_stat(dev, stat & NACK); } if (stat & RDR) { ... omap_i2c_ack_stat(dev, stat & RDR); } and so on. The tricky place is only WRT errata handling, for example: if (*stat & (NACK | AL)) { omap_i2c_ack_stat(dev, *stat & (XRDY | XDR)); ... } but in this case, the errata says we must clear XRDY and XDR if that errata triggers, so if they just got enabled or not, it doesn't matter. Another tricky place is RDR | RRDY (likewise for XDR | XRDY): if (stat & (RDR | RRDY)) { ... omap_i2c_ack_stat(dev, stat & (RDR | RRDY)); } again here there will be no issues because those IRQs never fire simultaneously and one will only after after we have handled the previous, that's because the same FIFO is used anyway and we won't shift data into FIFO until we tell the IP "hey, I'm done with the FIFO, you can shift more data" Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- - Added the explaination from the discurssion to the commit logs as per Wolfram's suggestion. drivers/i2c/busses/i2c-omap.c | 19 ++- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7be661e..359ee08 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -750,7 +750,7 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); return -ETIMEDOUT; } @@ -811,10 +811,11 @@ complete: */ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, stat & - (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | - OMAP_I2C_STAT_ARDY)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR | + OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR | + OMAP_I2C_STAT_ARDY)); omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } @@ -861,8 +862,8 @@ complete: } } } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR)); continue; } @@ -909,8 +910,8 @@ complete: omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR)); continue; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 03/17] i2c: omap: decrease indentation level on data handling
From: Felipe Balbi The patch intends to decrease the indentation level on the data handling by using the fact that else of if (dev->buf_len) is same as if (!dev->buf_len) if (dev->buf_len) { aaa; } else { bbb; break; } to if (!dev->buf_len) { bbb; break; } aaa; Hence no functional changes. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- - Changelogs updated. drivers/i2c/busses/i2c-omap.c | 63 - 1 files changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 1df2bc9..f67e998 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -832,22 +832,7 @@ complete: >> 8) & 0x3F; } while (num_bytes--) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - if (dev->buf_len) { - *dev->buf++ = w; - dev->buf_len--; - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & -OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } else { + if (!dev->buf_len) { if (stat & OMAP_I2C_STAT_RRDY) dev_err(dev->dev, "RRDY IRQ while no data" @@ -858,6 +843,21 @@ complete: " requested\n"); break; } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } } omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); @@ -874,22 +874,7 @@ complete: & 0x3F; } while (num_bytes--) { - w = 0; - if (dev->buf_len) { - w = *dev->buf++; - dev->buf_len--; - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & -OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; - } - } - } else { + if (!dev->buf_len) { if (stat & OMAP_I2C_STAT_XRDY) dev_err(dev->dev, "XRDY IRQ while no " @@ -901,6 +886,20 @@ complete: break; } + w = *dev->buf++; +
[PATCHv3 12/17] i2c: omap: bus: add a receiver flag
From: Felipe Balbi that way we can ignore TX IRQs while in receiver mode and ignore RX IRQs while in transmitter mode. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |9 + 1 files changed, 9 insertions(+), 0 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 9f04976..00d5adc 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -196,6 +196,7 @@ struct omap_i2c_dev { */ u8 rev; unsignedb_hw:1; /* bad h/w fixes */ + unsignedreceiver:1; /* true when we're in receiver mode */ u16 iestate;/* Saved interrupt register */ u16 pscstate; u16 scllstate; @@ -512,6 +513,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; + dev->receiver = !!(msg->flags & I2C_M_RD); w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -856,6 +858,13 @@ omap_i2c_isr(int this_irq, void *dev_id) stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); stat &= bits; + /* If we're in receiver mode, ignore XDR/XRDY */ + if (dev->receiver) { + stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); + } else { + stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); + } + if (!stat) { /* my work here is done */ return IRQ_HANDLED; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 11/17] i2c: omap: switch to platform_get_irq()
From: Felipe Balbi that's a nice helper from drivers core which will give us the exact IRQ number, instead of a pointer to an IRQ resource. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 12 +++- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6e4c2be..9f04976 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1016,11 +1016,12 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq; + struct resource *mem; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; irq_handler_t isr; + int irq; int r; /* NOTE: driver uses the static register mapping */ @@ -1029,10 +1030,11 @@ omap_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no mem resource?\n"); return -ENODEV; } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); - return -ENODEV; + return irq; } dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); @@ -1066,7 +1068,7 @@ omap_i2c_probe(struct platform_device *pdev) } dev->dev = &pdev->dev; - dev->irq = irq->start; + dev->irq = irq; platform_set_drvdata(pdev, dev); init_completion(&dev->cmd_complete); -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 14/17] i2c: omap: always return IRQ_HANDLED
From: Felipe Balbi otherwise we could get our IRQ line disabled due to many spurious IRQs. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index c48977c..2cd3b9a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -986,7 +986,7 @@ complete: } } while (stat); - return count ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } static const struct i2c_algorithm omap_i2c_algo = { -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 09/17] i2c: omap: switch over to do {} while loop
From: Felipe Balbi this will make sure that we execute at least once. No functional changes otherwise. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 20 ++-- 1 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index d57b75d..e4b83af 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -846,20 +846,28 @@ omap_i2c_isr(int this_irq, void *dev_id) struct omap_i2c_dev *dev = dev_id; u16 bits; u16 stat; - int err, count = 0; + int err = 0, count = 0; if (pm_runtime_suspended(dev->dev)) return IRQ_NONE; - bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) { + do { + bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + stat &= bits; + + if (!stat) { + /* my work here is done */ + return IRQ_HANDLED; + } + dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { dev_warn(dev->dev, "Too much work in one IRQ\n"); - break; + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } - err = 0; complete: /* * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be @@ -963,7 +971,7 @@ complete: dev_err(dev->dev, "Transmit underflow\n"); dev->cmd_err |= OMAP_I2C_STAT_XUDF; } - } + } while (stat); return count ? IRQ_HANDLED : IRQ_NONE; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 04/17] i2c: omap: add blank lines
From: Felipe Balbi trivial patch to aid readability. No functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |5 + 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f67e998..7be661e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -805,6 +805,7 @@ complete: dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; } + /* * ProDB0017052: Clear ARDY bit twice */ @@ -817,6 +818,7 @@ complete: omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } + if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { u8 num_bytes = 1; @@ -863,6 +865,7 @@ complete: stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); continue; } + if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { u8 num_bytes = 1; if (dev->fifo_size) { @@ -910,10 +913,12 @@ complete: stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); continue; } + if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); dev->cmd_err |= OMAP_I2C_STAT_ROVR; } + if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); dev->cmd_err |= OMAP_I2C_STAT_XUDF; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 08/17] i2c: omap: re-factor receive/transmit data loop
From: Felipe Balbi re-factor the common parts to a separate function, so that code is easier to read and understand. No functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 204 1 files changed, 82 insertions(+), 122 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 870452d..d57b75d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -771,12 +771,81 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) return 0; } +static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_rdr) +{ + u16 w; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, "%s without data", + is_rdr ? "RDR" : "RRDY"); + break; + } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } + } +} + +static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_xdr) +{ + u16 w; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, "%s without data", + is_xdr ? "XDR" : "XRDY"); + break; + } + + w = *dev->buf++; + dev->buf_len--; + + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + } + + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + if (ret < 0) + return ret; + } + + omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + } + + return 0; +} + static irqreturn_t omap_i2c_isr(int this_irq, void *dev_id) { struct omap_i2c_dev *dev = dev_id; u16 bits; - u16 stat, w; + u16 stat; int err, count = 0; if (pm_runtime_suspended(dev->dev)) @@ -831,30 +900,7 @@ complete: OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; - while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, - "RDR IRQ while no data" - " requested\n"); - break; - } - - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; - - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } + omap_i2c_receive_data(dev, num_bytes, true); if (dev->errata & I2C_OMAP_ERRATA_I207) i2c_omap_errata_i207(dev, stat); @@ -869,79 +915,24 @@ complete: if (dev->fifo_size) num_bytes = dev->fifo_size; - while (num_bytes--) { - if (!dev->buf_len) { -
[PATCHv3 01/17] i2c: omap: switch to devm_* API
From: Felipe Balbi that helps deleting some boiler plate code and lets driver-core manage our resources for us. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 40 +++- 1 files changed, 11 insertions(+), 29 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index feb15dd..7ad4efd 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -962,7 +962,7 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq, *ioarea; + struct resource *mem, *irq; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; @@ -981,17 +981,16 @@ omap_i2c_probe(struct platform_device *pdev) return -ENODEV; } - ioarea = request_mem_region(mem->start, resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; + dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "Menory allocation failed\n"); + return -ENOMEM; } - dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - r = -ENOMEM; - goto err_release_region; + dev->base = devm_request_and_ioremap(&pdev->dev, mem); + if (!dev->base) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -ENOMEM; } match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); @@ -1014,11 +1013,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->irq = irq->start; - dev->base = ioremap(mem->start, resource_size(mem)); - if (!dev->base) { - r = -ENOMEM; - goto err_free_mem; - } platform_set_drvdata(pdev, dev); init_completion(&dev->cmd_complete); @@ -1076,7 +1070,7 @@ omap_i2c_probe(struct platform_device *pdev) isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : omap_i2c_isr; - r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev); + r = devm_request_irq(&pdev->dev, dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev); if (r) { dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); @@ -1100,7 +1094,7 @@ omap_i2c_probe(struct platform_device *pdev) r = i2c_add_numbered_adapter(adap); if (r) { dev_err(dev->dev, "failure adding adapter\n"); - goto err_free_irq; + goto err_unuse_clocks; } of_i2c_register_devices(adap); @@ -1109,18 +1103,12 @@ omap_i2c_probe(struct platform_device *pdev) return 0; -err_free_irq: - free_irq(dev->irq, dev); err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); err_free_mem: pm_runtime_put(dev->dev); - iounmap(dev->base); pm_runtime_disable(&pdev->dev); platform_set_drvdata(pdev, NULL); - kfree(dev); -err_release_region: - release_mem_region(mem->start, resource_size(mem)); return r; } @@ -1128,12 +1116,10 @@ err_release_region: static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); - struct resource *mem; int ret; platform_set_drvdata(pdev, NULL); - free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); ret = pm_runtime_get_sync(&pdev->dev); if (!IS_ERR_VALUE(ret)) @@ -1141,10 +1127,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - iounmap(dev->base); - kfree(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); return 0; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 13/17] i2c: omap: simplify errata check
From: Felipe Balbi omap_i2c_dev is allocated with kzalloc(), so we need not initialize b_hw to zero. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 00d5adc..c48977c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1119,9 +1119,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) - dev->b_hw = 0; /* Disable hardware fixes */ - else + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 07/17] i2c: omap: improve i462 errata handling
From: Felipe Balbi Make it not depend on ISR's local variables in order to make it easier to re-factor the transmit data loop. Also since we are waiting for XUDF just before writing data lets not flag the underflow. This is anyways going to go once we write the data. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 43 1 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 45bd731..870452d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -744,27 +744,30 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) +static int errata_omap3_i462(struct omap_i2c_dev *dev) { unsigned long timeout = 1; + u16 stat; - while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { - if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { + do { + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + if (stat & OMAP_I2C_STAT_XUDF) + break; + + if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - return -ETIMEDOUT; + return -EIO; } cpu_relax(); - *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - } + } while (--timeout); if (!timeout) { dev_err(dev->dev, "timeout waiting on XUDF bit\n"); return 0; } - *err |= OMAP_I2C_STAT_XUDF; return 0; } @@ -926,9 +929,16 @@ complete: } } - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + stat = omap_i2c_read_reg(dev, + OMAP_I2C_STAT_REG); + + if (ret < 0) + goto complete; + } omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } @@ -966,9 +976,16 @@ complete: } } - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + stat = omap_i2c_read_reg(dev, + OMAP_I2C_STAT_REG); + + if (ret < 0) + goto complete; + } omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 16/17] i2c: omap: resize fifos before each message
From: Felipe Balbi This patch will try to avoid the usage of draining feature by reconfiguring the FIFO the start condition of each message based on the message's size. By doing that, we will be better utilizing the FIFO when doing big transfers. While at that also drop the now uneeded check for dev->buf_len as we always know the amount of data to be transmitted. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 83 + 1 files changed, 51 insertions(+), 32 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 1196417..ac3bdae 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -190,6 +190,7 @@ struct omap_i2c_dev { u8 *regs; size_t buf_len; struct i2c_adapter adapter; + u8 threshold; u8 fifo_size; /* use as flag and value * fifo_size==0 implies no fifo * if set, should be trsh+1 @@ -415,13 +416,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); - if (dev->fifo_size) { - /* Note: setup required fifo size - 1. RTRSH and XTRSH */ - buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR | - (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR; - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); - } - /* Take the I2C module out of reset: */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); @@ -482,6 +476,45 @@ static int omap_i2c_bus_clear(struct omap_i2c_dev *dev) return omap_i2c_wait_for_bb(dev); } +static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) +{ + u16 buf; + + if (dev->flags & OMAP_I2C_FLAG_NO_FIFO) + return; + + /* +* Set up notification threshold based on message size. We're doing +* this to try and avoid draining feature as much as possible. Whenever +* we have big messages to transfer (bigger than our total fifo size) +* then we might use draining feature to transfer the remaining bytes. +*/ + + dev->threshold = clamp(size, (u8) 1, dev->fifo_size); + + buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + + if (is_rx) { + /* Clear RX Threshold */ + buf &= ~(0x3f << 8); + buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; + } else { + /* Clear TX Threshold */ + buf &= ~0x3f; + buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; + } + + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); + + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) + dev->b_hw = 1; /* Enable hardware fixes */ + + /* calculate wakeup latency constraint for MPU */ + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (100 * dev->threshold) / + (1000 * dev->speed / 8); +} + /* * Low level master read/write transaction. */ @@ -498,6 +531,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (msg->len == 0) return -EINVAL; + dev->receiver = !!(msg->flags & I2C_M_RD); + omap_i2c_resize_fifo(dev, msg->len, dev->receiver); + omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr); /* REVISIT: Could the STB bit of I2C_CON be used with probing? */ @@ -513,7 +549,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; - dev->receiver = !!(msg->flags & I2C_M_RD); w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -779,12 +814,6 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, u16 w; while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, "%s without data", - is_rdr ? "RDR" : "RRDY"); - break; - } - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); *dev->buf++ = w; dev->buf_len--; @@ -794,10 +823,8 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, * omap4 is 8 bit wide */ if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { -
[PATCHv3 00/17] I2C Big cleanup
I have dropped a few patches from the series and also tested every single patch on my pandaboard. There's still lots of work to be done on the i2c-omap.c driver but it's now easier to read, IMO. Changes since v1: - removed tabification on patch 6/17 - removed dev_err() which was introduced on patch 09/17 Changes since v2: - do not set full fifo depth in the RDR interrupt. - some changelog updates. - rebase to the Wolfram's tree. Tested on omap4sdp and 3430sdp. Functional testing. Also did suspend resume. For omap3 the per domain seems to be OK. This applies on Wolfram's i2c-embedded/for-next branch plus the below series http://www.spinics.net/lists/linux-omap/msg72901.html are available in the git repository at: git://gitorious.org/linus-tree/linus-tree.git for_next/omap/big_cleanup Felipe Balbi (17): i2c: omap: switch to devm_* API i2c: omap: simplify num_bytes handling i2c: omap: decrease indentation level on data handling i2c: omap: add blank lines i2c: omap: simplify omap_i2c_ack_stat() i2c: omap: split out [XR]DR and [XR]RDY i2c: omap: improve i462 errata handling i2c: omap: re-factor receive/transmit data loop i2c: omap: switch over to do {} while loop i2c: omap: ack IRQ in parts i2c: omap: switch to platform_get_irq() i2c: omap: bus: add a receiver flag i2c: omap: simplify errata check i2c: omap: always return IRQ_HANDLED i2c: omap: simplify IRQ exit path i2c: omap: resize fifos before each message i2c: omap: get rid of the "complete" label drivers/i2c/busses/i2c-omap.c | 394 - 1 files changed, 232 insertions(+), 162 deletions(-) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv3 06/17] i2c: omap: split out [XR]DR and [XR]RDY
From: Felipe Balbi While they do pretty much the same thing, there are a few peculiarities. Specially WRT erratas, it's best to split those out and re-factor the read/write loop to another function which both cases call. This last part will be done on another patch. While at that, also avoid an unncessary register read since dev->fifo_len will always contain the correct amount of data to be transferred. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 126 ++-- 1 files changed, 94 insertions(+), 32 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 359ee08..45bd731 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -820,36 +820,64 @@ complete: return IRQ_HANDLED; } - if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { + if (stat & OMAP_I2C_STAT_RDR) { u8 num_bytes = 1; + if (dev->fifo_size) + num_bytes = (omap_i2c_read_reg(dev, + OMAP_I2C_BUFSTAT_REG) >> 8) + & 0x3F; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, + "RDR IRQ while no data" + " requested\n"); + break; + } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } + } + if (dev->errata & I2C_OMAP_ERRATA_I207) i2c_omap_errata_i207(dev, stat); - if (dev->fifo_size) { - if (stat & OMAP_I2C_STAT_RRDY) - num_bytes = dev->fifo_size; - else/* read RXSTAT on RDR interrupt */ - num_bytes = (omap_i2c_read_reg(dev, - OMAP_I2C_BUFSTAT_REG) - >> 8) & 0x3F; - } + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + continue; + } + + if (stat & OMAP_I2C_STAT_RRDY) { + u8 num_bytes = 1; + + if (dev->fifo_size) + num_bytes = dev->fifo_size; + while (num_bytes--) { if (!dev->buf_len) { - if (stat & OMAP_I2C_STAT_RRDY) - dev_err(dev->dev, + dev_err(dev->dev, "RRDY IRQ while no data" - " requested\n"); - if (stat & OMAP_I2C_STAT_RDR) - dev_err(dev->dev, - "RDR IRQ while no data" - " requested\n"); + " requested\n"); break; } w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); *dev->buf++ = w; dev->buf_len--; + /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide @@ -862,36 +890,70 @@ complete: } }
[RFC PATCH 0/3] I2C: Report the actual transferred bytes
Currently the I2C core reports only a negative number on errors. However some of the users in case of errors want to re-transfer only the remaining bytes. The patch series tries to add a actual field to the msg which can be checked by the user. Also a patch to implement the actual bytes transferred in case of i2c-omap. Felipe Balbi (1): i2c: omap: implement handling for 'actual' bytes transferred Shubhrajyoti D (2): i2c: add 'actual' field to struct i2c_msg i2c: inititalise the actual transferred to zero drivers/i2c/busses/i2c-omap.c |5 + drivers/i2c/i2c-core.c|4 ++-- include/linux/i2c.h |1 + 3 files changed, 8 insertions(+), 2 deletions(-) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 3/3] i2c: inititalise the actual transferred to zero
In i2c_smbus_xfer_emulated initialise the actual bytes to zero. Signed-off-by: Shubhrajyoti D --- drivers/i2c/i2c-core.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a6ad32b..fa7f799 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1949,8 +1949,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; int num = read_write == I2C_SMBUS_READ ? 2 : 1; - struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, - { addr, flags | I2C_M_RD, 0, msgbuf1 } + struct i2c_msg msg[2] = { { addr, flags, 1, 0, msgbuf0 }, + { addr, flags | I2C_M_RD, 0, 0, msgbuf1 } }; int i; u8 partial_pec = 0; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 1/3] i2c: add 'actual' field to struct i2c_msg
In case of a NACK, it's wise to tell our clients drivers about how many bytes were actually transferred. Support this by adding an extra field to the struct i2c_msg which gets incremented the amount of bytes actually transferred. Signed-off-by: Shubhrajyoti D Signed-off-by: Felipe Balbi --- include/linux/i2c.h |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ddfa041..0cb6b83 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -547,6 +547,7 @@ struct i2c_msg { #define I2C_M_NO_RD_ACK0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */ #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ __u16 len; /* msg length */ + __u16 actual; /* actual bytes transferred */ __u8 *buf; /* pointer to msg data */ }; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[RFC PATCH 2/3] i2c: omap: implement handling for 'actual' bytes transferred
From: Felipe Balbi this is important in cases where client driver wants to know how many bytes were actually transferred. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |5 + 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 266bba7..fc726a6 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -189,6 +189,7 @@ struct omap_i2c_dev { u8 *buf; u8 *regs; size_t buf_len; + u16 actual; struct i2c_adapter adapter; u8 threshold; u8 fifo_size; /* use as flag and value @@ -601,6 +602,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, omap_i2c_init(dev); return -ETIMEDOUT; } + msg->actual = dev->actual; if (likely(!dev->cmd_err)) return 0; @@ -828,6 +830,7 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); *dev->buf++ = w; dev->buf_len--; + dev->actual++; /* * Data reg in 2430, omap3 and @@ -848,6 +851,7 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, while (num_bytes--) { w = *dev->buf++; dev->buf_len--; + dev->actual++; /* * Data reg in 2430, omap3 and @@ -908,6 +912,7 @@ omap_i2c_isr(int this_irq, void *dev_id) if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; + dev->actual--; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); goto out; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 18/18] i2c: omap: remove redundant status read
Remove the redundant read of the status register. Signed-off-by: Shubhrajyoti D --- v4:Patch addition(fixes a review comment) drivers/i2c/busses/i2c-omap.c |2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 8940eb3..b1a32f8 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -965,7 +965,6 @@ omap_i2c_isr(int this_irq, void *dev_id) num_bytes = dev->buf_len; ret = omap_i2c_transmit_data(dev, num_bytes, true); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) goto out; @@ -981,7 +980,6 @@ omap_i2c_isr(int this_irq, void *dev_id) num_bytes = dev->threshold; ret = omap_i2c_transmit_data(dev, num_bytes, false); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) goto out; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 17/18] i2c: omap: get rid of the "complete" label
From: Felipe Balbi we can ack stat and complete the command from the errata handling itself. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 16 +--- 1 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f64916f..8940eb3 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -794,6 +794,17 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + if (stat & OMAP_I2C_STAT_NACK) { + dev->cmd_err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + } + + if (stat & OMAP_I2C_STAT_AL) { + dev_err(dev->dev, "Arbitration lost\n"); + dev->cmd_err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + } + return -EIO; } @@ -894,7 +905,6 @@ omap_i2c_isr(int this_irq, void *dev_id) goto out; } -complete: if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); @@ -957,7 +967,7 @@ complete: ret = omap_i2c_transmit_data(dev, num_bytes, true); stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) - goto complete; + goto out; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); continue; @@ -973,7 +983,7 @@ complete: ret = omap_i2c_transmit_data(dev, num_bytes, false); stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); if (ret < 0) - goto complete; + goto out; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); continue; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 10/18] i2c: omap: ack IRQ in parts
From: Felipe Balbi According to flow diagrams on OMAP TRMs, we should ACK the IRQ as they happen. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 28 1 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6c8f135..30db822 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -869,21 +869,19 @@ omap_i2c_isr(int this_irq, void *dev_id) } complete: - /* -* Ack the stat in one go, but [R/X]DR and [R/X]RDY should be -* acked after the data operation is complete. -* Ref: TRM SWPU114Q Figure 18-31 -*/ - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat & - ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - - if (stat & OMAP_I2C_STAT_NACK) + if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; + } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } /* @@ -960,12 +958,18 @@ complete: if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); - dev->cmd_err |= OMAP_I2C_STAT_ROVR; + err |= OMAP_I2C_STAT_ROVR; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); - dev->cmd_err |= OMAP_I2C_STAT_XUDF; + err |= OMAP_I2C_STAT_XUDF; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } } while (stat); -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 02/18] i2c: omap: simplify num_bytes handling
From: Felipe Balbi trivial patch, no functional changes If the fifo is disabled or fifo_size is 0 the num_bytes is set to 1. Else it is set to fifo_size or in case of a draining interrupt the remaining bytes in the buff stat. So the zero check is redundant and can be safely optimised. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |6 ++ 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0946be5..440e41f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -831,8 +831,7 @@ complete: OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); if (dev->buf_len) { *dev->buf++ = w; @@ -874,8 +873,7 @@ complete: OMAP_I2C_BUFSTAT_REG) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = 0; if (dev->buf_len) { w = *dev->buf++; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 07/18] i2c: omap: improve i462 errata handling
From: Felipe Balbi Make it not depend on ISR's local variables in order to make it easier to re-factor the transmit data loop. Also since we are waiting for XUDF just before writing data lets not service the underflow. This is anyways going to go once we write the data. Signed-off-by: Felipe Balbi [Avoid flagging the XUDF] Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 43 1 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 5c2460d..1715c35 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -744,27 +744,30 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) +static int errata_omap3_i462(struct omap_i2c_dev *dev) { unsigned long timeout = 1; + u16 stat; - while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { - if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { + do { + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + if (stat & OMAP_I2C_STAT_XUDF) + break; + + if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - return -ETIMEDOUT; + return -EIO; } cpu_relax(); - *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - } + } while (--timeout); if (!timeout) { dev_err(dev->dev, "timeout waiting on XUDF bit\n"); return 0; } - *err |= OMAP_I2C_STAT_XUDF; return 0; } @@ -922,9 +925,16 @@ complete: } } - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + stat = omap_i2c_read_reg(dev, + OMAP_I2C_STAT_REG); + + if (ret < 0) + goto complete; + } omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } @@ -962,9 +972,16 @@ complete: } } - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + stat = omap_i2c_read_reg(dev, + OMAP_I2C_STAT_REG); + + if (ret < 0) + goto complete; + } omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 05/18] i2c: omap: simplify omap_i2c_ack_stat()
From: Felipe Balbi stat & BIT(1) is the same as BIT(1), so let's simplify things a bit by removing "stat &" from all omap_i2c_ack_stat() calls. Code snippet (extremely simplified): if (stat & NACK) { ... omap_i2c_ack_stat(dev, stat & NACK); } if (stat & RDR) { ... omap_i2c_ack_stat(dev, stat & RDR); } and so on. The tricky place is only WRT errata handling, for example: if (*stat & (NACK | AL)) { omap_i2c_ack_stat(dev, *stat & (XRDY | XDR)); ... } but in this case, the errata says we must clear XRDY and XDR if that errata triggers, so if they just got enabled or not, it doesn't matter. Another tricky place is RDR | RRDY (likewise for XDR | XRDY): if (stat & (RDR | RRDY)) { ... omap_i2c_ack_stat(dev, stat & (RDR | RRDY)); } again here there will be no issues because those IRQs never fire simultaneously and one will only after after we have handled the previous, that's because the same FIFO is used anyway and we won't shift data into FIFO until we tell the IP "hey, I'm done with the FIFO, you can shift more data" Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar [Added the explaination from the discurssion to the commit logs] Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 19 ++- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 31c4e55..1c1ee7a 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -750,7 +750,7 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); return -ETIMEDOUT; } @@ -811,10 +811,11 @@ complete: */ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, stat & - (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | - OMAP_I2C_STAT_ARDY)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR | + OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR | + OMAP_I2C_STAT_ARDY)); omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } @@ -861,8 +862,8 @@ complete: } } } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR)); continue; } @@ -909,8 +910,8 @@ complete: omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR)); continue; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 04/18] i2c: omap: add blank lines
From: Felipe Balbi trivial patch to aid readability. No functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |5 + 1 files changed, 5 insertions(+), 0 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0da00ac..31c4e55 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -805,6 +805,7 @@ complete: dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; } + /* * ProDB0017052: Clear ARDY bit twice */ @@ -817,6 +818,7 @@ complete: omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } + if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { u8 num_bytes = 1; @@ -863,6 +865,7 @@ complete: stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); continue; } + if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { u8 num_bytes = 1; if (dev->fifo_size) { @@ -910,10 +913,12 @@ complete: stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); continue; } + if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); dev->cmd_err |= OMAP_I2C_STAT_ROVR; } + if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); dev->cmd_err |= OMAP_I2C_STAT_XUDF; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 00/18] I2C OMAP big cleanup
Changes since v1: - removed tabification on patch 6/17 - removed dev_err() which was introduced on patch 09/17 Changes since v2: - do not set full fifo depth in the RDR interrupt. - some changelog updates. - rebase to the Wolfram's tree. Changes since v3: - Remove a redundant read of status register - Read the dev->buf_len variable instead of the register as the information of the remaining bytes is there. Tested on omap4sdp and 3430sdp. Functional testing. Also did suspend resume. (with omap_fixes_a_3.5rc' of git://git.pwsan.com/linux-2.6 into lkml_master for 32ktimer fix) This applies on Wolfram's i2c-embedded/for-next branch plus the below series http://www.spinics.net/lists/linux-omap/msg72901.html Previous disscurssion http://www.spinics.net/lists/linux-omap/msg72997.html are available in the git repository at: git://gitorious.org/linus-tree/linus-tree.git for_next/omap/big_cleanup Felipe Balbi (17): i2c: omap: switch to devm_* API i2c: omap: simplify num_bytes handling i2c: omap: decrease indentation level on data handling i2c: omap: add blank lines i2c: omap: simplify omap_i2c_ack_stat() i2c: omap: split out [XR]DR and [XR]RDY i2c: omap: improve i462 errata handling i2c: omap: re-factor receive/transmit data loop i2c: omap: switch over to do {} while loop i2c: omap: ack IRQ in parts i2c: omap: switch to platform_get_irq() i2c: omap: bus: add a receiver flag i2c: omap: simplify errata check i2c: omap: always return IRQ_HANDLED i2c: omap: simplify IRQ exit path i2c: omap: resize fifos before each message i2c: omap: get rid of the "complete" label Shubhrajyoti D (1): i2c: omap: remove redundant status read drivers/i2c/busses/i2c-omap.c | 392 - 1 files changed, 228 insertions(+), 164 deletions(-) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 13/18] i2c: omap: simplify errata check
From: Felipe Balbi omap_i2c_dev is allocated with kzalloc(), so we need not initialize b_hw to zero. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 0fda3b7..7e3502e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1114,9 +1114,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) - dev->b_hw = 0; /* Disable hardware fixes */ - else + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 03/18] i2c: omap: decrease indentation level on data handling
From: Felipe Balbi The patch intends to decrease the indentation level on the data handling by using the fact that else of if (dev->buf_len) is same as if (!dev->buf_len) if (dev->buf_len) { aaa; } else { bbb; break; } to if (!dev->buf_len) { bbb; break; } aaa; Hence no functional changes. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 63 - 1 files changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 440e41f..0da00ac 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -832,22 +832,7 @@ complete: >> 8) & 0x3F; } while (num_bytes--) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - if (dev->buf_len) { - *dev->buf++ = w; - dev->buf_len--; - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & -OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } else { + if (!dev->buf_len) { if (stat & OMAP_I2C_STAT_RRDY) dev_err(dev->dev, "RRDY IRQ while no data" @@ -858,6 +843,21 @@ complete: " requested\n"); break; } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } } omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); @@ -874,22 +874,7 @@ complete: & 0x3F; } while (num_bytes--) { - w = 0; - if (dev->buf_len) { - w = *dev->buf++; - dev->buf_len--; - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & -OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; - } - } - } else { + if (!dev->buf_len) { if (stat & OMAP_I2C_STAT_XRDY) dev_err(dev->dev, "XRDY IRQ while no " @@ -901,6 +886,20 @@ complete: break; } + w = *dev->buf++; +
[PATCHv4 14/18] i2c: omap: always return IRQ_HANDLED
From: Felipe Balbi otherwise we could get our IRQ line disabled due to many spurious IRQs. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 7e3502e..81c1c1b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -981,7 +981,7 @@ complete: } } while (stat); - return count ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } static const struct i2c_algorithm omap_i2c_algo = { -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 16/18] i2c: omap: resize fifos before each message
From: Felipe Balbi This patch will try to avoid the usage of draining feature by reconfiguring the FIFO the start condition of each message based on the message's size. By doing that, we will be better utilizing the FIFO when doing big transfers. While at that also drop the now uneeded check for dev->buf_len as we always know the amount of data to be transmitted. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 83 + 1 files changed, 51 insertions(+), 32 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 5e3fb4c..f64916f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -190,6 +190,7 @@ struct omap_i2c_dev { u8 *regs; size_t buf_len; struct i2c_adapter adapter; + u8 threshold; u8 fifo_size; /* use as flag and value * fifo_size==0 implies no fifo * if set, should be trsh+1 @@ -415,13 +416,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll); omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); - if (dev->fifo_size) { - /* Note: setup required fifo size - 1. RTRSH and XTRSH */ - buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR | - (dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR; - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); - } - /* Take the I2C module out of reset: */ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); @@ -482,6 +476,45 @@ static int omap_i2c_bus_clear(struct omap_i2c_dev *dev) return omap_i2c_wait_for_bb(dev); } +static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) +{ + u16 buf; + + if (dev->flags & OMAP_I2C_FLAG_NO_FIFO) + return; + + /* +* Set up notification threshold based on message size. We're doing +* this to try and avoid draining feature as much as possible. Whenever +* we have big messages to transfer (bigger than our total fifo size) +* then we might use draining feature to transfer the remaining bytes. +*/ + + dev->threshold = clamp(size, (u8) 1, dev->fifo_size); + + buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + + if (is_rx) { + /* Clear RX Threshold */ + buf &= ~(0x3f << 8); + buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; + } else { + /* Clear TX Threshold */ + buf &= ~0x3f; + buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; + } + + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); + + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) + dev->b_hw = 1; /* Enable hardware fixes */ + + /* calculate wakeup latency constraint for MPU */ + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (100 * dev->threshold) / + (1000 * dev->speed / 8); +} + /* * Low level master read/write transaction. */ @@ -498,6 +531,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (msg->len == 0) return -EINVAL; + dev->receiver = !!(msg->flags & I2C_M_RD); + omap_i2c_resize_fifo(dev, msg->len, dev->receiver); + omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr); /* REVISIT: Could the STB bit of I2C_CON be used with probing? */ @@ -513,7 +549,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; - dev->receiver = !!(msg->flags & I2C_M_RD); w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -779,12 +814,6 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, u16 w; while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, "%s without data", - is_rdr ? "RDR" : "RRDY"); - break; - } - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); *dev->buf++ = w; dev->buf_len--; @@ -794,10 +823,8 @@ static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, * omap4 is 8 bit wide */ if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { -
[PATCHv4 15/18] i2c: omap: simplify IRQ exit path
From: Felipe Balbi instead of having multiple return points, use a goto statement to make that clearer. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 20 1 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 81c1c1b..5e3fb4c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -872,24 +872,21 @@ omap_i2c_isr(int this_irq, void *dev_id) dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { dev_warn(dev->dev, "Too much work in one IRQ\n"); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } complete: if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } /* @@ -902,8 +899,7 @@ complete: OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_ARDY)); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_RDR) { @@ -968,19 +964,19 @@ complete: dev_err(dev->dev, "Receive overrun\n"); err |= OMAP_I2C_STAT_ROVR; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); err |= OMAP_I2C_STAT_XUDF; omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); - omap_i2c_complete_cmd(dev, err); - return IRQ_HANDLED; + goto out; } } while (stat); +out: + omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 11/18] i2c: omap: switch to platform_get_irq()
From: Felipe Balbi that's a nice helper from drivers core which will give us the exact IRQ number, instead of a pointer to an IRQ resource. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 12 +++- 1 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 30db822..46d099e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1012,11 +1012,12 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq; + struct resource *mem; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; irq_handler_t isr; + int irq; int r; /* NOTE: driver uses the static register mapping */ @@ -1025,10 +1026,11 @@ omap_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no mem resource?\n"); return -ENODEV; } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); - return -ENODEV; + return irq; } dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); @@ -1062,7 +1064,7 @@ omap_i2c_probe(struct platform_device *pdev) } dev->dev = &pdev->dev; - dev->irq = irq->start; + dev->irq = irq; platform_set_drvdata(pdev, dev); init_completion(&dev->cmd_complete); -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 12/18] i2c: omap: bus: add a receiver flag
From: Felipe Balbi that way we can ignore TX IRQs while in receiver mode and ignore RX IRQs while in transmitter mode. Signed-off-by: Felipe Balbi [Trivial formatting changes] Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |8 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 46d099e..0fda3b7 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -196,6 +196,7 @@ struct omap_i2c_dev { */ u8 rev; unsignedb_hw:1; /* bad h/w fixes */ + unsignedreceiver:1; /* true when we're in receiver mode */ u16 iestate;/* Saved interrupt register */ u16 pscstate; u16 scllstate; @@ -512,6 +513,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; + dev->receiver = !!(msg->flags & I2C_M_RD); w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -856,6 +858,12 @@ omap_i2c_isr(int this_irq, void *dev_id) stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); stat &= bits; + /* If we're in receiver mode, ignore XDR/XRDY */ + if (dev->receiver) + stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); + else + stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); + if (!stat) { /* my work here is done */ return IRQ_HANDLED; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 06/18] i2c: omap: split out [XR]DR and [XR]RDY
From: Felipe Balbi While they do pretty much the same thing, there are a few peculiarities. Specially WRT erratas, it's best to split those out and re-factor the read/write loop to another function which both cases call. This last part will be done on another patch. While at that, also avoid an unncessary register read since dev->fifo_len will always contain the correct amount of data to be transferred. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- v4: use dev->buf_len as it is in sync with the remaining bytes avoids a reg read thereby. drivers/i2c/busses/i2c-omap.c | 126 ++--- 1 files changed, 92 insertions(+), 34 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 1c1ee7a..5c2460d 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -820,36 +820,62 @@ complete: return IRQ_HANDLED; } - if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { + if (stat & OMAP_I2C_STAT_RDR) { u8 num_bytes = 1; + if (dev->fifo_size) + num_bytes = dev->buf_len; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, + "RDR IRQ while no data" + " requested\n"); + break; + } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & + OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } + } + if (dev->errata & I2C_OMAP_ERRATA_I207) i2c_omap_errata_i207(dev, stat); - if (dev->fifo_size) { - if (stat & OMAP_I2C_STAT_RRDY) - num_bytes = dev->fifo_size; - else/* read RXSTAT on RDR interrupt */ - num_bytes = (omap_i2c_read_reg(dev, - OMAP_I2C_BUFSTAT_REG) - >> 8) & 0x3F; - } + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + continue; + } + + if (stat & OMAP_I2C_STAT_RRDY) { + u8 num_bytes = 1; + + if (dev->fifo_size) + num_bytes = dev->fifo_size; + while (num_bytes--) { if (!dev->buf_len) { - if (stat & OMAP_I2C_STAT_RRDY) - dev_err(dev->dev, + dev_err(dev->dev, "RRDY IRQ while no data" - " requested\n"); - if (stat & OMAP_I2C_STAT_RDR) - dev_err(dev->dev, - "RDR IRQ while no data" - " requested\n"); + " requested\n"); break; } w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); *dev->buf++ = w; dev->buf_len--; + /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide @@ -862,36 +888,68 @@ complete: } } } - omap_i2c_ack_stat(dev, (
[PATCHv4 09/18] i2c: omap: switch over to do {} while loop
From: Felipe Balbi this will make sure that we execute at least once. No functional changes otherwise. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 20 ++-- 1 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index dca6d3e..6c8f135 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -846,20 +846,28 @@ omap_i2c_isr(int this_irq, void *dev_id) struct omap_i2c_dev *dev = dev_id; u16 bits; u16 stat; - int err, count = 0; + int err = 0, count = 0; if (pm_runtime_suspended(dev->dev)) return IRQ_NONE; - bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) { + do { + bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + stat &= bits; + + if (!stat) { + /* my work here is done */ + return IRQ_HANDLED; + } + dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { dev_warn(dev->dev, "Too much work in one IRQ\n"); - break; + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } - err = 0; complete: /* * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be @@ -959,7 +967,7 @@ complete: dev_err(dev->dev, "Transmit underflow\n"); dev->cmd_err |= OMAP_I2C_STAT_XUDF; } - } + } while (stat); return count ? IRQ_HANDLED : IRQ_NONE; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 01/18] i2c: omap: switch to devm_* API
From: Felipe Balbi that helps deleting some boiler plate code and lets driver-core manage our resources for us. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 41 - 1 files changed, 12 insertions(+), 29 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2500f19..0946be5 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -962,7 +962,7 @@ omap_i2c_probe(struct platform_device *pdev) { struct omap_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *mem, *irq, *ioarea; + struct resource *mem, *irq; struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; @@ -981,17 +981,16 @@ omap_i2c_probe(struct platform_device *pdev) return -ENODEV; } - ioarea = request_mem_region(mem->start, resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "I2C region already claimed\n"); - return -EBUSY; + dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); + if (!dev) { + dev_err(&pdev->dev, "Menory allocation failed\n"); + return -ENOMEM; } - dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - r = -ENOMEM; - goto err_release_region; + dev->base = devm_request_and_ioremap(&pdev->dev, mem); + if (!dev->base) { + dev_err(&pdev->dev, "I2C region already claimed\n"); + return -ENOMEM; } match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); @@ -1014,11 +1013,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->dev = &pdev->dev; dev->irq = irq->start; - dev->base = ioremap(mem->start, resource_size(mem)); - if (!dev->base) { - r = -ENOMEM; - goto err_free_mem; - } platform_set_drvdata(pdev, dev); init_completion(&dev->cmd_complete); @@ -1076,7 +1070,8 @@ omap_i2c_probe(struct platform_device *pdev) isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : omap_i2c_isr; - r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev); + r = devm_request_irq(&pdev->dev, dev->irq, isr, IRQF_NO_SUSPEND, +pdev->name, dev); if (r) { dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); @@ -1100,7 +1095,7 @@ omap_i2c_probe(struct platform_device *pdev) r = i2c_add_numbered_adapter(adap); if (r) { dev_err(dev->dev, "failure adding adapter\n"); - goto err_free_irq; + goto err_unuse_clocks; } of_i2c_register_devices(adap); @@ -1109,18 +1104,12 @@ omap_i2c_probe(struct platform_device *pdev) return 0; -err_free_irq: - free_irq(dev->irq, dev); err_unuse_clocks: omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(dev->dev); - iounmap(dev->base); pm_runtime_disable(&pdev->dev); err_free_mem: platform_set_drvdata(pdev, NULL); - kfree(dev); -err_release_region: - release_mem_region(mem->start, resource_size(mem)); return r; } @@ -1128,12 +1117,10 @@ err_release_region: static int __devexit omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *dev = platform_get_drvdata(pdev); - struct resource *mem; int ret; platform_set_drvdata(pdev, NULL); - free_irq(dev->irq, dev); i2c_del_adapter(&dev->adapter); ret = pm_runtime_get_sync(&pdev->dev); if (IS_ERR_VALUE(ret)) @@ -1142,10 +1129,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev) omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - iounmap(dev->base); - kfree(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem->start, resource_size(mem)); return 0; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv4 08/18] i2c: omap: re-factor receive/transmit data loop
From: Felipe Balbi re-factor the common parts to a separate function, so that code is easier to read and understand. No functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 204 1 files changed, 82 insertions(+), 122 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 1715c35..dca6d3e 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -771,12 +771,81 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) return 0; } +static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_rdr) +{ + u16 w; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, "%s without data", + is_rdr ? "RDR" : "RRDY"); + break; + } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } + } +} + +static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_xdr) +{ + u16 w; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, "%s without data", + is_xdr ? "XDR" : "XRDY"); + break; + } + + w = *dev->buf++; + dev->buf_len--; + + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + } + + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + if (ret < 0) + return ret; + } + + omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + } + + return 0; +} + static irqreturn_t omap_i2c_isr(int this_irq, void *dev_id) { struct omap_i2c_dev *dev = dev_id; u16 bits; - u16 stat, w; + u16 stat; int err, count = 0; if (pm_runtime_suspended(dev->dev)) @@ -829,30 +898,7 @@ complete: if (dev->fifo_size) num_bytes = dev->buf_len; - while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, - "RDR IRQ while no data" - " requested\n"); - break; - } - - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; - - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } + omap_i2c_receive_data(dev, num_bytes, true); if (dev->errata & I2C_OMAP_ERRATA_I207) i2c_omap_errata_i207(dev, stat); @@ -867,77 +913,22 @@ complete: if (dev->fifo_size) num_bytes = dev->fifo_size; - while (num_bytes--) { - if (!dev->buf_len) { -
[PATCH RFC] spi: omap2-mcspi: Fix the dma_unmap warning
The dma_map and dma_unmap should have same parameter passed otherwise we get the below warn. ks8851 spi1.0: DMA-API: device driver tries to free DMA memory it has not allocated [device address=0x9f22] [2.066925] Modules linked in: [2.070312] [2.071929] [] (unwind_backtrace+0x0/0x130) from [] (warn_slowpath_common+0x4c/0x64) [2.081909] [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_fmt+0x30/0x40) [2.091949] [] (warn_slowpath_fmt+0x30/0x40) from [] (check_unmap+0x6d0/0x7b0) [2.101348] [] (check_unmap+0x6d0/0x7b0) from [] (debug_dma_unmap_page+0x64/0x70) [2.111053] [] (debug_dma_unmap_page+0x64/0x70) from [] (omap2_mcspi_txrx_dma+0x2d8/0x4fc) [2.121582] [] (omap2_mcspi_txrx_dma+0x2d8/0x4fc) from [] (omap2_mcspi_work.clone.4+0xf0/0x290) [2.132537] [] (omap2_mcspi_work.clone.4+0xf0/0x290) from [] (omap2_mcspi_transfer_one_message+0x288/0x438) [2.144592] [] (omap2_mcspi_transfer_one_message+0x288/0x438) from [] (spi_pump_messages+0x100/0x160) [2.156127] [] (spi_pump_messages+0x100/0x160) from [] (kthread_worker_fn+0xac/0x180) [2.166168] [] (kthread_worker_fn+0xac/0x180) from [] (kthread+0x90/0x9c) [2.175140] [] (kthread+0x90/0x9c) from [] (kernel_thread_exit+0x0/0x8) [2.183898] ---[ end trace d1830ce6e44292f2 ]--- Fix the warn by changing the unmap parameter to the one used while doing dma_map. Reported-by: Russell King Signed-off-by: Shubhrajyoti D --- drivers/spi/spi-omap2-mcspi.c |6 -- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 0c73dd4..37ccdb7 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -388,7 +388,8 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) if (tx != NULL) { wait_for_completion(&mcspi_dma->dma_tx_completion); - dma_unmap_single(&spi->dev, xfer->tx_dma, count, DMA_TO_DEVICE); + dma_unmap_single(mcspi->dev, xfer->tx_dma, count, +DMA_TO_DEVICE); /* for TX_ONLY mode, be sure all words have shifted out */ if (rx == NULL) { @@ -403,7 +404,8 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) if (rx != NULL) { wait_for_completion(&mcspi_dma->dma_rx_completion); - dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE); + dma_unmap_single(mcspi->dev, xfer->rx_dma, count, +DMA_FROM_DEVICE); omap2_mcspi_set_enable(spi, 0); if (l & OMAP2_MCSPI_CHCONF_TURBO) { -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 13/18] i2c: omap: simplify errata check
From: Felipe Balbi omap_i2c_dev is allocated with kzalloc(), so we need not initialize b_hw to zero. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |4 +--- 1 files changed, 1 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index d732865..19f6048 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1092,9 +1092,7 @@ omap_i2c_probe(struct platform_device *pdev) dev->fifo_size = (dev->fifo_size / 2); - if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) - dev->b_hw = 0; /* Disable hardware fixes */ - else + if (dev->rev < OMAP_I2C_REV_ON_3630_4430) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 08/18] i2c: omap: re-factor receive/transmit data loop
From: Felipe Balbi re-factor the common parts to a separate function, so that code is easier to read and understand. No functional changes. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 204 1 files changed, 82 insertions(+), 122 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6f98812..700f018 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -749,12 +749,81 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) return 0; } +static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_rdr) +{ + u16 w; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, "%s without data", + is_rdr ? "RDR" : "RRDY"); + break; + } + + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); + *dev->buf++ = w; + dev->buf_len--; + + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + } + } +} + +static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, + bool is_xdr) +{ + u16 w; + + while (num_bytes--) { + if (!dev->buf_len) { + dev_err(dev->dev, "%s without data", + is_xdr ? "XDR" : "XRDY"); + break; + } + + w = *dev->buf++; + dev->buf_len--; + + /* +* Data reg in 2430, omap3 and +* omap4 is 8 bit wide +*/ + if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + if (dev->buf_len) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + } + + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + if (ret < 0) + return ret; + } + + omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + } + + return 0; +} + static irqreturn_t omap_i2c_isr(int this_irq, void *dev_id) { struct omap_i2c_dev *dev = dev_id; u16 bits; - u16 stat, w; + u16 stat; int err, count = 0; if (pm_runtime_suspended(dev->dev)) @@ -807,30 +876,7 @@ complete: if (dev->fifo_size) num_bytes = dev->buf_len; - while (num_bytes--) { - if (!dev->buf_len) { - dev_err(dev->dev, - "RDR IRQ while no data" - " requested\n"); - break; - } - - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; - - /* -* Data reg in 2430, omap3 and -* omap4 is 8 bit wide -*/ - if (dev->flags & - OMAP_I2C_FLAG_16BIT_DATA_REG) { - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; - } - } - } + omap_i2c_receive_data(dev, num_bytes, true); if (dev->errata & I2C_OMAP_ERRATA_I207) i2c_omap_errata_i207(dev, stat); @@ -845,77 +891,22 @@ complete: if (dev->fifo_size) num_bytes = dev->fifo_size; - while (num_bytes--) { - if (!dev->buf_len) { -
[PATCHv5 05/18] i2c: omap: simplify omap_i2c_ack_stat()
From: Felipe Balbi stat & BIT(1) is the same as BIT(1), so let's simplify things a bit by removing "stat &" from all omap_i2c_ack_stat() calls. Code snippet (extremely simplified): if (stat & NACK) { ... omap_i2c_ack_stat(dev, stat & NACK); } if (stat & RDR) { ... omap_i2c_ack_stat(dev, stat & RDR); } and so on. The tricky place is only WRT errata handling, for example: if (*stat & (NACK | AL)) { omap_i2c_ack_stat(dev, *stat & (XRDY | XDR)); ... } but in this case, the errata says we must clear XRDY and XDR if that errata triggers, so if they just got enabled or not, it doesn't matter. Another tricky place is RDR | RRDY (likewise for XDR | XRDY): if (stat & (RDR | RRDY)) { ... omap_i2c_ack_stat(dev, stat & (RDR | RRDY)); } again here there will be no issues because those IRQs never fire simultaneously and one will only after after we have handled the previous, that's because the same FIFO is used anyway and we won't shift data into FIFO until we tell the IP "hey, I'm done with the FIFO, you can shift more data" Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar [Added the explaination from the discurssion to the commit logs] Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 19 ++- 1 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 323d52e..940ba64 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -728,7 +728,7 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); return -ETIMEDOUT; } @@ -789,10 +789,11 @@ complete: */ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, stat & - (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | - OMAP_I2C_STAT_ARDY)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR | + OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR | + OMAP_I2C_STAT_ARDY)); omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } @@ -839,8 +840,8 @@ complete: } } } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + OMAP_I2C_STAT_RDR)); continue; } @@ -887,8 +888,8 @@ complete: omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } - omap_i2c_ack_stat(dev, - stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | + OMAP_I2C_STAT_XDR)); continue; } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 14/18] i2c: omap: always return IRQ_HANDLED
From: Felipe Balbi otherwise we could get our IRQ line disabled due to many spurious IRQs. Signed-off-by: Felipe Balbi Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 19f6048..6847a98 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -959,7 +959,7 @@ complete: } } while (stat); - return count ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } static const struct i2c_algorithm omap_i2c_algo = { -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 02/18] i2c: omap: simplify num_bytes handling
From: Felipe Balbi trivial patch, no functional changes If the fifo is disabled or fifo_size is 0 the num_bytes is set to 1. Else it is set to fifo_size or in case of a draining interrupt the remaining bytes in the buff stat. So the zero check is redundant and can be safely optimised. Signed-off-by: Felipe Balbi Reviewed-by : Santosh Shilimkar Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |6 ++ 1 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 788c16c..520f3ea 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -809,8 +809,7 @@ complete: OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); if (dev->buf_len) { *dev->buf++ = w; @@ -852,8 +851,7 @@ complete: OMAP_I2C_BUFSTAT_REG) & 0x3F; } - while (num_bytes) { - num_bytes--; + while (num_bytes--) { w = 0; if (dev->buf_len) { w = *dev->buf++; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 12/18] i2c: omap: bus: add a receiver flag
From: Felipe Balbi that way we can ignore TX IRQs while in receiver mode and ignore RX IRQs while in transmitter mode. Signed-off-by: Felipe Balbi [Trivial formatting changes] Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c |8 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 71047dd..d732865 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -199,6 +199,7 @@ struct omap_i2c_dev { */ u8 rev; unsignedb_hw:1; /* bad h/w fixes */ + unsignedreceiver:1; /* true when we're in receiver mode */ u16 iestate;/* Saved interrupt register */ u16 pscstate; u16 scllstate; @@ -492,6 +493,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, INIT_COMPLETION(dev->cmd_complete); dev->cmd_err = 0; + dev->receiver = !!(msg->flags & I2C_M_RD); w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; @@ -834,6 +836,12 @@ omap_i2c_isr(int this_irq, void *dev_id) stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); stat &= bits; + /* If we're in receiver mode, ignore XDR/XRDY */ + if (dev->receiver) + stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); + else + stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); + if (!stat) { /* my work here is done */ return IRQ_HANDLED; -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 10/18] i2c: omap: ack IRQ in parts
From: Felipe Balbi According to flow diagrams on OMAP TRMs, we should ACK the IRQ as they happen. Signed-off-by: Felipe Balbi [ack the stat OMAP_I2C_STAT_AL in case of arbitration lost] Signed-off-by: Shubhrajyoti D --- v5 - ack the OMAP_I2C_STAT_AL. drivers/i2c/busses/i2c-omap.c | 28 1 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 78fc274..62ad126 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -847,21 +847,19 @@ omap_i2c_isr(int this_irq, void *dev_id) } complete: - /* -* Ack the stat in one go, but [R/X]DR and [R/X]RDY should be -* acked after the data operation is complete. -* Ref: TRM SWPU114Q Figure 18-31 -*/ - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat & - ~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - - if (stat & OMAP_I2C_STAT_NACK) + if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; + } if (stat & OMAP_I2C_STAT_AL) { dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } /* @@ -938,12 +936,18 @@ complete: if (stat & OMAP_I2C_STAT_ROVR) { dev_err(dev->dev, "Receive overrun\n"); - dev->cmd_err |= OMAP_I2C_STAT_ROVR; + err |= OMAP_I2C_STAT_ROVR; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } if (stat & OMAP_I2C_STAT_XUDF) { dev_err(dev->dev, "Transmit underflow\n"); - dev->cmd_err |= OMAP_I2C_STAT_XUDF; + err |= OMAP_I2C_STAT_XUDF; + omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); + omap_i2c_complete_cmd(dev, err); + return IRQ_HANDLED; } } while (stat); -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCHv5 07/18] i2c: omap: improve i462 errata handling
From: Felipe Balbi Make it not depend on ISR's local variables in order to make it easier to re-factor the transmit data loop. Also since we are waiting for XUDF(Transmitter underflow) just before writing data lets not flag the underflow. This is anyways going to go once we write the data. Signed-off-by: Felipe Balbi [Avoid flagging the XUDF] Signed-off-by: Shubhrajyoti D --- drivers/i2c/busses/i2c-omap.c | 43 1 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 5f6d9c5..6f98812 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -722,27 +722,30 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) +static int errata_omap3_i462(struct omap_i2c_dev *dev) { unsigned long timeout = 1; + u16 stat; - while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { - if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { + do { + stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + if (stat & OMAP_I2C_STAT_XUDF) + break; + + if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - return -ETIMEDOUT; + return -EIO; } cpu_relax(); - *stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); - } + } while (--timeout); if (!timeout) { dev_err(dev->dev, "timeout waiting on XUDF bit\n"); return 0; } - *err |= OMAP_I2C_STAT_XUDF; return 0; } @@ -900,9 +903,16 @@ complete: } } - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + stat = omap_i2c_read_reg(dev, + OMAP_I2C_STAT_REG); + + if (ret < 0) + goto complete; + } omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } @@ -940,9 +950,16 @@ complete: } } - if ((dev->errata & I2C_OMAP_ERRATA_I462) && - errata_omap3_i462(dev, &stat, &err)) - goto complete; + if (dev->errata & I2C_OMAP_ERRATA_I462) { + int ret; + + ret = errata_omap3_i462(dev); + stat = omap_i2c_read_reg(dev, + OMAP_I2C_STAT_REG); + + if (ret < 0) + goto complete; + } omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); } -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html