diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-pxa.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 156 |
1 files changed, 103 insertions, 53 deletions
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index a636ea0eb50a..968a8b8794da 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -32,6 +32,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/platform_data/i2c-pxa.h> +#include <linux/property.h> #include <linux/slab.h> /* I2C register field definitions */ @@ -217,7 +218,7 @@ static const struct platform_device_id i2c_pxa_id_table[] = { { "ce4100-i2c", REGS_CE4100 }, { "pxa910-i2c", REGS_PXA910 }, { "armada-3700-i2c", REGS_A3700 }, - { }, + { } }; MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); @@ -264,6 +265,9 @@ struct pxa_i2c { u32 hs_mask; struct i2c_bus_recovery_info recovery; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_default; + struct pinctrl_state *pinctrl_recovery; }; #define _IBMR(i2c) ((i2c)->reg_ibmr) @@ -320,6 +324,7 @@ static void decode_ISR(unsigned int val) decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val); } +#ifdef CONFIG_I2C_PXA_SLAVE static const struct bits icr_bits[] = { PXA_BIT(ICR_START, "START", NULL), PXA_BIT(ICR_STOP, "STOP", NULL), @@ -338,7 +343,6 @@ static const struct bits icr_bits[] = { PXA_BIT(ICR_UR, "UR", "ur"), }; -#ifdef CONFIG_I2C_PXA_SLAVE static void decode_ICR(unsigned int val) { decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val); @@ -822,7 +826,7 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c) { u32 icr; - long timeout; + long time_left; spin_lock_irq(&i2c->lock); i2c->highmode_enter = true; @@ -833,12 +837,12 @@ static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c) writel(icr, _ICR(i2c)); spin_unlock_irq(&i2c->lock); - timeout = wait_event_timeout(i2c->wait, - i2c->highmode_enter == false, HZ * 1); + time_left = wait_event_timeout(i2c->wait, + i2c->highmode_enter == false, HZ * 1); i2c->highmode_enter = false; - return (timeout == 0) ? I2C_RETRY : 0; + return (time_left == 0) ? I2C_RETRY : 0; } /* @@ -1046,7 +1050,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) */ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) { - long timeout; + long time_left; int ret; /* @@ -1091,7 +1095,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) /* * The rest of the processing occurs in the interrupt handler. */ - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); + time_left = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); i2c_pxa_stop_message(i2c); /* @@ -1099,7 +1103,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) */ ret = i2c->msg_idx; - if (!timeout && i2c->msg_num) { + if (!time_left && i2c->msg_num) { i2c_pxa_scream_blue_murder(i2c, "timeout with active message"); i2c_recover_bus(&i2c->adap); ret = I2C_RETRY; @@ -1150,11 +1154,11 @@ static u32 i2c_pxa_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm i2c_pxa_algorithm = { - .master_xfer = i2c_pxa_xfer, - .functionality = i2c_pxa_functionality, + .xfer = i2c_pxa_xfer, + .functionality = i2c_pxa_functionality, #ifdef CONFIG_I2C_PXA_SLAVE - .reg_slave = i2c_pxa_slave_reg, - .unreg_slave = i2c_pxa_slave_unreg, + .reg_slave = i2c_pxa_slave_reg, + .unreg_slave = i2c_pxa_slave_unreg, #endif }; @@ -1240,11 +1244,11 @@ static int i2c_pxa_pio_xfer(struct i2c_adapter *adap, } static const struct i2c_algorithm i2c_pxa_pio_algorithm = { - .master_xfer = i2c_pxa_pio_xfer, - .functionality = i2c_pxa_functionality, + .xfer = i2c_pxa_pio_xfer, + .functionality = i2c_pxa_functionality, #ifdef CONFIG_I2C_PXA_SLAVE - .reg_slave = i2c_pxa_slave_reg, - .unreg_slave = i2c_pxa_slave_unreg, + .reg_slave = i2c_pxa_slave_reg, + .unreg_slave = i2c_pxa_slave_unreg, #endif }; @@ -1252,21 +1256,17 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, enum pxa_i2c_types *i2c_types) { struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(i2c_pxa_dt_ids, &pdev->dev); - if (!of_id) + if (!pdev->dev.of_node) return 1; /* For device tree we always use the dynamic or alias-assigned ID */ i2c->adap.nr = -1; - if (of_get_property(np, "mrvl,i2c-polling", NULL)) - i2c->use_pio = 1; - if (of_get_property(np, "mrvl,i2c-fast-mode", NULL)) - i2c->fast_mode = 1; + i2c->use_pio = of_property_read_bool(np, "mrvl,i2c-polling"); + i2c->fast_mode = of_property_read_bool(np, "mrvl,i2c-fast-mode"); - *i2c_types = (enum pxa_i2c_types)(of_id->data); + *i2c_types = (enum pxa_i2c_types)device_get_match_data(&pdev->dev); return 0; } @@ -1302,12 +1302,13 @@ static void i2c_pxa_prepare_recovery(struct i2c_adapter *adap) */ gpiod_set_value(i2c->recovery.scl_gpiod, ibmr & IBMR_SCLS); gpiod_set_value(i2c->recovery.sda_gpiod, ibmr & IBMR_SDAS); + + WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery)); } static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap) { struct pxa_i2c *i2c = adap->algo_data; - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; u32 isr; /* @@ -1321,7 +1322,7 @@ static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap) i2c_pxa_do_reset(i2c); } - WARN_ON(pinctrl_select_state(bri->pinctrl, bri->pins_default)); + WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default)); dev_dbg(&i2c->adap.dev, "recovery: IBMR 0x%08x ISR 0x%08x\n", readl(_IBMR(i2c)), readl(_ISR(i2c))); @@ -1343,20 +1344,76 @@ static int i2c_pxa_init_recovery(struct pxa_i2c *i2c) if (IS_ENABLED(CONFIG_I2C_PXA_SLAVE)) return 0; - bri->pinctrl = devm_pinctrl_get(dev); - if (PTR_ERR(bri->pinctrl) == -ENODEV) { - bri->pinctrl = NULL; + i2c->pinctrl = devm_pinctrl_get(dev); + if (PTR_ERR(i2c->pinctrl) == -ENODEV) + i2c->pinctrl = NULL; + if (IS_ERR(i2c->pinctrl)) + return PTR_ERR(i2c->pinctrl); + + if (!i2c->pinctrl) + return 0; + + i2c->pinctrl_default = pinctrl_lookup_state(i2c->pinctrl, + PINCTRL_STATE_DEFAULT); + i2c->pinctrl_recovery = pinctrl_lookup_state(i2c->pinctrl, "recovery"); + + if (IS_ERR(i2c->pinctrl_default) || IS_ERR(i2c->pinctrl_recovery)) { + dev_info(dev, "missing pinmux recovery information: %ld %ld\n", + PTR_ERR(i2c->pinctrl_default), + PTR_ERR(i2c->pinctrl_recovery)); + return 0; + } + + /* + * Claiming GPIOs can influence the pinmux state, and may glitch the + * I2C bus. Do this carefully. + */ + bri->scl_gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN); + if (bri->scl_gpiod == ERR_PTR(-EPROBE_DEFER)) + return -EPROBE_DEFER; + if (IS_ERR(bri->scl_gpiod)) { + dev_info(dev, "missing scl gpio recovery information: %pe\n", + bri->scl_gpiod); + return 0; + } + + /* + * We have SCL. Pull SCL low and wait a bit so that SDA glitches + * have no effect. + */ + gpiod_direction_output(bri->scl_gpiod, 0); + udelay(10); + bri->sda_gpiod = devm_gpiod_get(dev, "sda", GPIOD_OUT_HIGH_OPEN_DRAIN); + + /* Wait a bit in case of a SDA glitch, and then release SCL. */ + udelay(10); + gpiod_direction_output(bri->scl_gpiod, 1); + + if (bri->sda_gpiod == ERR_PTR(-EPROBE_DEFER)) + return -EPROBE_DEFER; + + if (IS_ERR(bri->sda_gpiod)) { + dev_info(dev, "missing sda gpio recovery information: %pe\n", + bri->sda_gpiod); return 0; } - if (IS_ERR(bri->pinctrl)) - return PTR_ERR(bri->pinctrl); bri->prepare_recovery = i2c_pxa_prepare_recovery; bri->unprepare_recovery = i2c_pxa_unprepare_recovery; + bri->recover_bus = i2c_generic_scl_recovery; i2c->adap.bus_recovery_info = bri; - return 0; + /* + * Claiming GPIOs can change the pinmux state, which confuses the + * pinctrl since pinctrl's idea of the current setting is unaffected + * by the pinmux change caused by claiming the GPIO. Work around that + * by switching pinctrl to the GPIO state here. We do it this way to + * avoid glitching the I2C bus. + */ + pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery); + + return pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default); } static int i2c_pxa_probe(struct platform_device *dev) @@ -1364,7 +1421,7 @@ static int i2c_pxa_probe(struct platform_device *dev) struct i2c_pxa_platform_data *plat = dev_get_platdata(&dev->dev); enum pxa_i2c_types i2c_type; struct pxa_i2c *i2c; - struct resource *res = NULL; + struct resource *res; int ret, irq; i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL); @@ -1381,8 +1438,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.dev.of_node = dev->dev.of_node; #endif - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - i2c->reg_base = devm_ioremap_resource(&dev->dev, res); + i2c->reg_base = devm_platform_get_and_ioremap_resource(dev, 0, &res); if (IS_ERR(i2c->reg_base)) return PTR_ERR(i2c->reg_base); @@ -1403,13 +1459,12 @@ static int i2c_pxa_probe(struct platform_device *dev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - strlcpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); + strscpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); i2c->clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(i2c->clk)) { - dev_err(&dev->dev, "failed to get the clk: %ld\n", PTR_ERR(i2c->clk)); - return PTR_ERR(i2c->clk); - } + if (IS_ERR(i2c->clk)) + return dev_err_probe(&dev->dev, PTR_ERR(i2c->clk), + "failed to get the clk\n"); i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr; i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; @@ -1448,7 +1503,10 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.name); } - clk_prepare_enable(i2c->clk); + ret = clk_prepare_enable(i2c->clk); + if (ret) + return dev_err_probe(&dev->dev, ret, + "failed to enable clock\n"); if (i2c->use_pio) { i2c->adap.algo = &i2c_pxa_pio_algorithm; @@ -1484,18 +1542,15 @@ ereqirq: return ret; } -static int i2c_pxa_remove(struct platform_device *dev) +static void i2c_pxa_remove(struct platform_device *dev) { struct pxa_i2c *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); clk_disable_unprepare(i2c->clk); - - return 0; } -#ifdef CONFIG_PM static int i2c_pxa_suspend_noirq(struct device *dev) { struct pxa_i2c *i2c = dev_get_drvdata(dev); @@ -1520,17 +1575,12 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = { .resume_noirq = i2c_pxa_resume_noirq, }; -#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops) -#else -#define I2C_PXA_DEV_PM_OPS NULL -#endif - static struct platform_driver i2c_pxa_driver = { .probe = i2c_pxa_probe, .remove = i2c_pxa_remove, .driver = { .name = "pxa2xx-i2c", - .pm = I2C_PXA_DEV_PM_OPS, + .pm = pm_sleep_ptr(&i2c_pxa_dev_pm_ops), .of_match_table = i2c_pxa_dt_ids, }, .id_table = i2c_pxa_id_table, @@ -1546,8 +1596,8 @@ static void __exit i2c_adap_pxa_exit(void) platform_driver_unregister(&i2c_pxa_driver); } +MODULE_DESCRIPTION("Intel PXA2XX I2C adapter"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-i2c"); subsys_initcall(i2c_adap_pxa_init); module_exit(i2c_adap_pxa_exit); |
