diff options
Diffstat (limited to 'drivers/i2c')
53 files changed, 1654 insertions, 926 deletions
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 1147bddb8b2c..3df0efd69ae3 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -649,6 +649,11 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, if (bit_adap->getscl == NULL) adap->quirks = &i2c_bit_quirk_no_clk_stretch; + /* Bring bus to a known state. Looks like STOP if bus is not free yet */ + setscl(bit_adap, 1); + udelay(bit_adap->udelay); + setsda(bit_adap, 1); + ret = add_adapter(adap); if (ret < 0) return ret; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 45a3f3ca29b3..e2954fb86d65 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -123,8 +123,10 @@ config I2C_I801 Wildcat Point (PCH) Wildcat Point-LP (PCH) BayTrail (SOC) + Braswell (SOC) Sunrise Point-H (PCH) Sunrise Point-LP (PCH) + Kaby Lake-H (PCH) DNV (SOC) Broxton (SOC) Lewisburg (PCH) @@ -198,6 +200,11 @@ config I2C_CHT_WC SMBus controller found in the Intel Cherry Trail Whiskey Cove PMIC found on some Intel Cherry Trail systems. + Note this controller is hooked up to a TI bq24292i charger-IC, + combined with a FUSB302 Type-C port-controller as such it is advised + to also select CONFIG_CHARGER_BQ24190=m and CONFIG_TYPEC_FUSB302=m + (the fusb302 driver currently is in drivers/staging). + config I2C_NFORCE2 tristate "Nvidia nForce2, nForce3 and nForce4" depends on PCI @@ -598,6 +605,14 @@ config I2C_GPIO This is a very simple bitbanging I2C driver utilizing the arch-neutral GPIO API to control the SCL and SDA lines. +config I2C_GPIO_FAULT_INJECTOR + bool "GPIO-based fault injector" + depends on I2C_GPIO + help + This adds some functionality to the i2c-gpio driver which can inject + faults to an I2C bus, so another bus master can be stress-tested. + This is for debugging. If unsure, say 'no'. + config I2C_HIGHLANDER tristate "Highlander FPGA SMBus interface" depends on SH_HIGHLANDER diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c index 9d7be5af2bf2..f4a5ae69bf6a 100644 --- a/drivers/i2c/busses/i2c-acorn.c +++ b/drivers/i2c/busses/i2c-acorn.c @@ -1,5 +1,5 @@ /* - * linux/drivers/acorn/char/i2c.c + * ARM IOC/IOMD i2c driver. * * Copyright (C) 2000 Russell King * @@ -7,8 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * ARM IOC/IOMD i2c driver. - * * On Acorn machines, the following i2c devices are on the bus: * - PCF8583 real time clock & static RAM */ @@ -94,3 +92,7 @@ static int __init i2c_ioc_init(void) } module_init(i2c_ioc_init); + +MODULE_AUTHOR("Russell King <[email protected]>"); +MODULE_DESCRIPTION("ARM IOC/IOMD i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 284f8670dbeb..7d4aeb4465b3 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -27,6 +27,7 @@ #include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/slab.h> /* I2C Register */ @@ -132,6 +133,7 @@ struct aspeed_i2c_bus { struct i2c_adapter adap; struct device *dev; void __iomem *base; + struct reset_control *rst; /* Synchronizes I/O mem access to base. */ spinlock_t lock; struct completion cmd_complete; @@ -847,6 +849,14 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) /* We just need the clock rate, we don't actually use the clk object. */ devm_clk_put(&pdev->dev, parent_clk); + bus->rst = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(bus->rst)) { + dev_err(&pdev->dev, + "missing or invalid reset controller device tree entry"); + return PTR_ERR(bus->rst); + } + reset_control_deassert(bus->rst); + ret = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &bus->bus_frequency); if (ret < 0) { @@ -917,6 +927,8 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev) spin_unlock_irqrestore(&bus->lock, flags); + reset_control_assert(bus->rst); + i2c_del_adapter(&bus->adap); return 0; diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index cd07a69e2e93..44deae78913e 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -50,6 +50,9 @@ #define BCM2835_I2C_S_CLKT BIT(9) #define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */ +#define BCM2835_I2C_FEDL_SHIFT 16 +#define BCM2835_I2C_REDL_SHIFT 0 + #define BCM2835_I2C_CDIV_MIN 0x0002 #define BCM2835_I2C_CDIV_MAX 0xFFFE @@ -81,7 +84,7 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg) static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) { - u32 divider; + u32 divider, redl, fedl; divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), i2c_dev->bus_clk_rate); @@ -100,6 +103,22 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); + /* + * Number of core clocks to wait after falling edge before + * outputting the next data bit. Note that both FEDL and REDL + * can't be greater than CDIV/2. + */ + fedl = max(divider / 16, 1u); + + /* + * Number of core clocks to wait after rising edge before + * sampling the next incoming data bit. + */ + redl = max(divider / 4, 1u); + + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL, + (fedl << BCM2835_I2C_FEDL_SHIFT) | + (redl << BCM2835_I2C_REDL_SHIFT)); return 0; } diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c index 190bbbc7bfee..44cffad43701 100644 --- a/drivers/i2c/busses/i2c-cht-wc.c +++ b/drivers/i2c/busses/i2c-cht-wc.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include <linux/acpi.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/i2c.h> @@ -25,6 +26,7 @@ #include <linux/mfd/intel_soc_pmic.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/power/bq24190_charger.h> #include <linux/slab.h> #define CHT_WC_I2C_CTRL 0x5e24 @@ -232,13 +234,35 @@ static const struct irq_chip cht_wc_i2c_irq_chip = { .name = "cht_wc_ext_chrg_irq_chip", }; +static const char * const bq24190_suppliers[] = { "fusb302-typec-source" }; + static const struct property_entry bq24190_props[] = { - PROPERTY_ENTRY_STRING("extcon-name", "cht_wcove_pwrsrc"), + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers), PROPERTY_ENTRY_BOOL("omit-battery-class"), PROPERTY_ENTRY_BOOL("disable-reset"), { } }; +static struct regulator_consumer_supply fusb302_consumer = { + .supply = "vbus", + /* Must match fusb302 dev_name in intel_cht_int33fe.c */ + .dev_name = "i2c-fusb302", +}; + +static const struct regulator_init_data bq24190_vbus_init_data = { + .constraints = { + /* The name is used in intel_cht_int33fe.c do not change. */ + .name = "cht_wc_usb_typec_vbus", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = &fusb302_consumer, + .num_consumer_supplies = 1, +}; + +static struct bq24190_platform_data bq24190_pdata = { + .regulator_init_data = &bq24190_vbus_init_data, +}; + static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); @@ -246,7 +270,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) struct i2c_board_info board_info = { .type = "bq24190", .addr = 0x6b, + .dev_name = "bq24190", .properties = bq24190_props, + .platform_data = &bq24190_pdata, }; int ret, reg, irq; @@ -314,11 +340,21 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) if (ret) goto remove_irq_domain; - board_info.irq = adap->client_irq; - adap->client = i2c_new_device(&adap->adapter, &board_info); - if (!adap->client) { - ret = -ENOMEM; - goto del_adapter; + /* + * Normally the Whiskey Cove PMIC is paired with a TI bq24292i charger, + * connected to this i2c bus, and a max17047 fuel-gauge and a fusb302 + * USB Type-C controller connected to another i2c bus. In this setup + * the max17047 and fusb302 devices are enumerated through an INT33FE + * ACPI device. If this device is present register an i2c-client for + * the TI bq24292i charger. + */ + if (acpi_dev_present("INT33FE", NULL, -1)) { + board_info.irq = adap->client_irq; + adap->client = i2c_new_device(&adap->adapter, &board_info); + if (!adap->client) { + ret = -ENOMEM; + goto del_adapter; + } } platform_set_drvdata(pdev, adap); @@ -335,14 +371,15 @@ static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev) { struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev); - i2c_unregister_device(adap->client); + if (adap->client) + i2c_unregister_device(adap->client); i2c_del_adapter(&adap->adapter); irq_domain_remove(adap->irq_domain); return 0; } -static struct platform_device_id cht_wc_i2c_adap_id_table[] = { +static const struct platform_device_id cht_wc_i2c_adap_id_table[] = { { .name = "cht_wcove_ext_chgr" }, {}, }; diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index b8c43535f16c..75d6ab177055 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -33,9 +33,10 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/cpufreq.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of_device.h> #include <linux/platform_data/i2c-davinci.h> +#include <linux/pm_runtime.h> /* ----- global defines ----------------------------------------------- */ @@ -122,6 +123,9 @@ /* set the SDA GPIO low */ #define DAVINCI_I2C_DCLR_PDCLR1 BIT(1) +/* timeout for pm runtime autosuspend */ +#define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */ + struct davinci_i2c_dev { struct device *dev; void __iomem *base; @@ -135,7 +139,6 @@ struct davinci_i2c_dev { u8 terminate; struct i2c_adapter adapter; #ifdef CONFIG_CPU_FREQ - struct completion xfr_complete; struct notifier_block freq_transition; #endif struct davinci_i2c_platform_data *pdata; @@ -290,7 +293,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) } /* - * This routine does i2c bus recovery by using i2c_generic_gpio_recovery + * This routine does i2c bus recovery by using i2c_generic_scl_recovery * which is provided by I2C Bus recovery infrastructure. */ static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap) @@ -312,7 +315,7 @@ static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap) } static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = { - .recover_bus = i2c_generic_gpio_recovery, + .recover_bus = i2c_generic_scl_recovery, .prepare_recovery = davinci_i2c_prepare_recovery, .unprepare_recovery = davinci_i2c_unprepare_recovery, }; @@ -500,7 +503,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) /* This should be 0 if all bytes were transferred * or dev->cmd_err denotes an error. */ - dev_err(dev->dev, "abnormal termination buf_len=%i\n", + dev_err(dev->dev, "abnormal termination buf_len=%zu\n", dev->buf_len); dev->terminate = 1; wmb(); @@ -541,10 +544,17 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); + ret = pm_runtime_get_sync(dev->dev); + if (ret < 0) { + dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret); + pm_runtime_put_noidle(dev->dev); + return ret; + } + ret = i2c_davinci_wait_bus_not_busy(dev); if (ret < 0) { dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return ret; + goto out; } for (i = 0; i < num; i++) { @@ -552,14 +562,16 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num, ret); if (ret < 0) - return ret; + goto out; } -#ifdef CONFIG_CPU_FREQ - complete(&dev->xfr_complete); -#endif + ret = num; + +out: + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); - return num; + return ret; } static u32 i2c_davinci_func(struct i2c_adapter *adap) @@ -599,6 +611,9 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) int count = 0; u16 w; + if (pm_runtime_suspended(dev->dev)) + return IRQ_NONE; + while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) { dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); if (count++ == 100) { @@ -698,13 +713,15 @@ static int i2c_davinci_cpufreq_transition(struct notifier_block *nb, struct davinci_i2c_dev *dev; dev = container_of(nb, struct davinci_i2c_dev, freq_transition); + + i2c_lock_adapter(&dev->adapter); if (val == CPUFREQ_PRECHANGE) { - wait_for_completion(&dev->xfr_complete); davinci_i2c_reset_ctrl(dev, 0); } else if (val == CPUFREQ_POSTCHANGE) { i2c_davinci_calc_clk_dividers(dev); davinci_i2c_reset_ctrl(dev, 1); } + i2c_unlock_adapter(&dev->adapter); return 0; } @@ -750,6 +767,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) struct davinci_i2c_dev *dev; struct i2c_adapter *adap; struct resource *mem; + struct i2c_bus_recovery_info *rinfo; int r, irq; irq = platform_get_irq(pdev, 0); @@ -770,9 +788,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) } init_completion(&dev->cmd_complete); -#ifdef CONFIG_CPU_FREQ - init_completion(&dev->xfr_complete); -#endif + dev->dev = &pdev->dev; dev->irq = irq; dev->pdata = dev_get_platdata(&pdev->dev); @@ -802,13 +818,24 @@ static int davinci_i2c_probe(struct platform_device *pdev) dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return PTR_ERR(dev->clk); - clk_prepare_enable(dev->clk); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(dev->base)) { - r = PTR_ERR(dev->base); - goto err_unuse_clocks; + return PTR_ERR(dev->base); + } + + pm_runtime_set_autosuspend_delay(dev->dev, + DAVINCI_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(dev->dev); + + pm_runtime_enable(dev->dev); + + r = pm_runtime_get_sync(dev->dev); + if (r < 0) { + dev_err(dev->dev, "failed to runtime_get device: %d\n", r); + pm_runtime_put_noidle(dev->dev); + return r; } i2c_davinci_init(dev); @@ -838,10 +865,20 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (dev->pdata->has_pfunc) adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; - else if (dev->pdata->scl_pin) { - adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info; - adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin; - adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin; + else if (dev->pdata->gpio_recovery) { + rinfo = &davinci_i2c_gpio_recovery_info; + adap->bus_recovery_info = rinfo; + rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", + GPIOD_OUT_HIGH_OPEN_DRAIN); + if (IS_ERR(rinfo->scl_gpiod)) { + r = PTR_ERR(rinfo->scl_gpiod); + goto err_unuse_clocks; + } + rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); + if (IS_ERR(rinfo->sda_gpiod)) { + r = PTR_ERR(rinfo->sda_gpiod); + goto err_unuse_clocks; + } } adap->nr = pdev->id; @@ -849,27 +886,40 @@ static int davinci_i2c_probe(struct platform_device *pdev) if (r) goto err_unuse_clocks; + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + return 0; err_unuse_clocks: - clk_disable_unprepare(dev->clk); - dev->clk = NULL; + pm_runtime_dont_use_autosuspend(dev->dev); + pm_runtime_put_sync(dev->dev); + pm_runtime_disable(dev->dev); + return r; } static int davinci_i2c_remove(struct platform_device *pdev) { struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); + int ret; i2c_davinci_cpufreq_deregister(dev); i2c_del_adapter(&dev->adapter); - clk_disable_unprepare(dev->clk); - dev->clk = NULL; + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&pdev->dev); + return ret; + } davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); + pm_runtime_dont_use_autosuspend(dev->dev); + pm_runtime_put_sync(dev->dev); + pm_runtime_disable(dev->dev); + return 0; } @@ -880,7 +930,6 @@ static int davinci_i2c_suspend(struct device *dev) /* put I2C into reset */ davinci_i2c_reset_ctrl(i2c_dev, 0); - clk_disable_unprepare(i2c_dev->clk); return 0; } @@ -889,7 +938,6 @@ static int davinci_i2c_resume(struct device *dev) { struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev); - clk_prepare_enable(i2c_dev->clk); /* take I2C out of reset */ davinci_i2c_reset_ctrl(i2c_dev, 1); @@ -899,6 +947,8 @@ static int davinci_i2c_resume(struct device *dev) static const struct dev_pm_ops davinci_i2c_pm = { .suspend = davinci_i2c_suspend, .resume = davinci_i2c_resume, + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; #define davinci_i2c_pm_ops (&davinci_i2c_pm) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index d1a69372432f..27ebd90de43b 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -21,6 +21,7 @@ * ---------------------------------------------------------------------------- * */ +#include <linux/clk.h> #include <linux/delay.h> #include <linux/export.h> #include <linux/errno.h> @@ -185,6 +186,19 @@ unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } +int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare) +{ + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + + if (prepare) + return clk_prepare_enable(dev->clk); + + clk_disable_unprepare(dev->clk); + return 0; +} +EXPORT_SYMBOL_GPL(i2c_dw_prepare_clk); + int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) { int ret; @@ -217,7 +231,11 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { if (timeout <= 0) { dev_warn(dev->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; + i2c_recover_bus(&dev->adapter); + + if (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) + return -ETIMEDOUT; + return 0; } timeout--; usleep_range(1000, 1100); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 9fee4c054d3d..8707c76b2fee 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -284,6 +284,7 @@ struct dw_i2c_dev { void (*disable_int)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); int mode; + struct i2c_bus_recovery_info rinfo; }; #define ACCESS_SWAP 0x00000001 @@ -299,6 +300,7 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable); void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable); unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); +int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); void i2c_dw_release_lock(struct dw_i2c_dev *dev); int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 418c233075d3..05732531829f 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -25,11 +25,13 @@ #include <linux/err.h> #include <linux/errno.h> #include <linux/export.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include "i2c-designware-core.h" @@ -207,7 +209,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) i2c_dw_disable_int(dev); /* Enable the adapter */ - __i2c_dw_enable(dev, true); + __i2c_dw_enable_and_wait(dev, true); /* Clear and enable interrupts */ dw_readl(dev, DW_IC_CLR_INTR); @@ -443,6 +445,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ + i2c_recover_bus(&dev->adapter); i2c_dw_init_master(dev); ret = -ETIMEDOUT; goto done; @@ -613,6 +616,56 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) return IRQ_HANDLED; } +static void i2c_dw_prepare_recovery(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_dw_disable(dev); + reset_control_assert(dev->rst); + i2c_dw_prepare_clk(dev, false); +} + +static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + + i2c_dw_prepare_clk(dev, true); + reset_control_deassert(dev->rst); + i2c_dw_init_master(dev); +} + +static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) +{ + struct i2c_bus_recovery_info *rinfo = &dev->rinfo; + struct i2c_adapter *adap = &dev->adapter; + struct gpio_desc *gpio; + int r; + + gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH); + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); + if (r == -ENOENT || r == -ENOSYS) + return 0; + return r; + } + rinfo->scl_gpiod = gpio; + + gpio = devm_gpiod_get_optional(dev->dev, "sda", GPIOD_IN); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + rinfo->sda_gpiod = gpio; + + rinfo->recover_bus = i2c_generic_scl_recovery; + rinfo->prepare_recovery = i2c_dw_prepare_recovery; + rinfo->unprepare_recovery = i2c_dw_unprepare_recovery; + adap->bus_recovery_info = rinfo; + + dev_info(dev->dev, "running with gpio recovery mode! scl%s", + rinfo->sda_gpiod ? ",sda" : ""); + + return 0; +} + int i2c_dw_probe(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; @@ -652,6 +705,10 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) return ret; } + ret = i2c_dw_init_recovery_info(dev); + if (ret) + return ret; + /* * Increment PM usage count during adapter registration in order to * avoid possible spurious runtime suspend when adapter device is diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 0e65b97842b4..5660daf6c92e 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -42,6 +42,7 @@ #include <linux/reset.h> #include <linux/sched.h> #include <linux/slab.h> +#include <linux/suspend.h> #include "i2c-designware-core.h" @@ -201,29 +202,6 @@ static void i2c_dw_configure_slave(struct dw_i2c_dev *dev) DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED; dev->mode = DW_IC_SLAVE; - - switch (dev->clk_freq) { - case 100000: - dev->slave_cfg |= DW_IC_CON_SPEED_STD; - break; - case 3400000: - dev->slave_cfg |= DW_IC_CON_SPEED_HIGH; - break; - default: - dev->slave_cfg |= DW_IC_CON_SPEED_FAST; - } -} - -static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) -{ - if (IS_ERR(i_dev->clk)) - return PTR_ERR(i_dev->clk); - - if (prepare) - return clk_prepare_enable(i_dev->clk); - - clk_disable_unprepare(i_dev->clk); - return 0; } static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id) @@ -249,6 +227,14 @@ static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id) } } +static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev) +{ + pm_runtime_disable(dev->dev); + + if (dev->pm_disabled) + pm_runtime_put_noidle(dev->dev); +} + static int dw_i2c_plat_probe(struct platform_device *pdev) { struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -257,7 +243,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) u32 acpi_speed, ht = 0; struct resource *mem; int i, irq, ret; - const int supported_speeds[] = { 0, 100000, 400000, 1000000, 3400000 }; + static const int supported_speeds[] = { + 0, 100000, 400000, 1000000, 3400000 + }; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -345,7 +333,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) i2c_dw_configure_master(dev); dev->clk = devm_clk_get(&pdev->dev, NULL); - if (!i2c_dw_plat_prepare_clk(dev, true)) { + if (!i2c_dw_prepare_clk(dev, true)) { dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; if (!dev->sda_hold_time && ht) @@ -362,14 +350,22 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->dev.of_node = pdev->dev.of_node; - if (dev->pm_disabled) { - pm_runtime_forbid(&pdev->dev); - } else { - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - } + dev_pm_set_driver_flags(&pdev->dev, + DPM_FLAG_SMART_PREPARE | + DPM_FLAG_SMART_SUSPEND | + DPM_FLAG_LEAVE_SUSPENDED); + + /* The code below assumes runtime PM to be disabled. */ + WARN_ON(pm_runtime_enabled(&pdev->dev)); + + pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + + if (dev->pm_disabled) + pm_runtime_get_noresume(&pdev->dev); + + pm_runtime_enable(&pdev->dev); if (dev->mode == DW_IC_SLAVE) ret = i2c_dw_probe_slave(dev); @@ -382,8 +378,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) return ret; exit_probe: - if (!dev->pm_disabled) - pm_runtime_disable(&pdev->dev); + dw_i2c_plat_pm_cleanup(dev); exit_reset: if (!IS_ERR_OR_NULL(dev->rst)) reset_control_assert(dev->rst); @@ -402,8 +397,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); - if (!dev->pm_disabled) - pm_runtime_disable(&pdev->dev); + dw_i2c_plat_pm_cleanup(dev); + if (!IS_ERR_OR_NULL(dev->rst)) reset_control_assert(dev->rst); @@ -423,12 +418,24 @@ MODULE_DEVICE_TABLE(of, dw_i2c_of_match); #ifdef CONFIG_PM_SLEEP static int dw_i2c_plat_prepare(struct device *dev) { - return pm_runtime_suspended(dev); + /* + * If the ACPI companion device object is present for this device, it + * may be accessed during suspend and resume of other devices via I2C + * operation regions, so tell the PM core and middle layers to avoid + * skipping system suspend/resume callbacks for it in that case. + */ + return !has_acpi_companion(dev); } static void dw_i2c_plat_complete(struct device *dev) { - if (dev->power.direct_complete) + /* + * The device can only be in runtime suspend at this point if it has not + * been resumed throughout the ending system suspend/resume cycle, so if + * the platform firmware might mess up with it, request the runtime PM + * framework to resume it. + */ + if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) pm_request_resume(dev); } #else @@ -437,12 +444,12 @@ static void dw_i2c_plat_complete(struct device *dev) #endif #ifdef CONFIG_PM -static int dw_i2c_plat_runtime_suspend(struct device *dev) +static int dw_i2c_plat_suspend(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); i_dev->disable(i_dev); - i2c_dw_plat_prepare_clk(i_dev, false); + i2c_dw_prepare_clk(i_dev, false); return 0; } @@ -451,27 +458,17 @@ static int dw_i2c_plat_resume(struct device *dev) { struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - i2c_dw_plat_prepare_clk(i_dev, true); + i2c_dw_prepare_clk(i_dev, true); i_dev->init(i_dev); return 0; } -#ifdef CONFIG_PM_SLEEP -static int dw_i2c_plat_suspend(struct device *dev) -{ - pm_runtime_resume(dev); - return dw_i2c_plat_runtime_suspend(dev); -} -#endif - static const struct dev_pm_ops dw_i2c_dev_pm_ops = { .prepare = dw_i2c_plat_prepare, .complete = dw_i2c_plat_complete, - SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) - SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, - dw_i2c_plat_resume, - NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) + SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL) }; #define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops) diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index ea9578ab19a1..d42558d1b002 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -51,9 +51,7 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) */ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) { - u32 sda_falling_time, scl_falling_time; u32 reg, comp_param1; - u32 hcnt, lcnt; int ret; ret = i2c_dw_acquire_lock(dev); @@ -79,68 +77,6 @@ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) /* Disable the adapter. */ __i2c_dw_enable_and_wait(dev, false); - /* Set standard and fast speed deviders for high/low periods. */ - sda_falling_time = dev->sda_falling_time ?: 300; /* ns */ - scl_falling_time = dev->scl_falling_time ?: 300; /* ns */ - - /* Set SCL timing parameters for standard-mode. */ - if (dev->ss_hcnt && dev->ss_lcnt) { - hcnt = dev->ss_hcnt; - lcnt = dev->ss_lcnt; - } else { - hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), - 4000, /* tHD;STA = tHIGH = 4.0 us */ - sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ - 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), - 4700, /* tLOW = 4.7 us */ - scl_falling_time, - 0); /* No offset */ - } - dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); - dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - - /* Set SCL timing parameters for fast-mode or fast-mode plus. */ - if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) { - hcnt = dev->fp_hcnt; - lcnt = dev->fp_lcnt; - } else if (dev->fs_hcnt && dev->fs_lcnt) { - hcnt = dev->fs_hcnt; - lcnt = dev->fs_lcnt; - } else { - hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev), - 600, /* tHD;STA = tHIGH = 0.6 us */ - sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ - 0); /* No offset */ - lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev), - 1300, /* tLOW = 1.3 us */ - scl_falling_time, - 0); /* No offset */ - } - dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); - dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - - if ((dev->slave_cfg & DW_IC_CON_SPEED_MASK) == - DW_IC_CON_SPEED_HIGH) { - if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) - != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) { - dev_err(dev->dev, "High Speed not supported!\n"); - dev->slave_cfg &= ~DW_IC_CON_SPEED_MASK; - dev->slave_cfg |= DW_IC_CON_SPEED_FAST; - } else if (dev->hs_hcnt && dev->hs_lcnt) { - hcnt = dev->hs_hcnt; - lcnt = dev->hs_lcnt; - dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT); - dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT); - dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n", - hcnt, lcnt); - } - } - /* Configure SDA Hold Time if required. */ reg = dw_readl(dev, DW_IC_COMP_VERSION); if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 3855e0b11877..b02428498f6d 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -170,7 +170,7 @@ #define HSI2C_HS_TX_CLOCK 1000000 #define HSI2C_FS_TX_CLOCK 100000 -#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000)) +#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(100)) #define HSI2C_EXYNOS7 BIT(0) diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 0ef8fcc6ac3a..58abb3eced58 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -7,6 +7,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/debugfs.h> +#include <linux/delay.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> #include <linux/i2c-gpio.h> @@ -14,27 +16,20 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of.h> -#include <linux/of_gpio.h> struct i2c_gpio_private_data { + struct gpio_desc *sda; + struct gpio_desc *scl; struct i2c_adapter adap; struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR + struct dentry *debug_dir; +#endif }; -/* Toggle SDA by changing the direction of the pin */ -static void i2c_gpio_setsda_dir(void *data, int state) -{ - struct i2c_gpio_platform_data *pdata = data; - - if (state) - gpio_direction_input(pdata->sda_pin); - else - gpio_direction_output(pdata->sda_pin, 0); -} - /* * Toggle SDA by changing the output value of the pin. This is only * valid for pins configured as open drain (i.e. setting the value @@ -42,20 +37,9 @@ static void i2c_gpio_setsda_dir(void *data, int state) */ static void i2c_gpio_setsda_val(void *data, int state) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - gpio_set_value(pdata->sda_pin, state); -} - -/* Toggle SCL by changing the direction of the pin. */ -static void i2c_gpio_setscl_dir(void *data, int state) -{ - struct i2c_gpio_platform_data *pdata = data; - - if (state) - gpio_direction_input(pdata->scl_pin); - else - gpio_direction_output(pdata->scl_pin, 0); + gpiod_set_value_cansleep(priv->sda, state); } /* @@ -66,46 +50,127 @@ static void i2c_gpio_setscl_dir(void *data, int state) */ static void i2c_gpio_setscl_val(void *data, int state) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - gpio_set_value(pdata->scl_pin, state); + gpiod_set_value_cansleep(priv->scl, state); } static int i2c_gpio_getsda(void *data) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - return gpio_get_value(pdata->sda_pin); + return gpiod_get_value_cansleep(priv->sda); } static int i2c_gpio_getscl(void *data) { - struct i2c_gpio_platform_data *pdata = data; + struct i2c_gpio_private_data *priv = data; - return gpio_get_value(pdata->scl_pin); + return gpiod_get_value_cansleep(priv->scl); } -static int of_i2c_gpio_get_pins(struct device_node *np, - unsigned int *sda_pin, unsigned int *scl_pin) +#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR +static struct dentry *i2c_gpio_debug_dir; + +#define setsda(bd, val) ((bd)->setsda((bd)->data, val)) +#define setscl(bd, val) ((bd)->setscl((bd)->data, val)) +#define getsda(bd) ((bd)->getsda((bd)->data)) +#define getscl(bd) ((bd)->getscl((bd)->data)) + +#define WIRE_ATTRIBUTE(wire) \ +static int fops_##wire##_get(void *data, u64 *val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_adapter(&priv->adap); \ + *val = get##wire(&priv->bit_data); \ + i2c_unlock_adapter(&priv->adap); \ + return 0; \ +} \ +static int fops_##wire##_set(void *data, u64 val) \ +{ \ + struct i2c_gpio_private_data *priv = data; \ + \ + i2c_lock_adapter(&priv->adap); \ + set##wire(&priv->bit_data, val); \ + i2c_unlock_adapter(&priv->adap); \ + return 0; \ +} \ +DEFINE_DEBUGFS_ATTRIBUTE(fops_##wire, fops_##wire##_get, fops_##wire##_set, "%llu\n") + +WIRE_ATTRIBUTE(scl); +WIRE_ATTRIBUTE(sda); + +static int fops_incomplete_transfer_set(void *data, u64 addr) { - if (of_gpio_count(np) < 2) - return -ENODEV; + struct i2c_gpio_private_data *priv = data; + struct i2c_algo_bit_data *bit_data = &priv->bit_data; + int i, pattern; + + if (addr > 0x7f) + return -EINVAL; + + /* ADDR (7 bit) + RD (1 bit) + SDA hi (1 bit) */ + pattern = (addr << 2) | 3; + + i2c_lock_adapter(&priv->adap); + + /* START condition */ + setsda(bit_data, 0); + udelay(bit_data->udelay); + + /* Send ADDR+RD, request ACK, don't send STOP */ + for (i = 8; i >= 0; i--) { + setscl(bit_data, 0); + udelay(bit_data->udelay / 2); + setsda(bit_data, (pattern >> i) & 1); + udelay((bit_data->udelay + 1) / 2); + setscl(bit_data, 1); + udelay(bit_data->udelay); + } - *sda_pin = of_get_gpio(np, 0); - *scl_pin = of_get_gpio(np, 1); + i2c_unlock_adapter(&priv->adap); - if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER) - return -EPROBE_DEFER; + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_transfer, NULL, fops_incomplete_transfer_set, "%llu\n"); - if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) { - pr_err("%pOF: invalid GPIO pins, sda=%d/scl=%d\n", - np, *sda_pin, *scl_pin); - return -ENODEV; +static void i2c_gpio_fault_injector_init(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + /* + * If there will be a debugfs-dir per i2c adapter somewhen, put the + * 'fault-injector' dir there. Until then, we have a global dir with + * all adapters as subdirs. + */ + if (!i2c_gpio_debug_dir) { + i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); + if (!i2c_gpio_debug_dir) + return; } - return 0; + priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); + if (!priv->debug_dir) + return; + + debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); + debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); + debugfs_create_file_unsafe("incomplete_transfer", 0200, priv->debug_dir, + priv, &fops_incomplete_transfer); } +static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) +{ + struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); + + debugfs_remove_recursive(priv->debug_dir); +} +#else +static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} +static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} +#endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ + static void of_i2c_gpio_get_props(struct device_node *np, struct i2c_gpio_platform_data *pdata) { @@ -124,72 +189,108 @@ static void of_i2c_gpio_get_props(struct device_node *np, of_property_read_bool(np, "i2c-gpio,scl-output-only"); } +static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, + const char *con_id, + unsigned int index, + enum gpiod_flags gflags) +{ + struct gpio_desc *retdesc; + int ret; + + retdesc = devm_gpiod_get(dev, con_id, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from name %s\n", con_id); + return retdesc; + } + + retdesc = devm_gpiod_get_index(dev, NULL, index, gflags); + if (!IS_ERR(retdesc)) { + dev_dbg(dev, "got GPIO from index %u\n", index); + return retdesc; + } + + ret = PTR_ERR(retdesc); + + /* FIXME: hack in the old code, is this really necessary? */ + if (ret == -EINVAL) + retdesc = ERR_PTR(-EPROBE_DEFER); + + /* This happens if the GPIO driver is not yet probed, let's defer */ + if (ret == -ENOENT) + retdesc = ERR_PTR(-EPROBE_DEFER); + + if (ret != -EPROBE_DEFER) + dev_err(dev, "error trying to get descriptor: %d\n", ret); + + return retdesc; +} + static int i2c_gpio_probe(struct platform_device *pdev) { struct i2c_gpio_private_data *priv; struct i2c_gpio_platform_data *pdata; struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; - unsigned int sda_pin, scl_pin; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + enum gpiod_flags gflags; int ret; - /* First get the GPIO pins; if it fails, we'll defer the probe. */ - if (pdev->dev.of_node) { - ret = of_i2c_gpio_get_pins(pdev->dev.of_node, - &sda_pin, &scl_pin); - if (ret) - return ret; - } else { - if (!dev_get_platdata(&pdev->dev)) - return -ENXIO; - pdata = dev_get_platdata(&pdev->dev); - sda_pin = pdata->sda_pin; - scl_pin = pdata->scl_pin; - } - - ret = devm_gpio_request(&pdev->dev, sda_pin, "sda"); - if (ret) { - if (ret == -EINVAL) - ret = -EPROBE_DEFER; /* Try again later */ - return ret; - } - ret = devm_gpio_request(&pdev->dev, scl_pin, "scl"); - if (ret) { - if (ret == -EINVAL) - ret = -EPROBE_DEFER; /* Try again later */ - return ret; - } - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + adap = &priv->adap; bit_data = &priv->bit_data; pdata = &priv->pdata; - if (pdev->dev.of_node) { - pdata->sda_pin = sda_pin; - pdata->scl_pin = scl_pin; - of_i2c_gpio_get_props(pdev->dev.of_node, pdata); + if (np) { + of_i2c_gpio_get_props(np, pdata); } else { - memcpy(pdata, dev_get_platdata(&pdev->dev), sizeof(*pdata)); + /* + * If all platform data settings are zero it is OK + * to not provide any platform data from the board. + */ + if (dev_get_platdata(dev)) + memcpy(pdata, dev_get_platdata(dev), sizeof(*pdata)); } - if (pdata->sda_is_open_drain) { - gpio_direction_output(pdata->sda_pin, 1); - bit_data->setsda = i2c_gpio_setsda_val; - } else { - gpio_direction_input(pdata->sda_pin); - bit_data->setsda = i2c_gpio_setsda_dir; - } + /* + * First get the GPIO pins; if it fails, we'll defer the probe. + * If the SDA line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->sda_is_open_drain) + gflags = GPIOD_OUT_HIGH; + else + gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; + priv->sda = i2c_gpio_get_desc(dev, "sda", 0, gflags); + if (IS_ERR(priv->sda)) + return PTR_ERR(priv->sda); + + /* + * If the SCL line is marked from platform data or device tree as + * "open drain" it means something outside of our control is making + * this line being handled as open drain, and we should just handle + * it as any other output. Else we enforce open drain as this is + * required for an I2C bus. + */ + if (pdata->scl_is_open_drain) + gflags = GPIOD_OUT_LOW; + else + gflags = GPIOD_OUT_LOW_OPEN_DRAIN; + priv->scl = i2c_gpio_get_desc(dev, "scl", 1, gflags); + if (IS_ERR(priv->scl)) + return PTR_ERR(priv->scl); - if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { - gpio_direction_output(pdata->scl_pin, 1); - bit_data->setscl = i2c_gpio_setscl_val; - } else { - gpio_direction_input(pdata->scl_pin); - bit_data->setscl = i2c_gpio_setscl_dir; - } + if (gpiod_cansleep(priv->sda) || gpiod_cansleep(priv->scl)) + dev_warn(dev, "Slow GPIO pins might wreak havoc into I2C/SMBus bus timing"); + + bit_data->setsda = i2c_gpio_setsda_val; + bit_data->setscl = i2c_gpio_setscl_val; if (!pdata->scl_is_output_only) bit_data->getscl = i2c_gpio_getscl; @@ -207,18 +308,18 @@ static int i2c_gpio_probe(struct platform_device *pdev) else bit_data->timeout = HZ / 10; /* 100 ms */ - bit_data->data = pdata; + bit_data->data = priv; adap->owner = THIS_MODULE; - if (pdev->dev.of_node) - strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); + if (np) + strlcpy(adap->name, dev_name(dev), sizeof(adap->name)); else snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); adap->algo_data = bit_data; adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - adap->dev.parent = &pdev->dev; - adap->dev.of_node = pdev->dev.of_node; + adap->dev.parent = dev; + adap->dev.of_node = np; adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); @@ -227,11 +328,18 @@ static int i2c_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); - dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", - pdata->sda_pin, pdata->scl_pin, + /* + * FIXME: using global GPIO numbers is not helpful. If/when we + * get accessors to get the actual name of the GPIO line, + * from the descriptor, then provide that instead. + */ + dev_info(dev, "using lines %u (SDA) and %u (SCL%s)\n", + desc_to_gpio(priv->sda), desc_to_gpio(priv->scl), pdata->scl_is_output_only ? ", no clock stretching" : ""); + i2c_gpio_fault_injector_init(pdev); + return 0; } @@ -240,6 +348,8 @@ static int i2c_gpio_remove(struct platform_device *pdev) struct i2c_gpio_private_data *priv; struct i2c_adapter *adap; + i2c_gpio_fault_injector_exit(pdev); + priv = platform_get_drvdata(pdev); adap = &priv->adap; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 9e12a53ef7b8..692b34125866 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -58,6 +58,7 @@ * Wildcat Point (PCH) 0x8ca2 32 hard yes yes yes * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes * BayTrail (SOC) 0x0f12 32 hard yes yes yes + * Braswell (SOC) 0x2292 32 hard yes yes yes * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes * DNV (SOC) 0x19df 32 hard yes yes yes @@ -1617,6 +1618,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Default timeout in interrupt mode: 200 ms */ priv->adapter.timeout = HZ / 5; + if (dev->irq == IRQ_NOTCONNECTED) + priv->features &= ~FEATURE_IRQ; + if (priv->features & FEATURE_IRQ) { u16 pcictl, pcists; diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index eb1d91b986fd..f038858b6c54 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -82,6 +82,7 @@ #include <linux/module.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/timer.h> @@ -280,6 +281,8 @@ #define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err))) #define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M) +#define IMG_I2C_PM_TIMEOUT 1000 /* ms */ + enum img_i2c_mode { MODE_INACTIVE, MODE_RAW, @@ -408,6 +411,9 @@ struct img_i2c { unsigned int raw_timeout; }; +static int img_i2c_runtime_suspend(struct device *dev); +static int img_i2c_runtime_resume(struct device *dev); + static void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value) { writel(value, i2c->base + offset); @@ -826,9 +832,9 @@ next_atomic_cmd: * Timer function to check if something has gone wrong in automatic mode (so we * don't have to handle so many interrupts just to catch an exception). */ -static void img_i2c_check_timer(unsigned long arg) +static void img_i2c_check_timer(struct timer_list *t) { - struct img_i2c *i2c = (struct img_i2c *)arg; + struct img_i2c *i2c = from_timer(i2c, t, check_timer); unsigned long flags; unsigned int line_status; @@ -1054,8 +1060,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, atomic = true; } - ret = clk_prepare_enable(i2c->scb_clk); - if (ret) + ret = pm_runtime_get_sync(adap->dev.parent); + if (ret < 0) return ret; for (i = 0; i < num; i++) { @@ -1131,7 +1137,8 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, break; } - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(adap->dev.parent); + pm_runtime_put_autosuspend(adap->dev.parent); return i2c->msg_status ? i2c->msg_status : num; } @@ -1149,12 +1156,13 @@ static const struct i2c_algorithm img_i2c_algo = { static int img_i2c_init(struct img_i2c *i2c) { unsigned int clk_khz, bitrate_khz, clk_period, tckh, tckl, tsdh; - unsigned int i, ret, data, prescale, inc, int_bitrate, filt; + unsigned int i, data, prescale, inc, int_bitrate, filt; struct img_i2c_timings timing; u32 rev; + int ret; - ret = clk_prepare_enable(i2c->scb_clk); - if (ret) + ret = pm_runtime_get_sync(i2c->adap.dev.parent); + if (ret < 0) return ret; rev = img_i2c_readl(i2c, SCB_CORE_REV_REG); @@ -1163,7 +1171,8 @@ static int img_i2c_init(struct img_i2c *i2c) "Unknown hardware revision (%d.%d.%d.%d)\n", (rev >> 24) & 0xff, (rev >> 16) & 0xff, (rev >> 8) & 0xff, rev & 0xff); - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(i2c->adap.dev.parent); + pm_runtime_put_autosuspend(i2c->adap.dev.parent); return -EINVAL; } @@ -1314,7 +1323,8 @@ static int img_i2c_init(struct img_i2c *i2c) /* Perform a synchronous sequence to reset the bus */ ret = img_i2c_reset_bus(i2c); - clk_disable_unprepare(i2c->scb_clk); + pm_runtime_mark_last_busy(i2c->adap.dev.parent); + pm_runtime_put_autosuspend(i2c->adap.dev.parent); return ret; } @@ -1362,8 +1372,7 @@ static int img_i2c_probe(struct platform_device *pdev) } /* Set up the exception check timer */ - setup_timer(&i2c->check_timer, img_i2c_check_timer, - (unsigned long)i2c); + timer_setup(&i2c->check_timer, img_i2c_check_timer, 0); i2c->bitrate = timings[0].max_bitrate; if (!of_property_read_u32(node, "clock-frequency", &val)) @@ -1384,22 +1393,30 @@ static int img_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - ret = clk_prepare_enable(i2c->sys_clk); - if (ret) - return ret; + pm_runtime_set_autosuspend_delay(&pdev->dev, IMG_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_i2c_runtime_resume(&pdev->dev); + if (ret) + return ret; + } ret = img_i2c_init(i2c); if (ret) - goto disable_clk; + goto rpm_disable; ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) - goto disable_clk; + goto rpm_disable; return 0; -disable_clk: - clk_disable_unprepare(i2c->sys_clk); +rpm_disable: + if (!pm_runtime_enabled(&pdev->dev)) + img_i2c_runtime_suspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); return ret; } @@ -1408,19 +1425,55 @@ static int img_i2c_remove(struct platform_device *dev) struct img_i2c *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); + pm_runtime_disable(&dev->dev); + if (!pm_runtime_status_suspended(&dev->dev)) + img_i2c_runtime_suspend(&dev->dev); + + return 0; +} + +static int img_i2c_runtime_suspend(struct device *dev) +{ + struct img_i2c *i2c = dev_get_drvdata(dev); + + clk_disable_unprepare(i2c->scb_clk); clk_disable_unprepare(i2c->sys_clk); return 0; } +static int img_i2c_runtime_resume(struct device *dev) +{ + struct img_i2c *i2c = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(i2c->sys_clk); + if (ret) { + dev_err(dev, "Unable to enable sys clock\n"); + return ret; + } + + ret = clk_prepare_enable(i2c->scb_clk); + if (ret) { + dev_err(dev, "Unable to enable scb clock\n"); + clk_disable_unprepare(i2c->sys_clk); + return ret; + } + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int img_i2c_suspend(struct device *dev) { struct img_i2c *i2c = dev_get_drvdata(dev); + int ret; - img_i2c_switch_mode(i2c, MODE_SUSPEND); + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; - clk_disable_unprepare(i2c->sys_clk); + img_i2c_switch_mode(i2c, MODE_SUSPEND); return 0; } @@ -1430,7 +1483,7 @@ static int img_i2c_resume(struct device *dev) struct img_i2c *i2c = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(i2c->sys_clk); + ret = pm_runtime_force_resume(dev); if (ret) return ret; @@ -1440,7 +1493,12 @@ static int img_i2c_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static SIMPLE_DEV_PM_OPS(img_i2c_pm, img_i2c_suspend, img_i2c_resume); +static const struct dev_pm_ops img_i2c_pm = { + SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend, + img_i2c_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume) +}; static const struct of_device_id img_scb_i2c_match[] = { { .compatible = "img,scb-i2c" }, diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index e86801a63120..e6da2c7a9a3e 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -30,6 +30,7 @@ #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/sched.h> #include <linux/slab.h> @@ -90,6 +91,8 @@ #define FAST_PLUS_MAX_BITRATE 3400000 #define HIGHSPEED_MAX_BITRATE 5000000 +#define I2C_PM_TIMEOUT 10 /* ms */ + enum lpi2c_imx_mode { STANDARD, /* 100+Kbps */ FAST, /* 400+Kbps */ @@ -274,8 +277,8 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) unsigned int temp; int ret; - ret = clk_enable(lpi2c_imx->clk); - if (ret) + ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent); + if (ret < 0) return ret; temp = MCR_RST; @@ -284,7 +287,7 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) ret = lpi2c_imx_config(lpi2c_imx); if (ret) - goto clk_disable; + goto rpm_put; temp = readl(lpi2c_imx->base + LPI2C_MCR); temp |= MCR_MEN; @@ -292,8 +295,9 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) return 0; -clk_disable: - clk_disable(lpi2c_imx->clk); +rpm_put: + pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent); + pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent); return ret; } @@ -306,7 +310,8 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx) temp &= ~MCR_MEN; writel(temp, lpi2c_imx->base + LPI2C_MCR); - clk_disable(lpi2c_imx->clk); + pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent); + pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent); return 0; } @@ -606,22 +611,31 @@ static int lpi2c_imx_probe(struct platform_device *pdev) return ret; } + pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + temp = readl(lpi2c_imx->base + LPI2C_PARAM); lpi2c_imx->txfifosize = 1 << (temp & 0x0f); lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f); - clk_disable(lpi2c_imx->clk); - ret = i2c_add_adapter(&lpi2c_imx->adapter); if (ret) - goto clk_unprepare; + goto rpm_disable; + + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n"); return 0; -clk_unprepare: - clk_unprepare(lpi2c_imx->clk); +rpm_disable: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); return ret; } @@ -632,28 +646,48 @@ static int lpi2c_imx_remove(struct platform_device *pdev) i2c_del_adapter(&lpi2c_imx->adapter); - clk_unprepare(lpi2c_imx->clk); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); return 0; } #ifdef CONFIG_PM_SLEEP -static int lpi2c_imx_suspend(struct device *dev) +static int lpi2c_runtime_suspend(struct device *dev) { + struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); + + clk_disable_unprepare(lpi2c_imx->clk); pinctrl_pm_select_sleep_state(dev); return 0; } -static int lpi2c_imx_resume(struct device *dev) +static int lpi2c_runtime_resume(struct device *dev) { + struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); + int ret; + pinctrl_pm_select_default_state(dev); + ret = clk_prepare_enable(lpi2c_imx->clk); + if (ret) { + dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret); + return ret; + } return 0; } -#endif -static SIMPLE_DEV_PM_OPS(imx_lpi2c_pm, lpi2c_imx_suspend, lpi2c_imx_resume); +static const struct dev_pm_ops lpi2c_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend, + lpi2c_runtime_resume, NULL) +}; +#define IMX_LPI2C_PM (&lpi2c_pm_ops) +#else +#define IMX_LPI2C_PM NULL +#endif static struct platform_driver lpi2c_imx_driver = { .probe = lpi2c_imx_probe, @@ -661,7 +695,7 @@ static struct platform_driver lpi2c_imx_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = lpi2c_imx_of_match, - .pm = &imx_lpi2c_pm, + .pm = IMX_LPI2C_PM, }, }; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index f96830ffd9f1..999557729ad2 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -37,6 +37,7 @@ #include <linux/dmapool.h> #include <linux/err.h> #include <linux/errno.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -46,7 +47,6 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_dma.h> -#include <linux/of_gpio.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_data/i2c-imx.h> #include <linux/platform_device.h> @@ -1006,26 +1006,26 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, PINCTRL_STATE_DEFAULT); i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, "gpio"); - rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0); - rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0); + rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); + rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH); - if (rinfo->sda_gpio == -EPROBE_DEFER || - rinfo->scl_gpio == -EPROBE_DEFER) { + if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER || + PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) { return -EPROBE_DEFER; - } else if (!gpio_is_valid(rinfo->sda_gpio) || - !gpio_is_valid(rinfo->scl_gpio) || + } else if (IS_ERR(rinfo->sda_gpiod) || + IS_ERR(rinfo->scl_gpiod) || IS_ERR(i2c_imx->pinctrl_pins_default) || IS_ERR(i2c_imx->pinctrl_pins_gpio)) { dev_dbg(&pdev->dev, "recovery information incomplete\n"); return 0; } - dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n", - rinfo->scl_gpio, rinfo->sda_gpio); + dev_dbg(&pdev->dev, "using scl%s for recovery\n", + rinfo->sda_gpiod ? ",sda" : ""); rinfo->prepare_recovery = i2c_imx_prepare_recovery; rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; - rinfo->recover_bus = i2c_generic_gpio_recovery; + rinfo->recover_bus = i2c_generic_scl_recovery; i2c_imx->adapter.bus_recovery_info = rinfo; return 0; diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index b51adffa4841..0d1c3ec8cb40 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -172,7 +172,7 @@ struct ismt_priv { dma_addr_t io_rng_dma; /* descriptor HW base addr */ u8 head; /* ring buffer head pointer */ struct completion cmp; /* interrupt completion */ - u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */ + u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */ }; /** @@ -320,10 +320,12 @@ static int ismt_process_desc(const struct ismt_desc *desc, struct ismt_priv *priv, int size, char read_write) { - u8 *dma_buffer = priv->dma_buffer; + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n"); __ismt_desc_dump(&priv->pci_dev->dev, desc); + ismt_gen_reg_dump(priv); + ismt_mstr_reg_dump(priv); if (desc->status & ISMT_DESC_SCS) { if (read_write == I2C_SMBUS_WRITE && @@ -393,11 +395,12 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, struct ismt_desc *desc; struct ismt_priv *priv = i2c_get_adapdata(adap); struct device *dev = &priv->pci_dev->dev; + u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16); desc = &priv->hw[priv->head]; /* Initialize the DMA buffer */ - memset(priv->dma_buffer, 0, sizeof(priv->dma_buffer)); + memset(priv->buffer, 0, sizeof(priv->buffer)); /* Initialize the descriptor */ memset(desc, 0, sizeof(struct ismt_desc)); @@ -446,8 +449,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->wr_len_cmd = 2; dma_size = 2; dma_direction = DMA_TO_DEVICE; - priv->dma_buffer[0] = command; - priv->dma_buffer[1] = data->byte; + dma_buffer[0] = command; + dma_buffer[1] = data->byte; } else { /* Read Byte */ dev_dbg(dev, "I2C_SMBUS_BYTE_DATA: READ\n"); @@ -466,9 +469,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->wr_len_cmd = 3; dma_size = 3; dma_direction = DMA_TO_DEVICE; - priv->dma_buffer[0] = command; - priv->dma_buffer[1] = data->word & 0xff; - priv->dma_buffer[2] = data->word >> 8; + dma_buffer[0] = command; + dma_buffer[1] = data->word & 0xff; + dma_buffer[2] = data->word >> 8; } else { /* Read Word */ dev_dbg(dev, "I2C_SMBUS_WORD_DATA: READ\n"); @@ -486,9 +489,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, desc->rd_len = 2; dma_size = 3; dma_direction = DMA_BIDIRECTIONAL; - priv->dma_buffer[0] = command; - priv->dma_buffer[1] = data->word & 0xff; - priv->dma_buffer[2] = data->word >> 8; + dma_buffer[0] = command; + dma_buffer[1] = data->word & 0xff; + dma_buffer[2] = data->word >> 8; break; case I2C_SMBUS_BLOCK_DATA: @@ -499,8 +502,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, dma_direction = DMA_TO_DEVICE; desc->wr_len_cmd = dma_size; desc->control |= ISMT_DESC_BLK; - priv->dma_buffer[0] = command; - memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); } else { /* Block Read */ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: READ\n"); @@ -527,8 +530,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, dma_direction = DMA_TO_DEVICE; desc->wr_len_cmd = dma_size; desc->control |= ISMT_DESC_I2C; - priv->dma_buffer[0] = command; - memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1); + dma_buffer[0] = command; + memcpy(&dma_buffer[1], &data->block[1], dma_size - 1); } else { /* i2c Block Read */ dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA: READ\n"); @@ -557,23 +560,22 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, if (dma_size != 0) { dev_dbg(dev, " dev=%p\n", dev); dev_dbg(dev, " data=%p\n", data); - dev_dbg(dev, " dma_buffer=%p\n", priv->dma_buffer); + dev_dbg(dev, " dma_buffer=%p\n", dma_buffer); dev_dbg(dev, " dma_size=%d\n", dma_size); dev_dbg(dev, " dma_direction=%d\n", dma_direction); dma_addr = dma_map_single(dev, - priv->dma_buffer, + dma_buffer, dma_size, dma_direction); if (dma_mapping_error(dev, dma_addr)) { dev_err(dev, "Error in mapping dma buffer %p\n", - priv->dma_buffer); + dma_buffer); return -EIO; } - dev_dbg(dev, " dma_addr = 0x%016llX\n", - (unsigned long long)dma_addr); + dev_dbg(dev, " dma_addr = %pad\n", &dma_addr); desc->dptr_low = lower_32_bits(dma_addr); desc->dptr_high = upper_32_bits(dma_addr); diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 88d15b92ec35..90f5d0407d73 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -16,6 +16,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/types.h> @@ -57,6 +58,10 @@ enum { STATE_WRITE, }; +struct meson_i2c_data { + unsigned char div_factor; +}; + /** * struct meson_i2c - Meson I2C device private data * @@ -64,7 +69,6 @@ enum { * @dev: Pointer to device structure * @regs: Base address of the device memory mapped registers * @clk: Pointer to clock structure - * @irq: IRQ number * @msg: Pointer to the current I2C message * @state: Current state in the driver state machine * @last: Flag set for the last message in the transfer @@ -75,6 +79,7 @@ enum { * @done: Completion used to wait for transfer termination * @tokens: Sequence of tokens to be written to the device * @num_tokens: Number of tokens + * @data: Pointer to the controlller's platform data */ struct meson_i2c { struct i2c_adapter adap; @@ -93,6 +98,8 @@ struct meson_i2c { struct completion done; u32 tokens[2]; int num_tokens; + + const struct meson_i2c_data *data; }; static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask, @@ -128,7 +135,7 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) unsigned long clk_rate = clk_get_rate(i2c->clk); unsigned int div; - div = DIV_ROUND_UP(clk_rate, freq * 4); + div = DIV_ROUND_UP(clk_rate, freq * i2c->data->div_factor); /* clock divider has 12 bits */ if (div >= (1 << 12)) { @@ -376,6 +383,9 @@ static int meson_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->lock); init_completion(&i2c->done); + i2c->data = (const struct meson_i2c_data *) + of_device_get_match_data(&pdev->dev); + i2c->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "can't get device clock\n"); @@ -440,11 +450,25 @@ static int meson_i2c_remove(struct platform_device *pdev) return 0; } +static const struct meson_i2c_data i2c_meson6_data = { + .div_factor = 4, +}; + +static const struct meson_i2c_data i2c_gxbb_data = { + .div_factor = 4, +}; + +static const struct meson_i2c_data i2c_axg_data = { + .div_factor = 3, +}; + static const struct of_device_id meson_i2c_match[] = { - { .compatible = "amlogic,meson6-i2c" }, - { .compatible = "amlogic,meson-gxbb-i2c" }, - { }, + { .compatible = "amlogic,meson6-i2c", .data = &i2c_meson6_data }, + { .compatible = "amlogic,meson-gxbb-i2c", .data = &i2c_gxbb_data }, + { .compatible = "amlogic,meson-axg-i2c", .data = &i2c_axg_data }, + {}, }; + MODULE_DEVICE_TABLE(of, meson_i2c_match); static struct platform_driver meson_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 96caf378b1dc..d94f05c8b8b7 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -78,9 +78,7 @@ struct mpc_i2c_divider { }; struct mpc_i2c_data { - void (*setup)(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler); - u32 prescaler; + void (*setup)(struct device_node *node, struct mpc_i2c *i2c, u32 clock); }; static inline void writeccr(struct mpc_i2c *i2c, u32 x) @@ -201,7 +199,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = { }; static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, - int prescaler, u32 *real_clk) + u32 *real_clk) { const struct mpc_i2c_divider *div = NULL; unsigned int pvr = mfspr(SPRN_PVR); @@ -236,7 +234,7 @@ static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, static void mpc_i2c_setup_52xx(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { int ret, fdr; @@ -246,7 +244,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, return; } - ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->real_clk); + ret = mpc_i2c_get_fdr_52xx(node, clock, &i2c->real_clk); fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */ writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR); @@ -258,7 +256,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, #else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */ static void mpc_i2c_setup_52xx(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { } #endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */ @@ -266,7 +264,7 @@ static void mpc_i2c_setup_52xx(struct device_node *node, #ifdef CONFIG_PPC_MPC512x static void mpc_i2c_setup_512x(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { struct device_node *node_ctrl; void __iomem *ctrl; @@ -289,12 +287,12 @@ static void mpc_i2c_setup_512x(struct device_node *node, } /* The clock setup for the 52xx works also fine for the 512x */ - mpc_i2c_setup_52xx(node, i2c, clock, prescaler); + mpc_i2c_setup_52xx(node, i2c, clock); } #else /* CONFIG_PPC_MPC512x */ static void mpc_i2c_setup_512x(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { } #endif /* CONFIG_PPC_MPC512x */ @@ -322,7 +320,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = { static u32 mpc_i2c_get_sec_cfg_8xxx(void) { - struct device_node *node = NULL; + struct device_node *node; u32 __iomem *reg; u32 val = 0; @@ -332,14 +330,18 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) if (prop) { /* * Map and check POR Device Status Register 2 - * (PORDEVSR2) at 0xE0014 + * (PORDEVSR2) at 0xE0014. Note than while MPC8533 + * and MPC8544 indicate SEC frequency ratio + * configuration as bit 26 in PORDEVSR2, other MPC8xxx + * parts may store it differently or may not have it + * at all. */ reg = ioremap(get_immrbase() + *prop + 0x14, 0x4); if (!reg) printk(KERN_ERR "Error: couldn't map PORDEVSR2\n"); else - val = in_be32(reg) & 0x00000080; /* sec-cfg */ + val = in_be32(reg) & 0x00000020; /* sec-cfg */ iounmap(reg); } } @@ -350,7 +352,11 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) static u32 mpc_i2c_get_prescaler_8xxx(void) { - /* mpc83xx and mpc82xx all have prescaler 1 */ + /* + * According to the AN2919 all MPC824x have prescaler 1, while MPC83xx + * may have prescaler 1, 2, or 3, depending on the power-on + * configuration. + */ u32 prescaler = 1; /* mpc85xx */ @@ -367,6 +373,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void) || (SVR_SOC_VER(svr) == SVR_8610)) /* the above 85xx SoCs have prescaler 1 */ prescaler = 1; + else if ((SVR_SOC_VER(svr) == SVR_8533) + || (SVR_SOC_VER(svr) == SVR_8544)) + /* the above 85xx SoCs have prescaler 3 or 2 */ + prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2; else /* all the other 85xx have prescaler 2 */ prescaler = 2; @@ -376,9 +386,10 @@ static u32 mpc_i2c_get_prescaler_8xxx(void) } static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, - u32 prescaler, u32 *real_clk) + u32 *real_clk) { const struct mpc_i2c_divider *div = NULL; + u32 prescaler = mpc_i2c_get_prescaler_8xxx(); u32 divider; int i; @@ -388,12 +399,6 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, return -EINVAL; } - /* Determine proper divider value */ - if (of_device_is_compatible(node, "fsl,mpc8544-i2c")) - prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2; - if (!prescaler) - prescaler = mpc_i2c_get_prescaler_8xxx(); - divider = fsl_get_sys_freq() / clock / prescaler; pr_debug("I2C: src_clock=%d clock=%d divider=%d\n", @@ -415,7 +420,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, static void mpc_i2c_setup_8xxx(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { int ret, fdr; @@ -426,7 +431,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node, return; } - ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler, &i2c->real_clk); + ret = mpc_i2c_get_fdr_8xxx(node, clock, &i2c->real_clk); fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */ writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR); @@ -440,7 +445,7 @@ static void mpc_i2c_setup_8xxx(struct device_node *node, #else /* !CONFIG_FSL_SOC */ static void mpc_i2c_setup_8xxx(struct device_node *node, struct mpc_i2c *i2c, - u32 clock, u32 prescaler) + u32 clock) { } #endif /* CONFIG_FSL_SOC */ @@ -700,7 +705,7 @@ static int fsl_i2c_probe(struct platform_device *op) } } - if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) { + if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) { clock = MPC_I2C_CLOCK_PRESERVE; } else { prop = of_get_property(op->dev.of_node, "clock-frequency", @@ -711,11 +716,11 @@ static int fsl_i2c_probe(struct platform_device *op) if (match->data) { const struct mpc_i2c_data *data = match->data; - data->setup(op->dev.of_node, i2c, clock, data->prescaler); + data->setup(op->dev.of_node, i2c, clock); } else { /* Backwards compatibility */ if (of_get_property(op->dev.of_node, "dfsrr", NULL)) - mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock, 0); + mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock); } prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen); @@ -813,12 +818,10 @@ static const struct mpc_i2c_data mpc_i2c_data_8313 = { static const struct mpc_i2c_data mpc_i2c_data_8543 = { .setup = mpc_i2c_setup_8xxx, - .prescaler = 2, }; static const struct mpc_i2c_data mpc_i2c_data_8544 = { .setup = mpc_i2c_setup_8xxx, - .prescaler = 3, }; static const struct of_device_id mpc_i2c_of_match[] = { diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index 09d288ce0ddb..cf23a746cc17 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -61,6 +61,7 @@ #define I2C_DMA_HARD_RST 0x0002 #define I2C_DMA_4G_MODE 0x0001 +#define I2C_DEFAULT_CLK_DIV 5 #define I2C_DEFAULT_SPEED 100000 /* hz */ #define MAX_FS_MODE_SPEED 400000 #define MAX_HS_MODE_SPEED 3400000 @@ -127,6 +128,7 @@ enum I2C_REGS_OFFSET { OFFSET_DEBUGSTAT = 0x64, OFFSET_DEBUGCTRL = 0x68, OFFSET_TRANSFER_LEN_AUX = 0x6c, + OFFSET_CLOCK_DIV = 0x70, }; struct mtk_i2c_compatible { @@ -136,6 +138,7 @@ struct mtk_i2c_compatible { unsigned char auto_restart: 1; unsigned char aux_len_reg: 1; unsigned char support_33bits: 1; + unsigned char timing_adjust: 1; }; struct mtk_i2c { @@ -176,6 +179,15 @@ static const struct i2c_adapter_quirks mt7622_i2c_quirks = { .max_num_msgs = 255, }; +static const struct mtk_i2c_compatible mt2712_compat = { + .pmic_i2c = 0, + .dcm = 1, + .auto_restart = 1, + .aux_len_reg = 1, + .support_33bits = 1, + .timing_adjust = 1, +}; + static const struct mtk_i2c_compatible mt6577_compat = { .quirks = &mt6577_i2c_quirks, .pmic_i2c = 0, @@ -183,6 +195,7 @@ static const struct mtk_i2c_compatible mt6577_compat = { .auto_restart = 0, .aux_len_reg = 0, .support_33bits = 0, + .timing_adjust = 0, }; static const struct mtk_i2c_compatible mt6589_compat = { @@ -192,6 +205,7 @@ static const struct mtk_i2c_compatible mt6589_compat = { .auto_restart = 0, .aux_len_reg = 0, .support_33bits = 0, + .timing_adjust = 0, }; static const struct mtk_i2c_compatible mt7622_compat = { @@ -201,6 +215,7 @@ static const struct mtk_i2c_compatible mt7622_compat = { .auto_restart = 1, .aux_len_reg = 1, .support_33bits = 0, + .timing_adjust = 0, }; static const struct mtk_i2c_compatible mt8173_compat = { @@ -209,9 +224,11 @@ static const struct mtk_i2c_compatible mt8173_compat = { .auto_restart = 1, .aux_len_reg = 1, .support_33bits = 1, + .timing_adjust = 0, }; static const struct of_device_id mtk_i2c_of_match[] = { + { .compatible = "mediatek,mt2712-i2c", .data = &mt2712_compat }, { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat }, { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat }, { .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat }, @@ -271,6 +288,9 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c) if (i2c->dev_comp->dcm) writew(I2C_DCM_DISABLE, i2c->base + OFFSET_DCM_EN); + if (i2c->dev_comp->timing_adjust) + writew(I2C_DEFAULT_CLK_DIV - 1, i2c->base + OFFSET_CLOCK_DIV); + writew(i2c->timing_reg, i2c->base + OFFSET_TIMING); writew(i2c->high_speed_reg, i2c->base + OFFSET_HS); @@ -725,10 +745,6 @@ static int mtk_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c); - if (ret) - return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(i2c->base)) @@ -759,6 +775,13 @@ static int mtk_i2c_probe(struct platform_device *pdev) i2c->adap.timeout = 2 * HZ; i2c->adap.retries = 1; + ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c); + if (ret) + return -EINVAL; + + if (i2c->dev_comp->timing_adjust) + i2c->clk_src_div *= I2C_DEFAULT_CLK_DIV; + if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c) return -EINVAL; @@ -838,10 +861,19 @@ static int mtk_i2c_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int mtk_i2c_resume(struct device *dev) { + int ret; struct mtk_i2c *i2c = dev_get_drvdata(dev); + ret = mtk_i2c_clock_enable(i2c); + if (ret) { + dev_err(dev, "clock enable failed!\n"); + return ret; + } + mtk_i2c_init_hw(i2c); + mtk_i2c_clock_disable(i2c); + return 0; } #endif diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a832c45276a4..440fe4a96e68 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -135,6 +135,7 @@ struct mv64xxx_i2c_data { u32 freq_m; u32 freq_n; struct clk *clk; + struct clk *reg_clk; wait_queue_head_t waitq; spinlock_t lock; struct i2c_msg *msg; @@ -894,13 +895,20 @@ mv64xxx_i2c_probe(struct platform_device *pd) init_waitqueue_head(&drv_data->waitq); spin_lock_init(&drv_data->lock); - /* Not all platforms have a clk */ + /* Not all platforms have clocks */ drv_data->clk = devm_clk_get(&pd->dev, NULL); if (IS_ERR(drv_data->clk) && PTR_ERR(drv_data->clk) == -EPROBE_DEFER) return -EPROBE_DEFER; if (!IS_ERR(drv_data->clk)) clk_prepare_enable(drv_data->clk); + drv_data->reg_clk = devm_clk_get(&pd->dev, "reg"); + if (IS_ERR(drv_data->reg_clk) && + PTR_ERR(drv_data->reg_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!IS_ERR(drv_data->reg_clk)) + clk_prepare_enable(drv_data->reg_clk); + drv_data->irq = platform_get_irq(pd, 0); if (pdata) { @@ -950,9 +958,8 @@ exit_free_irq: exit_reset: reset_control_assert(drv_data->rstc); exit_clk: - /* Not all platforms have a clk */ - if (!IS_ERR(drv_data->clk)) - clk_disable_unprepare(drv_data->clk); + clk_disable_unprepare(drv_data->reg_clk); + clk_disable_unprepare(drv_data->clk); return rc; } @@ -965,9 +972,8 @@ mv64xxx_i2c_remove(struct platform_device *dev) i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); reset_control_assert(drv_data->rstc); - /* Not all platforms have a clk */ - if (!IS_ERR(drv_data->clk)) - clk_disable_unprepare(drv_data->clk); + clk_disable_unprepare(drv_data->reg_clk); + clk_disable_unprepare(drv_data->clk); return 0; } diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index d4e8f1954f23..e617bd600794 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -181,7 +181,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); if (msg->flags & I2C_M_RD) { - i2c->dma_read = 1; + i2c->dma_read = true; i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ; /* @@ -239,7 +239,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, goto read_init_dma_fail; } } else { - i2c->dma_read = 0; + i2c->dma_read = false; i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE; /* diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 1d8775799056..d9607905dc2f 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -233,6 +233,7 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) return -EOPNOTSUPP; case STAT_TXDATA_NAK: + case STAT_BUS_ERROR: return -EIO; case STAT_TXADDR_NAK: case STAT_RXADDR_NAK: diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index a7ef19855bb8..9bb9f64fdda0 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -43,7 +43,7 @@ #define TWSI_CTL_AAK 0x04 /* Assert ACK */ /* Status values */ -#define STAT_ERROR 0x00 +#define STAT_BUS_ERROR 0x00 #define STAT_START 0x08 #define STAT_REP_START 0x10 #define STAT_TXADDR_ACK 0x18 diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 23c2ea2baedc..b9172f08fd05 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -487,6 +487,22 @@ static int omap_i2c_init(struct omap_i2c_dev *omap) } /* + * Try bus recovery, but only if SDA is actually low. + */ +static int omap_i2c_recover_bus(struct omap_i2c_dev *omap) +{ + u16 systest; + + systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG); + if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) && + (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) + return 0; /* bus seems to already be fine */ + if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC)) + return -EBUSY; /* recovery would not fix SCL */ + return i2c_recover_bus(&omap->adapter); +} + +/* * Waiting on Bus Busy */ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap) @@ -496,7 +512,7 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap) timeout = jiffies + OMAP_I2C_TIMEOUT; while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { if (time_after(jiffies, timeout)) - return i2c_recover_bus(&omap->adapter); + return omap_i2c_recover_bus(omap); msleep(1); } @@ -577,8 +593,13 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap) } if (time_after(jiffies, timeout)) { + /* + * SDA or SCL were low for the entire timeout without + * any activity detected. Most likely, a slave is + * locking up the bus with no master driving the clock. + */ dev_warn(omap->dev, "timeout waiting for bus ready\n"); - return -ETIMEDOUT; + return omap_i2c_recover_bus(omap); } msleep(1); diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index faa8fb8f2b8f..fa41ff799533 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -123,7 +123,6 @@ static struct i2c_adapter parport_adapter = { /* SMBus alert support */ static struct i2c_smbus_alert_setup alert_data = { - .alert_edge_triggered = 1, }; static struct i2c_client *ara; static struct lineop parport_ctrl_irq = { diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index a8e54df4aed6..319209a07353 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -237,7 +237,6 @@ static void i2c_parport_attach(struct parport *port) /* Setup SMBus alert if supported */ if (adapter_parm[type].smbus_alert) { - adapter->alert_data.alert_edge_triggered = 1; adapter->ara = i2c_setup_smbus_alert(&adapter->adapter, &adapter->alert_data); if (adapter->ara) diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 174579d32e5f..462948e2c535 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -983,7 +983,7 @@ static void piix4_adap_remove(struct i2c_adapter *adap) if (adapdata->smba) { i2c_del_adapter(adap); - if (adapdata->port == (0 << 1)) { + if (adapdata->port == (0 << piix4_port_shift_sb800)) { release_region(adapdata->smba, SMBIOSIZE); if (adapdata->sb800_main) release_region(SB800_PIIX4_SMB_IDX, 2); diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 42d6b3a226f8..a542041df0cd 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -112,7 +112,6 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)alg_data; add_timer(timer); } @@ -435,9 +434,9 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void i2c_pnx_timeout(unsigned long data) +static void i2c_pnx_timeout(struct timer_list *t) { - struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data; + struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer); u32 ctl; dev_err(&alg_data->adapter.dev, @@ -659,8 +658,7 @@ static int i2c_pnx_probe(struct platform_device *pdev) if (IS_ERR(alg_data->clk)) return PTR_ERR(alg_data->clk); - setup_timer(&alg_data->mif.timer, i2c_pnx_timeout, - (unsigned long)alg_data); + timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0); snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), "%s", pdev->name); diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 004deb96afe3..72ea8f4c61aa 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -10,7 +10,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/platform_device.h> -#include <linux/i2c/pxa-i2c.h> +#include <linux/platform_data/i2c-pxa.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_address.h> diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 600d264e080c..fbf91d383b40 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -36,7 +36,7 @@ #include <linux/clk.h> #include <linux/slab.h> #include <linux/io.h> -#include <linux/i2c/pxa-i2c.h> +#include <linux/platform_data/i2c-pxa.h> #include <asm/irq.h> diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 15d764afec3b..4159ebcec2bb 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -62,7 +62,7 @@ #define MIE (1 << 3) /* master if enable */ #define TSBE (1 << 2) #define FSB (1 << 1) /* force stop bit */ -#define ESG (1 << 0) /* en startbit gen */ +#define ESG (1 << 0) /* enable start bit gen */ /* ICSSR (also for ICSIER) */ #define GCAR (1 << 6) /* general call received */ @@ -132,6 +132,7 @@ struct rcar_i2c_priv { int pos; u32 icccr; u32 flags; + u8 recovery_icmcr; /* protected by adapter lock */ enum rcar_i2c_type devtype; struct i2c_client *slave; @@ -158,6 +159,46 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) return readl(priv->io + reg); } +static int rcar_i2c_get_scl(struct i2c_adapter *adap) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + return !!(rcar_i2c_read(priv, ICMCR) & FSCL); + +}; + +static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + if (val) + priv->recovery_icmcr |= FSCL; + else + priv->recovery_icmcr &= ~FSCL; + + rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); +}; + +/* No get_sda, because the HW only reports its bus free logic, not SDA itself */ + +static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) +{ + struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); + + if (val) + priv->recovery_icmcr |= FSDA; + else + priv->recovery_icmcr &= ~FSDA; + + rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); +}; + +static struct i2c_bus_recovery_info rcar_i2c_bri = { + .get_scl = rcar_i2c_get_scl, + .set_scl = rcar_i2c_set_scl, + .set_sda = rcar_i2c_set_sda, + .recover_bus = i2c_generic_scl_recovery, +}; static void rcar_i2c_init(struct rcar_i2c_priv *priv) { /* reset master mode */ @@ -170,7 +211,7 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) { - int i; + int i, ret; for (i = 0; i < LOOP_TIMEOUT; i++) { /* make sure that bus is not busy */ @@ -179,7 +220,15 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) udelay(1); } - return -EBUSY; + /* Waiting did not help, try to recover */ + priv->recovery_icmcr = MDBS | OBPC | FSDA | FSCL; + ret = i2c_recover_bus(&priv->adap); + + /* No failure when recovering, so check bus busy bit again */ + if (ret == 0) + ret = (rcar_i2c_read(priv, ICMCR) & FSDA) ? -EBUSY : 0; + + return ret; } static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, struct i2c_timings *t) @@ -282,7 +331,7 @@ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read); /* - * We don't have a testcase but the HW engineers say that the write order + * We don't have a test case but the HW engineers say that the write order * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since * it didn't cause a drawback for me, let's rather be safe than sorry. */ @@ -359,7 +408,7 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv) int len; /* Do not use DMA if it's not available or for messages < 8 bytes */ - if (IS_ERR(chan) || msg->len < 8) + if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE)) return; if (read) { @@ -440,7 +489,7 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) /* * Try to use DMA to transmit the rest of the data if - * address transfer pashe just finished. + * address transfer phase just finished. */ if (msr & MAT) rcar_i2c_dma(priv); @@ -851,6 +900,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) adap->retries = 3; adap->dev.parent = dev; adap->dev.of_node = dev->of_node; + adap->bus_recovery_info = &rcar_i2c_bri; i2c_set_adapdata(adap, priv); strlcpy(adap->name, pdev->name, sizeof(adap->name)); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index c811af4c8d81..95c2f1ce3cad 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -84,12 +84,7 @@ #define ICSR2_NACKF 0x10 -/* ICBRx (@ PCLK 33MHz) */ #define ICBR_RESERVED 0xe0 /* Should be 1 on writes */ -#define ICBRL_SP100K (19 | ICBR_RESERVED) -#define ICBRH_SP100K (16 | ICBR_RESERVED) -#define ICBRL_SP400K (21 | ICBR_RESERVED) -#define ICBRH_SP400K (9 | ICBR_RESERVED) #define RIIC_INIT_MSG -1 @@ -288,48 +283,99 @@ static const struct i2c_algorithm riic_algo = { .functionality = riic_func, }; -static int riic_init_hw(struct riic_dev *riic, u32 spd) +static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) { int ret; unsigned long rate; + int total_ticks, cks, brl, brh; ret = clk_prepare_enable(riic->clk); if (ret) return ret; + if (t->bus_freq_hz > 400000) { + dev_err(&riic->adapter.dev, + "unsupported bus speed (%dHz). 400000 max\n", + t->bus_freq_hz); + clk_disable_unprepare(riic->clk); + return -EINVAL; + } + + rate = clk_get_rate(riic->clk); + /* - * TODO: Implement formula to calculate the timing values depending on - * variable parent clock rate and arbitrary bus speed + * Assume the default register settings: + * FER.SCLE = 1 (SCL sync circuit enabled, adds 2 or 3 cycles) + * FER.NFE = 1 (noise circuit enabled) + * MR3.NF = 0 (1 cycle of noise filtered out) + * + * Freq (CKS=000) = (I2CCLK + tr + tf)/ (BRH + 3 + 1) + (BRL + 3 + 1) + * Freq (CKS!=000) = (I2CCLK + tr + tf)/ (BRH + 2 + 1) + (BRL + 2 + 1) */ - rate = clk_get_rate(riic->clk); - if (rate != 33325000) { - dev_err(&riic->adapter.dev, - "invalid parent clk (%lu). Must be 33325000Hz\n", rate); + + /* + * Determine reference clock rate. We must be able to get the desired + * frequency with only 62 clock ticks max (31 high, 31 low). + * Aim for a duty of 60% LOW, 40% HIGH. + */ + total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz); + + for (cks = 0; cks < 7; cks++) { + /* + * 60% low time must be less than BRL + 2 + 1 + * BRL max register value is 0x1F. + */ + brl = ((total_ticks * 6) / 10); + if (brl <= (0x1F + 3)) + break; + + total_ticks /= 2; + rate /= 2; + } + + if (brl > (0x1F + 3)) { + dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n", + (unsigned long)t->bus_freq_hz); clk_disable_unprepare(riic->clk); return -EINVAL; } + brh = total_ticks - brl; + + /* Remove automatic clock ticks for sync circuit and NF */ + if (cks == 0) { + brl -= 4; + brh -= 4; + } else { + brl -= 3; + brh -= 3; + } + + /* + * Remove clock ticks for rise and fall times. Convert ns to clock + * ticks. + */ + brl -= t->scl_fall_ns / (1000000000 / rate); + brh -= t->scl_rise_ns / (1000000000 / rate); + + /* Adjust for min register values for when SCLE=1 and NFE=1 */ + if (brl < 1) + brl = 1; + if (brh < 1) + brh = 1; + + pr_debug("i2c-riic: freq=%lu, duty=%d, fall=%lu, rise=%lu, cks=%d, brl=%d, brh=%d\n", + rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6), + t->scl_fall_ns / (1000000000 / rate), + t->scl_rise_ns / (1000000000 / rate), cks, brl, brh); + /* Changing the order of accessing IICRST and ICE may break things! */ writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1); riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1); - switch (spd) { - case 100000: - writeb(ICMR1_CKS(3), riic->base + RIIC_ICMR1); - writeb(ICBRH_SP100K, riic->base + RIIC_ICBRH); - writeb(ICBRL_SP100K, riic->base + RIIC_ICBRL); - break; - case 400000: - writeb(ICMR1_CKS(1), riic->base + RIIC_ICMR1); - writeb(ICBRH_SP400K, riic->base + RIIC_ICBRH); - writeb(ICBRL_SP400K, riic->base + RIIC_ICBRL); - break; - default: - dev_err(&riic->adapter.dev, - "unsupported bus speed (%dHz). Use 100000 or 400000\n", spd); - clk_disable_unprepare(riic->clk); - return -EINVAL; - } + writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1); + writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH); + writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL); writeb(0, riic->base + RIIC_ICSER); writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3); @@ -351,11 +397,10 @@ static struct riic_irq_desc riic_irqs[] = { static int riic_i2c_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; struct riic_dev *riic; struct i2c_adapter *adap; struct resource *res; - u32 bus_rate = 0; + struct i2c_timings i2c_t; int i, ret; riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL); @@ -396,8 +441,9 @@ static int riic_i2c_probe(struct platform_device *pdev) init_completion(&riic->msg_done); - of_property_read_u32(np, "clock-frequency", &bus_rate); - ret = riic_init_hw(riic, bus_rate); + i2c_parse_fw_timings(&pdev->dev, &i2c_t, true); + + ret = riic_init_hw(riic, &i2c_t); if (ret) return ret; @@ -408,7 +454,8 @@ static int riic_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, riic); - dev_info(&pdev->dev, "registered with %dHz bus speed\n", bus_rate); + dev_info(&pdev->dev, "registered with %dHz bus speed\n", + i2c_t.bus_freq_hz); return 0; } diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index fe234578380a..e1a18d989f83 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -161,6 +161,7 @@ enum rk3x_i2c_state { }; /** + * struct rk3x_i2c_soc_data: * @grf_offset: offset inside the grf regmap for setting the i2c type * @calc_timings: Callback function for i2c timing information calculated */ @@ -194,7 +195,7 @@ struct rk3x_i2c_soc_data { struct rk3x_i2c { struct i2c_adapter adap; struct device *dev; - struct rk3x_i2c_soc_data *soc_data; + const struct rk3x_i2c_soc_data *soc_data; /* Hardware resources */ void __iomem *regs; @@ -1164,27 +1165,27 @@ static const struct rk3x_i2c_soc_data rk3399_soc_data = { static const struct of_device_id rk3x_i2c_match[] = { { .compatible = "rockchip,rv1108-i2c", - .data = (void *)&rv1108_soc_data + .data = &rv1108_soc_data }, { .compatible = "rockchip,rk3066-i2c", - .data = (void *)&rk3066_soc_data + .data = &rk3066_soc_data }, { .compatible = "rockchip,rk3188-i2c", - .data = (void *)&rk3188_soc_data + .data = &rk3188_soc_data }, { .compatible = "rockchip,rk3228-i2c", - .data = (void *)&rk3228_soc_data + .data = &rk3228_soc_data }, { .compatible = "rockchip,rk3288-i2c", - .data = (void *)&rk3288_soc_data + .data = &rk3288_soc_data }, { .compatible = "rockchip,rk3399-i2c", - .data = (void *)&rk3399_soc_data + .data = &rk3399_soc_data }, {}, }; @@ -1207,7 +1208,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev) return -ENOMEM; match = of_match_node(rk3x_i2c_match, np); - i2c->soc_data = (struct rk3x_i2c_soc_data *)match->data; + i2c->soc_data = match->data; /* use common interface to get I2C timing properties */ i2c_parse_fw_timings(&pdev->dev, &i2c->t, true); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 6f2aaeb7c4fa..d856bc211715 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -40,21 +40,21 @@ /* BUS: S A8 ACK P(*) */ /* IRQ: DTE WAIT */ /* ICIC: */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 */ /* */ /* 1 byte transmit */ /* BUS: S A8 ACK D8(1) ACK P(*) */ /* IRQ: DTE WAIT WAIT */ /* ICIC: -DTE */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 D8(1) */ /* */ /* 2 byte transmit */ /* BUS: S A8 ACK D8(1) ACK D8(2) ACK P(*) */ /* IRQ: DTE WAIT WAIT WAIT */ /* ICIC: -DTE */ -/* ICCR: 0x94 0x90 */ +/* ICCR: 0x94 0x90 */ /* ICDR: A8 D8(1) D8(2) */ /* */ /* 3 bytes or more, +---------+ gets repeated */ @@ -113,7 +113,6 @@ enum sh_mobile_i2c_op { OP_TX_FIRST, OP_TX, OP_TX_STOP, - OP_TX_STOP_DATA, OP_TX_TO_RX, OP_RX, OP_RX_STOP, @@ -145,11 +144,12 @@ struct sh_mobile_i2c_data { struct dma_chan *dma_rx; struct scatterlist sg; enum dma_data_direction dma_direction; + u8 *dma_buf; }; struct sh_mobile_dt_config { int clks_per_count; - void (*setup)(struct sh_mobile_i2c_data *pd); + int (*setup)(struct sh_mobile_i2c_data *pd); }; #define IIC_FLAG_HAS_ICIC67 (1 << 0) @@ -246,36 +246,10 @@ static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf) return (((count_khz * (tHIGH + tf)) + 5000) / 10000); } -static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) +static int sh_mobile_i2c_check_timing(struct sh_mobile_i2c_data *pd) { - unsigned long i2c_clk_khz; - u32 tHIGH, tLOW, tf; - uint16_t max_val; - - /* Get clock rate after clock is enabled */ - clk_prepare_enable(pd->clk); - i2c_clk_khz = clk_get_rate(pd->clk) / 1000; - clk_disable_unprepare(pd->clk); - i2c_clk_khz /= pd->clks_per_count; - - if (pd->bus_speed == STANDARD_MODE) { - tLOW = 47; /* tLOW = 4.7 us */ - tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */ - tf = 3; /* tf = 0.3 us */ - } else if (pd->bus_speed == FAST_MODE) { - tLOW = 13; /* tLOW = 1.3 us */ - tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */ - tf = 3; /* tf = 0.3 us */ - } else { - dev_err(pd->dev, "unrecognized bus speed %lu Hz\n", - pd->bus_speed); - return -EINVAL; - } - - pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf); - pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); + u16 max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff; - max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff; if (pd->iccl > max_val || pd->icch > max_val) { dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n", pd->iccl, pd->icch); @@ -298,35 +272,43 @@ static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) return 0; } -static void activate_ch(struct sh_mobile_i2c_data *pd) +static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { - /* Wake up device and enable clock */ - pm_runtime_get_sync(pd->dev); - clk_prepare_enable(pd->clk); + unsigned long i2c_clk_khz; + u32 tHIGH, tLOW, tf; - /* Enable channel and configure rx ack */ - iic_set_clr(pd, ICCR, ICCR_ICE, 0); + i2c_clk_khz = clk_get_rate(pd->clk) / 1000 / pd->clks_per_count; + + if (pd->bus_speed == STANDARD_MODE) { + tLOW = 47; /* tLOW = 4.7 us */ + tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */ + tf = 3; /* tf = 0.3 us */ + } else if (pd->bus_speed == FAST_MODE) { + tLOW = 13; /* tLOW = 1.3 us */ + tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */ + tf = 3; /* tf = 0.3 us */ + } else { + dev_err(pd->dev, "unrecognized bus speed %lu Hz\n", + pd->bus_speed); + return -EINVAL; + } - /* Mask all interrupts */ - iic_wr(pd, ICIC, 0); + pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf); + pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); - /* Set the clock */ - iic_wr(pd, ICCL, pd->iccl & 0xff); - iic_wr(pd, ICCH, pd->icch & 0xff); + return sh_mobile_i2c_check_timing(pd); } -static void deactivate_ch(struct sh_mobile_i2c_data *pd) +static int sh_mobile_i2c_v2_init(struct sh_mobile_i2c_data *pd) { - /* Clear/disable interrupts */ - iic_wr(pd, ICSR, 0); - iic_wr(pd, ICIC, 0); + unsigned long clks_per_cycle; - /* Disable channel */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); + /* L = 5, H = 4, L + H = 9 */ + clks_per_cycle = clk_get_rate(pd->clk) / pd->bus_speed; + pd->iccl = DIV_ROUND_UP(clks_per_cycle * 5 / 9 - 1, pd->clks_per_count); + pd->icch = DIV_ROUND_UP(clks_per_cycle * 4 / 9 - 5, pd->clks_per_count); - /* Disable clock and mark device as idle */ - clk_disable_unprepare(pd->clk); - pm_runtime_put_sync(pd->dev); + return sh_mobile_i2c_check_timing(pd); } static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, @@ -350,10 +332,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, case OP_TX: /* write data */ iic_wr(pd, ICDR, data); break; - case OP_TX_STOP_DATA: /* write data and issue a stop afterwards */ - iic_wr(pd, ICDR, data); - /* fallthrough */ - case OP_TX_STOP: /* issue a stop */ + case OP_TX_STOP: /* issue a stop (or rep_start) */ iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS : ICCR_ICE | ICCR_TRS | ICCR_BBSY); break; @@ -387,11 +366,6 @@ static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd) return pd->pos == -1; } -static bool sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd) -{ - return pd->pos == pd->msg->len - 1; -} - static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd, unsigned char *buf) { @@ -409,20 +383,12 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd) unsigned char data; if (pd->pos == pd->msg->len) { - /* Send stop if we haven't yet (DMA case) */ - if (pd->send_stop && pd->stop_after_dma) - i2c_op(pd, OP_TX_STOP, 0); + i2c_op(pd, OP_TX_STOP, 0); return 1; } sh_mobile_i2c_get_data(pd, &data); - - if (sh_mobile_i2c_is_last_byte(pd)) - i2c_op(pd, OP_TX_STOP_DATA, data); - else if (sh_mobile_i2c_is_first_byte(pd)) - i2c_op(pd, OP_TX_FIRST, data); - else - i2c_op(pd, OP_TX, data); + i2c_op(pd, sh_mobile_i2c_is_first_byte(pd) ? OP_TX_FIRST : OP_TX, data); pd->pos++; return 0; @@ -464,8 +430,9 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd) break; } data = i2c_op(pd, OP_RX_STOP_DATA, 0); - } else + } else if (real_pos >= 0) { data = i2c_op(pd, OP_RX, 0); + } if (real_pos >= 0) pd->msg->buf[real_pos] = data; @@ -548,6 +515,8 @@ static void sh_mobile_i2c_dma_callback(void *data) pd->pos = pd->msg->len; pd->stop_after_dma = true; + i2c_release_dma_safe_msg_buf(pd->msg, pd->dma_buf); + iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE); } @@ -608,7 +577,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) if (IS_ERR(chan)) return; - dma_addr = dma_map_single(chan->device->dev, pd->msg->buf, pd->msg->len, dir); + dma_addr = dma_map_single(chan->device->dev, pd->dma_buf, pd->msg->len, dir); if (dma_mapping_error(chan->device->dev, dma_addr)) { dev_dbg(pd->dev, "dma map failed, using PIO\n"); return; @@ -651,10 +620,10 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, if (do_init) { /* Initialize channel registers */ - iic_set_clr(pd, ICCR, 0, ICCR_ICE); + iic_wr(pd, ICCR, ICCR_SCP); /* Enable channel and configure rx ack */ - iic_set_clr(pd, ICCR, ICCR_ICE, 0); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP); /* Set the clock */ iic_wr(pd, ICCL, pd->iccl & 0xff); @@ -665,7 +634,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, pd->pos = -1; pd->sr = 0; - if (pd->msg->len > 8) + pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8); + if (pd->dma_buf) sh_mobile_i2c_xfer_dma(pd); /* Enable all interrupts to begin with */ @@ -731,7 +701,8 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, int i; long timeout; - activate_ch(pd); + /* Wake up device and enable clock */ + pm_runtime_get_sync(pd->dev); /* Process all messages */ for (i = 0; i < num; i++) { @@ -768,11 +739,13 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, break; } - deactivate_ch(pd); + /* Disable channel */ + iic_wr(pd, ICCR, ICCR_SCP); + + /* Disable clock and mark device as idle */ + pm_runtime_put_sync(pd->dev); - if (!err) - err = num; - return err; + return err ?: num; } static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) @@ -789,7 +762,7 @@ static const struct i2c_algorithm sh_mobile_i2c_algorithm = { * r8a7740 chip has lasting errata on I2C I/O pad reset. * this is work-around for it. */ -static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) +static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) { iic_set_clr(pd, ICCR, ICCR_ICE, 0); iic_rd(pd, ICCR); /* dummy read */ @@ -810,14 +783,23 @@ static void sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) udelay(10); iic_wr(pd, ICCR, ICCR_TRS); udelay(10); + + return sh_mobile_i2c_init(pd); } static const struct sh_mobile_dt_config default_dt_config = { .clks_per_count = 1, + .setup = sh_mobile_i2c_init, }; static const struct sh_mobile_dt_config fast_clock_dt_config = { .clks_per_count = 2, + .setup = sh_mobile_i2c_init, +}; + +static const struct sh_mobile_dt_config v2_freq_calc_dt_config = { + .clks_per_count = 2, + .setup = sh_mobile_i2c_v2_init, }; static const struct sh_mobile_dt_config r8a7740_dt_config = { @@ -828,7 +810,7 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = { static const struct of_device_id sh_mobile_i2c_dt_ids[] = { { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config }, - { .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config }, { .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config }, @@ -881,7 +863,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; - const struct of_device_id *match; + const struct sh_mobile_dt_config *config; int ret; u32 bus_speed; @@ -910,34 +892,13 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return PTR_ERR(pd->reg); ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed); - pd->bus_speed = ret ? STANDARD_MODE : bus_speed; + pd->bus_speed = (ret || !bus_speed) ? STANDARD_MODE : bus_speed; pd->clks_per_count = 1; - match = of_match_device(sh_mobile_i2c_dt_ids, &dev->dev); - if (match) { - const struct sh_mobile_dt_config *config = match->data; - - pd->clks_per_count = config->clks_per_count; - - if (config->setup) - config->setup(pd); - } - - /* The IIC blocks on SH-Mobile ARM processors - * come with two new bits in ICIC. - */ + /* Newer variants come with two new bits in ICIC */ if (resource_size(res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; - ret = sh_mobile_i2c_init(pd); - if (ret) - return ret; - - /* Init DMA */ - sg_init_table(&pd->sg, 1); - pd->dma_direction = DMA_NONE; - pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER); - /* Enable Runtime PM for this device. * * Also tell the Runtime PM core to ignore children @@ -950,6 +911,24 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) */ pm_suspend_ignore_children(&dev->dev, true); pm_runtime_enable(&dev->dev); + pm_runtime_get_sync(&dev->dev); + + config = of_device_get_match_data(&dev->dev); + if (config) { + pd->clks_per_count = config->clks_per_count; + ret = config->setup(pd); + } else { + ret = sh_mobile_i2c_init(pd); + } + + pm_runtime_put_sync(&dev->dev); + if (ret) + return ret; + + /* Init DMA */ + sg_init_table(&pd->sg, 1); + pd->dma_direction = DMA_NONE; + pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER); /* setup the private data */ adap = &pd->adap; diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c index 2fd8b6d00391..87197ece0f90 100644 --- a/drivers/i2c/busses/i2c-sirf.c +++ b/drivers/i2c/busses/i2c-sirf.c @@ -341,7 +341,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, adap); init_completion(&siic->done); - /* Controller Initalisation */ + /* Controller initialisation */ writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL); while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) @@ -369,7 +369,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) * but they start to affect the speed when clock is set to faster * frequencies. * Through the actual tests, use the different user_div value(which - * in the divider formular 'Fio / (Fi2c * user_div)') to adapt + * in the divider formula 'Fio / (Fi2c * user_div)') to adapt * the different ranges of i2c bus clock frequency, to make the SCL * more accurate. */ diff --git a/drivers/i2c/busses/i2c-stm32.h b/drivers/i2c/busses/i2c-stm32.h index dab51761f8c5..d4f9cef251ac 100644 --- a/drivers/i2c/busses/i2c-stm32.h +++ b/drivers/i2c/busses/i2c-stm32.h @@ -1,10 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* * i2c-stm32.h * * Copyright (C) M'boumba Cedric Madianga 2017 + * Copyright (C) STMicroelectronics 2017 * Author: M'boumba Cedric Madianga <[email protected]> * - * License terms: GNU General Public License (GPL), version 2 */ #ifndef _I2C_STM32_H diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index 4ec108496f15..47c8d00de53f 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for STMicroelectronics STM32 I2C controller * @@ -6,11 +7,11 @@ * http://www.st.com/resource/en/reference_manual/DM00031020.pdf * * Copyright (C) M'boumba Cedric Madianga 2016 + * Copyright (C) STMicroelectronics 2017 * Author: M'boumba Cedric Madianga <[email protected]> * * This driver is based on i2c-st.c * - * License terms: GNU General Public License (GPL), version 2 */ #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index d4a6e9c2e9aa..b445b3bb0bb1 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for STMicroelectronics STM32F7 I2C controller * @@ -7,11 +8,11 @@ * http://www.st.com/resource/en/reference_manual/dm00124865.pdf * * Copyright (C) M'boumba Cedric Madianga 2017 + * Copyright (C) STMicroelectronics 2017 * Author: M'boumba Cedric Madianga <[email protected]> * * This driver is based on i2c-stm32f4.c * - * License terms: GNU General Public License (GPL), version 2 */ #include <linux/clk.h> #include <linux/delay.h> diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index addd90a8cb59..7c7fc01116a1 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -282,8 +282,7 @@ static void taos_disconnect(struct serio *serio) { struct taos_data *taos = serio_get_drvdata(serio); - if (taos->client) - i2c_unregister_device(taos->client); + i2c_unregister_device(taos->client); i2c_del_adapter(&taos->adapter); serio_close(serio); kfree(taos); diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index df0976f4432a..19f8eec38717 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -118,8 +118,6 @@ static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk) static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, struct device_node *node) { - u32 type; - if (!node) return -EINVAL; @@ -127,10 +125,6 @@ static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, if (!i2c->alert_data.irq) return -EINVAL; - type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq)); - i2c->alert_data.alert_edge_triggered = - (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0; - i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data); if (!i2c->ara) return -ENODEV; @@ -149,8 +143,7 @@ static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c, static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c) { - if (i2c->ara) - i2c_unregister_device(i2c->ara); + i2c_unregister_device(i2c->ara); } static int thunder_i2c_probe_pci(struct pci_dev *pdev, diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 7e89ba6fcf6f..a7ac746018ad 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -129,6 +129,11 @@ struct slimpro_i2c_dev { #define to_slimpro_i2c_dev(cl) \ container_of(cl, struct slimpro_i2c_dev, mbox_client) +enum slimpro_i2c_version { + XGENE_SLIMPRO_I2C_V1 = 0, + XGENE_SLIMPRO_I2C_V2 = 1, +}; + /* * This function tests and clears a bitmask then returns its old value */ @@ -476,6 +481,15 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) } } else { struct acpi_pcct_hw_reduced *cppc_ss; + const struct acpi_device_id *acpi_id; + int version = XGENE_SLIMPRO_I2C_V1; + + acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, + &pdev->dev); + if (!acpi_id) + return -EINVAL; + + version = (int)acpi_id->driver_data; if (device_property_read_u32(&pdev->dev, "pcc-channel", &ctx->mbox_idx)) @@ -514,9 +528,16 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) */ ctx->comm_base_addr = cppc_ss->base_address; if (ctx->comm_base_addr) { - ctx->pcc_comm_addr = memremap(ctx->comm_base_addr, - cppc_ss->length, - MEMREMAP_WB); + if (version == XGENE_SLIMPRO_I2C_V2) + ctx->pcc_comm_addr = memremap( + ctx->comm_base_addr, + cppc_ss->length, + MEMREMAP_WT); + else + ctx->pcc_comm_addr = memremap( + ctx->comm_base_addr, + cppc_ss->length, + MEMREMAP_WB); } else { dev_err(&pdev->dev, "Failed to get PCC comm region\n"); rc = -ENOENT; @@ -581,7 +602,8 @@ MODULE_DEVICE_TABLE(of, xgene_slimpro_i2c_dt_ids); #ifdef CONFIG_ACPI static const struct acpi_device_id xgene_slimpro_i2c_acpi_ids[] = { - {"APMC0D40", 0}, + {"APMC0D40", XGENE_SLIMPRO_I2C_V1}, + {"APMC0D8B", XGENE_SLIMPRO_I2C_V2}, {} }; MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids); diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 6b106e94bc09..b970bf8f38e5 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -7,6 +7,7 @@ */ #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/completion.h> #include <linux/i2c.h> #include <linux/init.h> @@ -81,9 +82,12 @@ struct xlp9xx_i2c_dev { struct completion msg_complete; int irq; bool msg_read; + bool len_recv; + bool client_pec; u32 __iomem *base; u32 msg_buf_remaining; u32 msg_len; + u32 ip_clk_hz; u32 clk_hz; u32 msg_err; u8 *msg_buf; @@ -141,10 +145,25 @@ static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv) static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv) { u32 len, i; - u8 *buf = priv->msg_buf; + u8 rlen, *buf = priv->msg_buf; len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) & XLP9XX_I2C_FIFO_WCNT_MASK; + if (!len) + return; + if (priv->len_recv) { + /* read length byte */ + rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); + *buf++ = rlen; + len--; + if (priv->client_pec) + ++rlen; + /* update remaining bytes and message length */ + priv->msg_buf_remaining = rlen; + priv->msg_len = rlen + 1; + priv->len_recv = false; + } + len = min(priv->msg_buf_remaining, len); for (i = 0; i < len; i++, buf++) *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO); @@ -213,7 +232,7 @@ static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv) * The controller uses 5 * SCL clock internally. * So prescale value should be divided by 5. */ - prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz); + prescale = DIV_ROUND_UP(priv->ip_clk_hz, priv->clk_hz); prescale = ((prescale - 8) / 5) - 1; xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN | @@ -228,7 +247,7 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, int last_msg) { unsigned long timeleft; - u32 intr_mask, cmd, val; + u32 intr_mask, cmd, val, len; priv->msg_buf = msg->buf; priv->msg_buf_remaining = priv->msg_len = msg->len; @@ -261,9 +280,13 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, else val &= ~XLP9XX_I2C_CTRL_ADDMODE; + priv->len_recv = msg->flags & I2C_M_RECV_LEN; + len = priv->len_recv ? XLP9XX_I2C_FIFO_SIZE : msg->len; + priv->client_pec = msg->flags & I2C_CLIENT_PEC; + /* set data length to be transferred */ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | - (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); + (len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); /* fill fifo during tx */ @@ -310,6 +333,9 @@ static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, return -ETIMEDOUT; } + /* update msg->len with actual received length */ + if (msg->flags & I2C_M_RECV_LEN) + msg->len = priv->msg_len; return 0; } @@ -342,9 +368,19 @@ static const struct i2c_algorithm xlp9xx_i2c_algo = { static int xlp9xx_i2c_get_frequency(struct platform_device *pdev, struct xlp9xx_i2c_dev *priv) { + struct clk *clk; u32 freq; int err; + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + priv->ip_clk_hz = XLP9XX_I2C_IP_CLK_FREQ; + dev_dbg(&pdev->dev, "using default input frequency %u\n", + priv->ip_clk_hz); + } else { + priv->ip_clk_hz = clk_get_rate(clk); + } + err = device_property_read_u32(&pdev->dev, "clock-frequency", &freq); if (err) { freq = XLP9XX_I2C_DEFAULT_FREQ; diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 31186ead5a40..509a6007cdf6 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -86,6 +86,7 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig property_entries_dup(info->properties); if (IS_ERR(devinfo->board_info.properties)) { status = PTR_ERR(devinfo->board_info.properties); + kfree(devinfo); break; } } @@ -98,6 +99,7 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig GFP_KERNEL); if (!devinfo->board_info.resources) { status = -ENOMEM; + kfree(devinfo); break; } } diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 56e46581b84b..5a00bf443d06 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -27,8 +27,9 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/errno.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> +#include <linux/i2c-smbus.h> #include <linux/idr.h> #include <linux/init.h> #include <linux/irqflags.h> @@ -133,52 +134,22 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) /* i2c bus recovery routines */ static int get_scl_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->scl_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->scl_gpiod); } static void set_scl_gpio_value(struct i2c_adapter *adap, int val) { - gpio_set_value(adap->bus_recovery_info->scl_gpio, val); + gpiod_set_value_cansleep(adap->bus_recovery_info->scl_gpiod, val); } static int get_sda_gpio_value(struct i2c_adapter *adap) { - return gpio_get_value(adap->bus_recovery_info->sda_gpio); + return gpiod_get_value_cansleep(adap->bus_recovery_info->sda_gpiod); } -static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) +static void set_sda_gpio_value(struct i2c_adapter *adap, int val) { - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - struct device *dev = &adap->dev; - int ret = 0; - - ret = gpio_request_one(bri->scl_gpio, GPIOF_OPEN_DRAIN | - GPIOF_OUT_INIT_HIGH, "i2c-scl"); - if (ret) { - dev_warn(dev, "Can't get SCL gpio: %d\n", bri->scl_gpio); - return ret; - } - - if (bri->get_sda) { - if (gpio_request_one(bri->sda_gpio, GPIOF_IN, "i2c-sda")) { - /* work without SDA polling */ - dev_warn(dev, "Can't get SDA gpio: %d. Not using SDA polling\n", - bri->sda_gpio); - bri->get_sda = NULL; - } - } - - return ret; -} - -static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) -{ - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - - if (bri->get_sda) - gpio_free(bri->sda_gpio); - - gpio_free(bri->scl_gpio); + gpiod_set_value_cansleep(adap->bus_recovery_info->sda_gpiod, val); } /* @@ -189,7 +160,7 @@ static void i2c_put_gpios_for_recovery(struct i2c_adapter *adap) #define RECOVERY_NDELAY 5000 #define RECOVERY_CLK_CNT 9 -static int i2c_generic_recovery(struct i2c_adapter *adap) +int i2c_generic_scl_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; int i = 0, val = 1, ret = 0; @@ -198,6 +169,8 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) bri->prepare_recovery(adap); bri->set_scl(adap, val); + if (bri->set_sda) + bri->set_sda(adap, 1); ndelay(RECOVERY_NDELAY); /* @@ -205,9 +178,6 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) */ while (i++ < RECOVERY_CLK_CNT * 2) { if (val) { - /* Break if SDA is high */ - if (bri->get_sda && bri->get_sda(adap)) - break; /* SCL shouldn't be low here */ if (!bri->get_scl(adap)) { dev_err(&adap->dev, @@ -215,6 +185,9 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) ret = -EBUSY; break; } + /* Break if SDA is high */ + if (bri->get_sda && bri->get_sda(adap)) + break; } val = !val; @@ -222,33 +195,29 @@ static int i2c_generic_recovery(struct i2c_adapter *adap) ndelay(RECOVERY_NDELAY); } + /* check if recovery actually succeeded */ + if (bri->get_sda && !bri->get_sda(adap)) + ret = -EBUSY; + + /* If all went well, send STOP for a sane bus state. */ + if (ret == 0 && bri->set_sda) { + bri->set_scl(adap, 0); + ndelay(RECOVERY_NDELAY / 2); + bri->set_sda(adap, 0); + ndelay(RECOVERY_NDELAY / 2); + bri->set_scl(adap, 1); + ndelay(RECOVERY_NDELAY / 2); + bri->set_sda(adap, 1); + ndelay(RECOVERY_NDELAY / 2); + } + if (bri->unprepare_recovery) bri->unprepare_recovery(adap); return ret; } - -int i2c_generic_scl_recovery(struct i2c_adapter *adap) -{ - return i2c_generic_recovery(adap); -} EXPORT_SYMBOL_GPL(i2c_generic_scl_recovery); -int i2c_generic_gpio_recovery(struct i2c_adapter *adap) -{ - int ret; - - ret = i2c_get_gpios_for_recovery(adap); - if (ret) - return ret; - - ret = i2c_generic_recovery(adap); - i2c_put_gpios_for_recovery(adap); - - return ret; -} -EXPORT_SYMBOL_GPL(i2c_generic_gpio_recovery); - int i2c_recover_bus(struct i2c_adapter *adap) { if (!adap->bus_recovery_info) @@ -272,21 +241,19 @@ static void i2c_init_recovery(struct i2c_adapter *adap) goto err; } - /* Generic GPIO recovery */ - if (bri->recover_bus == i2c_generic_gpio_recovery) { - if (!gpio_is_valid(bri->scl_gpio)) { - err_str = "invalid SCL gpio"; - goto err; - } - - if (gpio_is_valid(bri->sda_gpio)) - bri->get_sda = get_sda_gpio_value; - else - bri->get_sda = NULL; - + if (bri->scl_gpiod && bri->recover_bus == i2c_generic_scl_recovery) { bri->get_scl = get_scl_gpio_value; bri->set_scl = set_scl_gpio_value; - } else if (bri->recover_bus == i2c_generic_scl_recovery) { + if (bri->sda_gpiod) { + bri->get_sda = get_sda_gpio_value; + /* FIXME: add proper flag instead of '0' once available */ + if (gpiod_get_direction(bri->sda_gpiod) == 0) + bri->set_sda = set_sda_gpio_value; + } + return; + } + + if (bri->recover_bus == i2c_generic_scl_recovery) { /* Generic SCL recovery */ if (!bri->set_scl || !bri->get_scl) { err_str = "no {get|set}_scl() found"; @@ -666,10 +633,16 @@ static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, } static void i2c_dev_set_name(struct i2c_adapter *adap, - struct i2c_client *client) + struct i2c_client *client, + struct i2c_board_info const *info) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); + if (info && info->dev_name) { + dev_set_name(&client->dev, "i2c-%s", info->dev_name); + return; + } + if (adev) { dev_set_name(&client->dev, "i2c-%s", acpi_dev_name(adev)); return; @@ -766,7 +739,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.of_node = info->of_node; client->dev.fwnode = info->fwnode; - i2c_dev_set_name(adap, client); + i2c_dev_set_name(adap, client, info); if (info->properties) { status = device_add_properties(&client->dev, info->properties); @@ -808,8 +781,14 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - if (client->dev.of_node) + if (!client) + return; + + if (client->dev.of_node) { of_node_clear_flag(client->dev.of_node, OF_POPULATED); + of_node_put(client->dev.of_node); + } + if (ACPI_COMPANION(&client->dev)) acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); device_unregister(&client->dev); @@ -1259,6 +1238,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) goto out_list; } + res = of_i2c_setup_smbus_alert(adap); + if (res) + goto out_reg; + dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); pm_runtime_no_callbacks(&adap->dev); @@ -1290,6 +1273,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap) return 0; +out_reg: + init_completion(&adap->dev_released); + device_unregister(&adap->dev); + wait_for_completion(&adap->dev_released); out_list: mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); @@ -1417,8 +1404,7 @@ static int __unregister_client(struct device *dev, void *dummy) static int __unregister_dummy(struct device *dev, void *dummy) { struct i2c_client *client = i2c_verify_client(dev); - if (client) - i2c_unregister_device(client); + i2c_unregister_device(client); return 0; } @@ -1952,63 +1938,35 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) EXPORT_SYMBOL(i2c_transfer); /** - * i2c_master_send - issue a single I2C message in master transmit mode - * @client: Handle to slave device - * @buf: Data that will be written to the slave - * @count: How many bytes to write, must be less than 64k since msg.len is u16 - * - * Returns negative errno, or else the number of bytes written. - */ -int i2c_master_send(const struct i2c_client *client, const char *buf, int count) -{ - int ret; - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; - - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.len = count; - msg.buf = (char *)buf; - - ret = i2c_transfer(adap, &msg, 1); - - /* - * If everything went ok (i.e. 1 msg transmitted), return #bytes - * transmitted, else error code. - */ - return (ret == 1) ? count : ret; -} -EXPORT_SYMBOL(i2c_master_send); - -/** - * i2c_master_recv - issue a single I2C message in master receive mode + * i2c_transfer_buffer_flags - issue a single I2C message transferring data + * to/from a buffer * @client: Handle to slave device - * @buf: Where to store data read from slave - * @count: How many bytes to read, must be less than 64k since msg.len is u16 + * @buf: Where the data is stored + * @count: How many bytes to transfer, must be less than 64k since msg.len is u16 + * @flags: The flags to be used for the message, e.g. I2C_M_RD for reads * - * Returns negative errno, or else the number of bytes read. + * Returns negative errno, or else the number of bytes transferred. */ -int i2c_master_recv(const struct i2c_client *client, char *buf, int count) +int i2c_transfer_buffer_flags(const struct i2c_client *client, char *buf, + int count, u16 flags) { - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg; int ret; + struct i2c_msg msg = { + .addr = client->addr, + .flags = flags | (client->flags & I2C_M_TEN), + .len = count, + .buf = buf, + }; - msg.addr = client->addr; - msg.flags = client->flags & I2C_M_TEN; - msg.flags |= I2C_M_RD; - msg.len = count; - msg.buf = buf; - - ret = i2c_transfer(adap, &msg, 1); + ret = i2c_transfer(client->adapter, &msg, 1); /* - * If everything went ok (i.e. 1 msg received), return #bytes received, - * else error code. + * If everything went ok (i.e. 1 msg transferred), return #bytes + * transferred, else error code. */ return (ret == 1) ? count : ret; } -EXPORT_SYMBOL(i2c_master_recv); +EXPORT_SYMBOL(i2c_transfer_buffer_flags); /* ---------------------------------------------------- * the i2c address scanning function @@ -2241,6 +2199,52 @@ void i2c_put_adapter(struct i2c_adapter *adap) } EXPORT_SYMBOL(i2c_put_adapter); +/** + * i2c_get_dma_safe_msg_buf() - get a DMA safe buffer for the given i2c_msg + * @msg: the message to be checked + * @threshold: the minimum number of bytes for which using DMA makes sense + * + * Return: NULL if a DMA safe buffer was not obtained. Use msg->buf with PIO. + * Or a valid pointer to be used with DMA. After use, release it by + * calling i2c_release_dma_safe_msg_buf(). + * + * This function must only be called from process context! + */ +u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold) +{ + if (msg->len < threshold) + return NULL; + + if (msg->flags & I2C_M_DMA_SAFE) + return msg->buf; + + pr_debug("using bounce buffer for addr=0x%02x, len=%d\n", + msg->addr, msg->len); + + if (msg->flags & I2C_M_RD) + return kzalloc(msg->len, GFP_KERNEL); + else + return kmemdup(msg->buf, msg->len, GFP_KERNEL); +} +EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf); + +/** + * i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg + * @msg: the message to be synced with + * @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL. + */ +void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf) +{ + if (!buf || buf == msg->buf) + return; + + if (msg->flags & I2C_M_RD) + memcpy(msg->buf, buf, msg->len); + + kfree(buf); +} +EXPORT_SYMBOL_GPL(i2c_release_dma_safe_msg_buf); + MODULE_AUTHOR("Simon G. Vogl <[email protected]>"); MODULE_DESCRIPTION("I2C-Bus main module"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index 10f00a82ec9d..59d5cf376f6a 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -17,6 +17,8 @@ #include <linux/device.h> #include <linux/err.h> #include <linux/i2c.h> +#include <linux/i2c-smbus.h> +#include <linux/slab.h> #define CREATE_TRACE_POINTS #include <trace/events/smbus.h> @@ -290,6 +292,22 @@ s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, } EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); +static void i2c_smbus_try_get_dmabuf(struct i2c_msg *msg, u8 init_val) +{ + bool is_read = msg->flags & I2C_M_RD; + unsigned char *dma_buf; + + dma_buf = kzalloc(I2C_SMBUS_BLOCK_MAX + (is_read ? 2 : 3), GFP_KERNEL); + if (!dma_buf) + return; + + msg->buf = dma_buf; + msg->flags |= I2C_M_DMA_SAFE; + + if (init_val) + msg->buf[0] = init_val; +} + /* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, @@ -367,6 +385,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ + i2c_smbus_try_get_dmabuf(&msg[1], 0); } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { @@ -375,8 +394,10 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->block[0]); return -EINVAL; } + + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i < msg[0].len; i++) - msgbuf0[i] = data->block[i-1]; + msg[0].buf[i] = data->block[i - 1]; } break; case I2C_SMBUS_BLOCK_PROC_CALL: @@ -388,26 +409,34 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, data->block[0]); return -EINVAL; } + msg[0].len = data->block[0] + 2; + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i < msg[0].len; i++) - msgbuf0[i] = data->block[i-1]; + msg[0].buf[i] = data->block[i - 1]; + msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ + i2c_smbus_try_get_dmabuf(&msg[1], 0); break; case I2C_SMBUS_I2C_BLOCK_DATA: + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { + dev_err(&adapter->dev, "Invalid block %s size %d\n", + read_write == I2C_SMBUS_READ ? "read" : "write", + data->block[0]); + return -EINVAL; + } + if (read_write == I2C_SMBUS_READ) { msg[1].len = data->block[0]; + i2c_smbus_try_get_dmabuf(&msg[1], 0); } else { msg[0].len = data->block[0] + 1; - if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { - dev_err(&adapter->dev, - "Invalid block write size %d\n", - data->block[0]); - return -EINVAL; - } + + i2c_smbus_try_get_dmabuf(&msg[0], command); for (i = 1; i <= data->block[0]; i++) - msgbuf0[i] = data->block[i]; + msg[0].buf[i] = data->block[i]; } break; default: @@ -455,14 +484,20 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, break; case I2C_SMBUS_I2C_BLOCK_DATA: for (i = 0; i < data->block[0]; i++) - data->block[i+1] = msgbuf1[i]; + data->block[i + 1] = msg[1].buf[i]; break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: - for (i = 0; i < msgbuf1[0] + 1; i++) - data->block[i] = msgbuf1[i]; + for (i = 0; i < msg[1].buf[0] + 1; i++) + data->block[i] = msg[1].buf[i]; break; } + + if (msg[0].flags & I2C_M_DMA_SAFE) + kfree(msg[0].buf); + if (msg[1].flags & I2C_M_DMA_SAFE) + kfree(msg[1].buf); + return 0; } @@ -592,3 +627,57 @@ s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, return i; } EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); + +/** + * i2c_setup_smbus_alert - Setup SMBus alert support + * @adapter: the target adapter + * @setup: setup data for the SMBus alert handler + * Context: can sleep + * + * Setup handling of the SMBus alert protocol on a given I2C bus segment. + * + * Handling can be done either through our IRQ handler, or by the + * adapter (from its handler, periodic polling, or whatever). + * + * NOTE that if we manage the IRQ, we *MUST* know if it's level or + * edge triggered in order to hand it to the workqueue correctly. + * If triggering the alert seems to wedge the system, you probably + * should have said it's level triggered. + * + * This returns the ara client, which should be saved for later use with + * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL + * to indicate an error. + */ +struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, + struct i2c_smbus_alert_setup *setup) +{ + struct i2c_board_info ara_board_info = { + I2C_BOARD_INFO("smbus_alert", 0x0c), + .platform_data = setup, + }; + + return i2c_new_device(adapter, &ara_board_info); +} +EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); + +#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF) +int of_i2c_setup_smbus_alert(struct i2c_adapter *adapter) +{ + struct i2c_client *client; + int irq; + + irq = of_property_match_string(adapter->dev.of_node, "interrupt-names", + "smbus_alert"); + if (irq == -EINVAL || irq == -ENODATA) + return 0; + else if (irq < 0) + return irq; + + client = i2c_setup_smbus_alert(adapter, NULL); + if (!client) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert); +#endif diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 6f638bbc922d..036a03f0d0a6 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -35,6 +35,7 @@ #include <linux/notifier.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/compat.h> /* * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a @@ -238,48 +239,33 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) } static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, - unsigned long arg) + unsigned nmsgs, struct i2c_msg *msgs) { - struct i2c_rdwr_ioctl_data rdwr_arg; - struct i2c_msg *rdwr_pa; u8 __user **data_ptrs; int i, res; - if (copy_from_user(&rdwr_arg, - (struct i2c_rdwr_ioctl_data __user *)arg, - sizeof(rdwr_arg))) - return -EFAULT; - - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) - return -EINVAL; - - rdwr_pa = memdup_user(rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg)); - if (IS_ERR(rdwr_pa)) - return PTR_ERR(rdwr_pa); - - data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); + data_ptrs = kmalloc(nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { - kfree(rdwr_pa); + kfree(msgs); return -ENOMEM; } res = 0; - for (i = 0; i < rdwr_arg.nmsgs; i++) { + for (i = 0; i < nmsgs; i++) { /* Limit the size of the message to a sane amount */ - if (rdwr_pa[i].len > 8192) { + if (msgs[i].len > 8192) { res = -EINVAL; break; } - data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; - rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len); - if (IS_ERR(rdwr_pa[i].buf)) { - res = PTR_ERR(rdwr_pa[i].buf); + data_ptrs[i] = (u8 __user *)msgs[i].buf; + msgs[i].buf = memdup_user(data_ptrs[i], msgs[i].len); + if (IS_ERR(msgs[i].buf)) { + res = PTR_ERR(msgs[i].buf); break; } + /* memdup_user allocates with GFP_KERNEL, so DMA is ok */ + msgs[i].flags |= I2C_M_DMA_SAFE; /* * If the message length is received from the slave (similar @@ -292,121 +278,117 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, * greater (for example to account for a checksum byte at * the end of the message.) */ - if (rdwr_pa[i].flags & I2C_M_RECV_LEN) { - if (!(rdwr_pa[i].flags & I2C_M_RD) || - rdwr_pa[i].buf[0] < 1 || - rdwr_pa[i].len < rdwr_pa[i].buf[0] + + if (msgs[i].flags & I2C_M_RECV_LEN) { + if (!(msgs[i].flags & I2C_M_RD) || + msgs[i].buf[0] < 1 || + msgs[i].len < msgs[i].buf[0] + I2C_SMBUS_BLOCK_MAX) { res = -EINVAL; break; } - rdwr_pa[i].len = rdwr_pa[i].buf[0]; + msgs[i].len = msgs[i].buf[0]; } } if (res < 0) { int j; for (j = 0; j < i; ++j) - kfree(rdwr_pa[j].buf); + kfree(msgs[j].buf); kfree(data_ptrs); - kfree(rdwr_pa); + kfree(msgs); return res; } - res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); + res = i2c_transfer(client->adapter, msgs, nmsgs); while (i-- > 0) { - if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { - if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, - rdwr_pa[i].len)) + if (res >= 0 && (msgs[i].flags & I2C_M_RD)) { + if (copy_to_user(data_ptrs[i], msgs[i].buf, + msgs[i].len)) res = -EFAULT; } - kfree(rdwr_pa[i].buf); + kfree(msgs[i].buf); } kfree(data_ptrs); - kfree(rdwr_pa); + kfree(msgs); return res; } static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, - unsigned long arg) + u8 read_write, u8 command, u32 size, + union i2c_smbus_data __user *data) { - struct i2c_smbus_ioctl_data data_arg; union i2c_smbus_data temp = {}; int datasize, res; - if (copy_from_user(&data_arg, - (struct i2c_smbus_ioctl_data __user *) arg, - sizeof(struct i2c_smbus_ioctl_data))) - return -EFAULT; - if ((data_arg.size != I2C_SMBUS_BYTE) && - (data_arg.size != I2C_SMBUS_QUICK) && - (data_arg.size != I2C_SMBUS_BYTE_DATA) && - (data_arg.size != I2C_SMBUS_WORD_DATA) && - (data_arg.size != I2C_SMBUS_PROC_CALL) && - (data_arg.size != I2C_SMBUS_BLOCK_DATA) && - (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && - (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && - (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { + if ((size != I2C_SMBUS_BYTE) && + (size != I2C_SMBUS_QUICK) && + (size != I2C_SMBUS_BYTE_DATA) && + (size != I2C_SMBUS_WORD_DATA) && + (size != I2C_SMBUS_PROC_CALL) && + (size != I2C_SMBUS_BLOCK_DATA) && + (size != I2C_SMBUS_I2C_BLOCK_BROKEN) && + (size != I2C_SMBUS_I2C_BLOCK_DATA) && + (size != I2C_SMBUS_BLOCK_PROC_CALL)) { dev_dbg(&client->adapter->dev, "size out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.size); + size); return -EINVAL; } /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, so the check is valid if size==I2C_SMBUS_QUICK too. */ - if ((data_arg.read_write != I2C_SMBUS_READ) && - (data_arg.read_write != I2C_SMBUS_WRITE)) { + if ((read_write != I2C_SMBUS_READ) && + (read_write != I2C_SMBUS_WRITE)) { dev_dbg(&client->adapter->dev, "read_write out of range (%x) in ioctl I2C_SMBUS.\n", - data_arg.read_write); + read_write); return -EINVAL; } /* Note that command values are always valid! */ - if ((data_arg.size == I2C_SMBUS_QUICK) || - ((data_arg.size == I2C_SMBUS_BYTE) && - (data_arg.read_write == I2C_SMBUS_WRITE))) + if ((size == I2C_SMBUS_QUICK) || + ((size == I2C_SMBUS_BYTE) && + (read_write == I2C_SMBUS_WRITE))) /* These are special: we do not use data */ return i2c_smbus_xfer(client->adapter, client->addr, - client->flags, data_arg.read_write, - data_arg.command, data_arg.size, NULL); + client->flags, read_write, + command, size, NULL); - if (data_arg.data == NULL) { + if (data == NULL) { dev_dbg(&client->adapter->dev, "data is NULL pointer in ioctl I2C_SMBUS.\n"); return -EINVAL; } - if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || - (data_arg.size == I2C_SMBUS_BYTE)) - datasize = sizeof(data_arg.data->byte); - else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || - (data_arg.size == I2C_SMBUS_PROC_CALL)) - datasize = sizeof(data_arg.data->word); + if ((size == I2C_SMBUS_BYTE_DATA) || + (size == I2C_SMBUS_BYTE)) + datasize = sizeof(data->byte); + else if ((size == I2C_SMBUS_WORD_DATA) || + (size == I2C_SMBUS_PROC_CALL)) + datasize = sizeof(data->word); else /* size == smbus block, i2c block, or block proc. call */ - datasize = sizeof(data_arg.data->block); + datasize = sizeof(data->block); - if ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || - (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || - (data_arg.read_write == I2C_SMBUS_WRITE)) { - if (copy_from_user(&temp, data_arg.data, datasize)) + if ((size == I2C_SMBUS_PROC_CALL) || + (size == I2C_SMBUS_BLOCK_PROC_CALL) || + (size == I2C_SMBUS_I2C_BLOCK_DATA) || + (read_write == I2C_SMBUS_WRITE)) { + if (copy_from_user(&temp, data, datasize)) return -EFAULT; } - if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { + if (size == I2C_SMBUS_I2C_BLOCK_BROKEN) { /* Convert old I2C block commands to the new convention. This preserves binary compatibility. */ - data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; - if (data_arg.read_write == I2C_SMBUS_READ) + size = I2C_SMBUS_I2C_BLOCK_DATA; + if (read_write == I2C_SMBUS_READ) temp.block[0] = I2C_SMBUS_BLOCK_MAX; } res = i2c_smbus_xfer(client->adapter, client->addr, client->flags, - data_arg.read_write, data_arg.command, data_arg.size, &temp); - if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || - (data_arg.read_write == I2C_SMBUS_READ))) { - if (copy_to_user(data_arg.data, &temp, datasize)) + read_write, command, size, &temp); + if (!res && ((size == I2C_SMBUS_PROC_CALL) || + (size == I2C_SMBUS_BLOCK_PROC_CALL) || + (read_write == I2C_SMBUS_READ))) { + if (copy_to_user(data, &temp, datasize)) return -EFAULT; } return res; @@ -454,12 +436,39 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) funcs = i2c_get_functionality(client->adapter); return put_user(funcs, (unsigned long __user *)arg); - case I2C_RDWR: - return i2cdev_ioctl_rdwr(client, arg); + case I2C_RDWR: { + struct i2c_rdwr_ioctl_data rdwr_arg; + struct i2c_msg *rdwr_pa; + + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data __user *)arg, + sizeof(rdwr_arg))) + return -EFAULT; + + /* Put an arbitrary limit on the number of messages that can + * be sent at once */ + if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) + return -EINVAL; - case I2C_SMBUS: - return i2cdev_ioctl_smbus(client, arg); + rdwr_pa = memdup_user(rdwr_arg.msgs, + rdwr_arg.nmsgs * sizeof(struct i2c_msg)); + if (IS_ERR(rdwr_pa)) + return PTR_ERR(rdwr_pa); + + return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + } + case I2C_SMBUS: { + struct i2c_smbus_ioctl_data data_arg; + if (copy_from_user(&data_arg, + (struct i2c_smbus_ioctl_data __user *) arg, + sizeof(struct i2c_smbus_ioctl_data))) + return -EFAULT; + return i2cdev_ioctl_smbus(client, data_arg.read_write, + data_arg.command, + data_arg.size, + data_arg.data); + } case I2C_RETRIES: client->adapter->retries = arg; break; @@ -480,6 +489,90 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; } +#ifdef CONFIG_COMPAT + +struct i2c_smbus_ioctl_data32 { + u8 read_write; + u8 command; + u32 size; + compat_caddr_t data; /* union i2c_smbus_data *data */ +}; + +struct i2c_msg32 { + u16 addr; + u16 flags; + u16 len; + compat_caddr_t buf; +}; + +struct i2c_rdwr_ioctl_data32 { + compat_caddr_t msgs; /* struct i2c_msg __user *msgs */ + u32 nmsgs; +}; + +static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = file->private_data; + unsigned long funcs; + switch (cmd) { + case I2C_FUNCS: + funcs = i2c_get_functionality(client->adapter); + return put_user(funcs, (compat_ulong_t __user *)arg); + case I2C_RDWR: { + struct i2c_rdwr_ioctl_data32 rdwr_arg; + struct i2c_msg32 *p; + struct i2c_msg *rdwr_pa; + int i; + + if (copy_from_user(&rdwr_arg, + (struct i2c_rdwr_ioctl_data32 __user *)arg, + sizeof(rdwr_arg))) + return -EFAULT; + + if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) + return -EINVAL; + + rdwr_pa = kmalloc_array(rdwr_arg.nmsgs, sizeof(struct i2c_msg), + GFP_KERNEL); + if (!rdwr_pa) + return -ENOMEM; + + p = compat_ptr(rdwr_arg.msgs); + for (i = 0; i < rdwr_arg.nmsgs; i++) { + struct i2c_msg32 umsg; + if (copy_from_user(&umsg, p + i, sizeof(umsg))) { + kfree(rdwr_pa); + return -EFAULT; + } + rdwr_pa[i] = (struct i2c_msg) { + .addr = umsg.addr, + .flags = umsg.flags, + .len = umsg.len, + .buf = compat_ptr(umsg.buf) + }; + } + + return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + } + case I2C_SMBUS: { + struct i2c_smbus_ioctl_data32 data32; + if (copy_from_user(&data32, + (void __user *) arg, + sizeof(data32))) + return -EFAULT; + return i2cdev_ioctl_smbus(client, data32.read_write, + data32.command, + data32.size, + compat_ptr(data32.data)); + } + default: + return i2cdev_ioctl(file, cmd, arg); + } +} +#else +#define compat_i2cdev_ioctl NULL +#endif + static int i2cdev_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); @@ -527,6 +620,7 @@ static const struct file_operations i2cdev_fops = { .read = i2cdev_read, .write = i2cdev_write, .unlocked_ioctl = i2cdev_ioctl, + .compat_ioctl = compat_i2cdev_ioctl, .open = i2cdev_open, .release = i2cdev_release, }; diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index f9271c713d20..5a1dd7f13bac 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -21,12 +21,11 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_irq.h> #include <linux/slab.h> #include <linux/workqueue.h> struct i2c_smbus_alert { - unsigned int alert_edge_triggered:1; - int irq; struct work_struct alert; struct i2c_client *ara; /* Alert response address */ }; @@ -72,13 +71,12 @@ static int smbus_do_alert(struct device *dev, void *addrp) * The alert IRQ handler needs to hand work off to a task which can issue * SMBus calls, because those sleeping calls can't be made in IRQ context. */ -static void smbus_alert(struct work_struct *work) +static irqreturn_t smbus_alert(int irq, void *d) { - struct i2c_smbus_alert *alert; + struct i2c_smbus_alert *alert = d; struct i2c_client *ara; unsigned short prev_addr = 0; /* Not a valid address */ - alert = container_of(work, struct i2c_smbus_alert, alert); ara = alert->ara; for (;;) { @@ -115,21 +113,17 @@ static void smbus_alert(struct work_struct *work) prev_addr = data.addr; } - /* We handled all alerts; re-enable level-triggered IRQs */ - if (!alert->alert_edge_triggered) - enable_irq(alert->irq); + return IRQ_HANDLED; } -static irqreturn_t smbalert_irq(int irq, void *d) +static void smbalert_work(struct work_struct *work) { - struct i2c_smbus_alert *alert = d; + struct i2c_smbus_alert *alert; - /* Disable level-triggered IRQs until we handle them */ - if (!alert->alert_edge_triggered) - disable_irq_nosync(irq); + alert = container_of(work, struct i2c_smbus_alert, alert); + + smbus_alert(0, alert); - schedule_work(&alert->alert); - return IRQ_HANDLED; } /* Setup SMBALERT# infrastructure */ @@ -139,28 +133,35 @@ static int smbalert_probe(struct i2c_client *ara, struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev); struct i2c_smbus_alert *alert; struct i2c_adapter *adapter = ara->adapter; - int res; + int res, irq; alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), GFP_KERNEL); if (!alert) return -ENOMEM; - alert->alert_edge_triggered = setup->alert_edge_triggered; - alert->irq = setup->irq; - INIT_WORK(&alert->alert, smbus_alert); + if (setup) { + irq = setup->irq; + } else { + irq = of_irq_get_byname(adapter->dev.of_node, "smbus_alert"); + if (irq <= 0) + return irq; + } + + INIT_WORK(&alert->alert, smbalert_work); alert->ara = ara; - if (setup->irq > 0) { - res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq, - 0, "smbus_alert", alert); + if (irq > 0) { + res = devm_request_threaded_irq(&ara->dev, irq, + NULL, smbus_alert, + IRQF_SHARED | IRQF_ONESHOT, + "smbus_alert", alert); if (res) return res; } i2c_set_clientdata(ara, alert); - dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n", - setup->alert_edge_triggered ? "edge" : "level"); + dev_info(&adapter->dev, "supports SMBALERT#\n"); return 0; } @@ -190,38 +191,6 @@ static struct i2c_driver smbalert_driver = { }; /** - * i2c_setup_smbus_alert - Setup SMBus alert support - * @adapter: the target adapter - * @setup: setup data for the SMBus alert handler - * Context: can sleep - * - * Setup handling of the SMBus alert protocol on a given I2C bus segment. - * - * Handling can be done either through our IRQ handler, or by the - * adapter (from its handler, periodic polling, or whatever). - * - * NOTE that if we manage the IRQ, we *MUST* know if it's level or - * edge triggered in order to hand it to the workqueue correctly. - * If triggering the alert seems to wedge the system, you probably - * should have said it's level triggered. - * - * This returns the ara client, which should be saved for later use with - * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL - * to indicate an error. - */ -struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, - struct i2c_smbus_alert_setup *setup) -{ - struct i2c_board_info ara_board_info = { - I2C_BOARD_INFO("smbus_alert", 0x0c), - .platform_data = setup, - }; - - return i2c_new_device(adapter, &ara_board_info); -} -EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert); - -/** * i2c_handle_smbus_alert - Handle an SMBus alert * @ara: the ARA client on the relevant adapter * Context: can't sleep diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 0f5c8fc36625..52a4a922e7e6 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -64,11 +64,11 @@ config I2C_MUX_PCA9541 will be called i2c-mux-pca9541. config I2C_MUX_PCA954x - tristate "Philips PCA954x I2C Mux/switches" + tristate "NXP PCA954x and PCA984x I2C Mux/switches" depends on GPIOLIB || COMPILE_TEST help - If you say yes here you get support for the Philips PCA954x - I2C mux/switch devices. + If you say yes here you get support for the NXP PCA954x + and PCA984x I2C mux/switch devices. This driver can also be built as a module. If so, the module will be called i2c-mux-pca954x. diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 7b992db38021..fbb84c7ef282 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -4,11 +4,11 @@ * Copyright (c) 2008-2009 Rodolfo Giometti <[email protected]> * Copyright (c) 2008-2009 Eurotech S.p.A. <[email protected]> * - * This module supports the PCA954x series of I2C multiplexer/switch chips - * made by Philips Semiconductors. + * This module supports the PCA954x and PCA954x series of I2C multiplexer/switch + * chips made by NXP Semiconductors. * This includes the: - * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547 - * and PCA9548. + * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547, + * PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849. * * These chips are all controlled via the I2C bus itself, and all have a * single 8-bit register. The upstream "parent" bus fans out to two, @@ -63,6 +63,10 @@ enum pca_type { pca_9546, pca_9547, pca_9548, + pca_9846, + pca_9847, + pca_9848, + pca_9849, }; struct chip_desc { @@ -129,6 +133,24 @@ static const struct chip_desc chips[] = { .nchans = 8, .muxtype = pca954x_isswi, }, + [pca_9846] = { + .nchans = 4, + .muxtype = pca954x_isswi, + }, + [pca_9847] = { + .nchans = 8, + .enable = 0x8, + .muxtype = pca954x_ismux, + }, + [pca_9848] = { + .nchans = 8, + .muxtype = pca954x_isswi, + }, + [pca_9849] = { + .nchans = 4, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, }; static const struct i2c_device_id pca954x_id[] = { @@ -140,6 +162,10 @@ static const struct i2c_device_id pca954x_id[] = { { "pca9546", pca_9546 }, { "pca9547", pca_9547 }, { "pca9548", pca_9548 }, + { "pca9846", pca_9846 }, + { "pca9847", pca_9847 }, + { "pca9848", pca_9848 }, + { "pca9849", pca_9849 }, { } }; MODULE_DEVICE_TABLE(i2c, pca954x_id); @@ -154,6 +180,10 @@ static const struct of_device_id pca954x_of_match[] = { { .compatible = "nxp,pca9546", .data = &chips[pca_9546] }, { .compatible = "nxp,pca9547", .data = &chips[pca_9547] }, { .compatible = "nxp,pca9548", .data = &chips[pca_9548] }, + { .compatible = "nxp,pca9846", .data = &chips[pca_9846] }, + { .compatible = "nxp,pca9847", .data = &chips[pca_9847] }, + { .compatible = "nxp,pca9848", .data = &chips[pca_9848] }, + { .compatible = "nxp,pca9849", .data = &chips[pca_9849] }, {} }; MODULE_DEVICE_TABLE(of, pca954x_of_match); @@ -246,36 +276,6 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) return handled ? IRQ_HANDLED : IRQ_NONE; } -static void pca954x_irq_mask(struct irq_data *idata) -{ - struct pca954x *data = irq_data_get_irq_chip_data(idata); - unsigned int pos = idata->hwirq; - unsigned long flags; - - raw_spin_lock_irqsave(&data->lock, flags); - - data->irq_mask &= ~BIT(pos); - if (!data->irq_mask) - disable_irq(data->client->irq); - - raw_spin_unlock_irqrestore(&data->lock, flags); -} - -static void pca954x_irq_unmask(struct irq_data *idata) -{ - struct pca954x *data = irq_data_get_irq_chip_data(idata); - unsigned int pos = idata->hwirq; - unsigned long flags; - - raw_spin_lock_irqsave(&data->lock, flags); - - if (!data->irq_mask) - enable_irq(data->client->irq); - data->irq_mask |= BIT(pos); - - raw_spin_unlock_irqrestore(&data->lock, flags); -} - static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) { if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW) @@ -285,8 +285,6 @@ static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type) static struct irq_chip pca954x_irq_chip = { .name = "i2c-mux-pca954x", - .irq_mask = pca954x_irq_mask, - .irq_unmask = pca954x_irq_unmask, .irq_set_type = pca954x_irq_set_type, }; @@ -294,7 +292,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) { struct pca954x *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; - int c, err, irq; + int c, irq; if (!data->chip->has_irq || client->irq <= 0) return 0; @@ -309,29 +307,31 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) for (c = 0; c < data->chip->nchans; c++) { irq = irq_create_mapping(data->irq, c); + if (!irq) { + dev_err(&client->dev, "failed irq create map\n"); + return -EINVAL; + } irq_set_chip_data(irq, data); irq_set_chip_and_handler(irq, &pca954x_irq_chip, handle_simple_irq); } - err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL, - pca954x_irq_handler, - IRQF_ONESHOT | IRQF_SHARED, - "pca954x", data); - if (err) - goto err_req_irq; + return 0; +} - disable_irq(data->client->irq); +static void pca954x_cleanup(struct i2c_mux_core *muxc) +{ + struct pca954x *data = i2c_mux_priv(muxc); + int c, irq; - return 0; -err_req_irq: - for (c = 0; c < data->chip->nchans; c++) { - irq = irq_find_mapping(data->irq, c); - irq_dispose_mapping(irq); + if (data->irq) { + for (c = 0; c < data->chip->nchans; c++) { + irq = irq_find_mapping(data->irq, c); + irq_dispose_mapping(irq); + } + irq_domain_remove(data->irq); } - irq_domain_remove(data->irq); - - return err; + i2c_mux_del_adapters(muxc); } /* @@ -391,7 +391,7 @@ static int pca954x_probe(struct i2c_client *client, ret = pca954x_irq_setup(muxc); if (ret) - goto fail_del_adapters; + goto fail_cleanup; /* Now create an adapter for each channel */ for (num = 0; num < data->chip->nchans; num++) { @@ -414,7 +414,16 @@ static int pca954x_probe(struct i2c_client *client, ret = i2c_mux_add_adapter(muxc, force, num, class); if (ret) - goto fail_del_adapters; + goto fail_cleanup; + } + + if (data->irq) { + ret = devm_request_threaded_irq(&client->dev, data->client->irq, + NULL, pca954x_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + "pca954x", data); + if (ret) + goto fail_cleanup; } dev_info(&client->dev, @@ -424,26 +433,16 @@ static int pca954x_probe(struct i2c_client *client, return 0; -fail_del_adapters: - i2c_mux_del_adapters(muxc); +fail_cleanup: + pca954x_cleanup(muxc); return ret; } static int pca954x_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); - struct pca954x *data = i2c_mux_priv(muxc); - int c, irq; - - if (data->irq) { - for (c = 0; c < data->chip->nchans; c++) { - irq = irq_find_mapping(data->irq, c); - irq_dispose_mapping(irq); - } - irq_domain_remove(data->irq); - } - i2c_mux_del_adapters(muxc); + pca954x_cleanup(muxc); return 0; } diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index d97031804de8..c948e5a4cb04 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -107,9 +107,9 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, put_device(&adapter->dev); mux->data.n_values = of_get_child_count(np); - if (of_find_property(np, "little-endian", NULL)) { + if (of_property_read_bool(np, "little-endian")) { mux->data.little_endian = true; - } else if (of_find_property(np, "big-endian", NULL)) { + } else if (of_property_read_bool(np, "big-endian")) { mux->data.little_endian = false; } else { #if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : \ @@ -122,10 +122,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, #error Endianness not defined? #endif } - if (of_find_property(np, "write-only", NULL)) - mux->data.write_only = true; - else - mux->data.write_only = false; + mux->data.write_only = of_property_read_bool(np, "write-only"); values = devm_kzalloc(&pdev->dev, sizeof(*mux->data.values) * mux->data.n_values, @@ -180,6 +177,9 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) sizeof(mux->data)); } else { ret = i2c_mux_reg_probe_dt(mux, pdev); + if (ret == -EPROBE_DEFER) + return ret; + if (ret < 0) { dev_err(&pdev->dev, "Error parsing device tree"); return ret; |