diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/busses/i2c-msm-v2.c | 124 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-scmi.c | 4 | ||||
| -rw-r--r-- | drivers/i2c/i2c-boardinfo.c | 4 |
3 files changed, 75 insertions, 57 deletions
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index 4a9536d39b58..d72953f2df23 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -32,6 +32,8 @@ #include <linux/dma-mapping.h> #include <linux/i2c.h> #include <linux/of.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/msm-sps.h> #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> @@ -50,6 +52,9 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl, static int i2c_msm_pm_resume(struct device *dev); static void i2c_msm_pm_suspend(struct device *dev); static void i2c_msm_clk_path_init(struct i2c_msm_ctrl *ctrl); +static struct pinctrl_state * + i2c_msm_rsrcs_gpio_get_state(struct i2c_msm_ctrl *ctrl, + const char *name); static void i2c_msm_pm_pinctrl_state(struct i2c_msm_ctrl *ctrl, bool runtime_active); @@ -1269,10 +1274,10 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl) tx->dir, (SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_NWD)); - if (dma_desc_tx < 0) { + if (IS_ERR_OR_NULL(dma_desc_tx)) { dev_err(ctrl->dev, "error dmaengine_prep_slave_sg tx:%ld\n", PTR_ERR(dma_desc_tx)); - ret = PTR_ERR(dma_desc_tx); + ret = dma_desc_tx ? PTR_ERR(dma_desc_tx) : -ENOMEM; goto dma_xfer_end; } @@ -1287,11 +1292,11 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl) sg_rx_itr - sg_rx, rx->dir, (SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_NWD)); - if (dma_desc_rx < 0) { + if (IS_ERR_OR_NULL(dma_desc_rx)) { dev_err(ctrl->dev, "error dmaengine_prep_slave_sg rx:%ld\n", PTR_ERR(dma_desc_rx)); - ret = PTR_ERR(dma_desc_rx); + ret = dma_desc_rx ? PTR_ERR(dma_desc_rx) : -ENOMEM; goto dma_xfer_end; } @@ -1917,63 +1922,74 @@ static void i2c_msm_qup_init(struct i2c_msm_ctrl *ctrl) "error on verifying HW support (I2C_MAST_GEN=0)\n"); } -/* - * qup_i2c_try_recover_bus_busy: issue QUP bus clear command - */ -static int qup_i2c_try_recover_bus_busy(struct i2c_msm_ctrl *ctrl) +static void qup_i2c_recover_bit_bang(struct i2c_msm_ctrl *ctrl) { - int ret; - ulong min_sleep_usec; + int i, ret; + int gpio_clk; + int gpio_dat; + bool gpio_clk_status = false; + uint32_t status = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS); + struct pinctrl_state *bitbang; - /* call i2c_msm_qup_init() to set core in idle state */ - i2c_msm_qup_init(ctrl); - - /* must be in run state for bus clear */ - ret = i2c_msm_qup_state_set(ctrl, QUP_STATE_RUN); - if (ret < 0) { - dev_err(ctrl->dev, "error: bus clear fail to set run state\n"); - return ret; + dev_info(ctrl->dev, "Executing bus recovery procedure (9 clk pulse)\n"); + disable_irq(ctrl->rsrcs.irq); + if (!(status & (I2C_STATUS_BUS_ACTIVE)) || + (status & (I2C_STATUS_BUS_MASTER))) { + dev_warn(ctrl->dev, "unexpected i2c recovery call:0x%x\n", + status); + goto recovery_exit; } - /* - * call i2c_msm_qup_xfer_init_run_state() to set clock dividers. - * the dividers are necessary for bus clear. - */ - i2c_msm_qup_xfer_init_run_state(ctrl); + gpio_clk = of_get_named_gpio(ctrl->adapter.dev.of_node, "qcom,i2c-clk", + 0); + gpio_dat = of_get_named_gpio(ctrl->adapter.dev.of_node, "qcom,i2c-dat", + 0); - writel_relaxed(0x1, ctrl->rsrcs.base + QUP_I2C_MASTER_BUS_CLR); + if (gpio_clk < 0 || gpio_dat < 0) { + dev_warn(ctrl->dev, "SW bigbang err: i2c gpios not known\n"); + goto recovery_exit; + } - /* - * wait for recovery (9 clock pulse cycles) to complete. - * min_time = 9 clock *10 (1000% margin) - * max_time = 10* min_time - */ - min_sleep_usec = - max_t(ulong, (9 * 10 * USEC_PER_SEC) / ctrl->rsrcs.clk_freq_out, 100); + bitbang = i2c_msm_rsrcs_gpio_get_state(ctrl, "i2c_bitbang"); + if (bitbang) + ret = pinctrl_select_state(ctrl->rsrcs.pinctrl, bitbang); + if (!bitbang || ret) { + dev_err(ctrl->dev, "GPIO pins have no bitbang setting\n"); + goto recovery_exit; + } + for (i = 0; i < 10; i++) { + if (gpio_get_value(gpio_dat) && gpio_clk_status) + break; + gpio_direction_output(gpio_clk, 0); + udelay(5); + gpio_direction_output(gpio_dat, 0); + udelay(5); + gpio_direction_input(gpio_clk); + udelay(5); + if (!gpio_get_value(gpio_clk)) + udelay(20); + if (!gpio_get_value(gpio_clk)) + usleep_range(10000, 10001); + gpio_clk_status = gpio_get_value(gpio_clk); + gpio_direction_input(gpio_dat); + udelay(5); + } - usleep_range(min_sleep_usec, min_sleep_usec * 10); - return ret; -} + i2c_msm_pm_pinctrl_state(ctrl, true); + udelay(10); -static int qup_i2c_recover_bus_busy(struct i2c_msm_ctrl *ctrl) -{ - u32 bus_clr, bus_active, status; - int retry = 0; - dev_info(ctrl->dev, "Executing bus recovery procedure (9 clk pulse)\n"); + status = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS); + if (!(status & I2C_STATUS_BUS_ACTIVE)) { + dev_info(ctrl->dev, + "Bus busy cleared after %d clock cycles, status %x\n", + i, status); + goto recovery_exit; + } - do { - qup_i2c_try_recover_bus_busy(ctrl); - bus_clr = readl_relaxed(ctrl->rsrcs.base + - QUP_I2C_MASTER_BUS_CLR); - status = readl_relaxed(ctrl->rsrcs.base + QUP_I2C_STATUS); - bus_active = status & I2C_STATUS_BUS_ACTIVE; - if (++retry >= I2C_QUP_MAX_BUS_RECOVERY_RETRY) - break; - } while (bus_clr || bus_active); + dev_warn(ctrl->dev, "Bus still busy, status %x\n", status); - dev_info(ctrl->dev, "Bus recovery %s after %d retries\n", - (bus_clr || bus_active) ? "fail" : "success", retry); - return 0; +recovery_exit: + enable_irq(ctrl->rsrcs.irq); } static int i2c_msm_qup_post_xfer(struct i2c_msm_ctrl *ctrl, int err) @@ -1984,7 +2000,7 @@ static int i2c_msm_qup_post_xfer(struct i2c_msm_ctrl *ctrl, int err) (ctrl->xfer.err == I2C_MSM_ERR_BUS_ERR) || (ctrl->xfer.err == I2C_MSM_ERR_TIMEOUT)) { if (i2c_msm_qup_slv_holds_bus(ctrl)) - qup_i2c_recover_bus_busy(ctrl); + qup_i2c_recover_bit_bang(ctrl); /* do not generalize error to EIO if its already set */ if (!err) @@ -2832,8 +2848,8 @@ static void i2c_msm_pm_rt_init(struct device *dev) {} static const struct dev_pm_ops i2c_msm_pm_ops = { #ifdef CONFIG_PM_SLEEP - .suspend_noirq = i2c_msm_pm_sys_suspend_noirq, - .resume_noirq = i2c_msm_pm_sys_resume_noirq, + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_msm_pm_sys_suspend_noirq, + i2c_msm_pm_sys_resume_noirq) #endif SET_RUNTIME_PM_OPS(i2c_msm_pm_rt_suspend, i2c_msm_pm_rt_resume, diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index dfc98df7b1b6..7aa7b9cb6203 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -18,6 +18,9 @@ #define ACPI_SMBUS_HC_CLASS "smbus" #define ACPI_SMBUS_HC_DEVICE_NAME "cmi" +/* SMBUS HID definition as supported by Microsoft Windows */ +#define ACPI_SMBUS_MS_HID "SMB0001" + ACPI_MODULE_NAME("smbus_cmi"); struct smbus_methods_t { @@ -51,6 +54,7 @@ static const struct smbus_methods_t ibm_smbus_methods = { static const struct acpi_device_id acpi_smbus_cmi_ids[] = { {"SMBUS01", (kernel_ulong_t)&smbus_methods}, {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, + {ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods}, {"", 0} }; MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 90e322959303..42c25aed671d 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -56,9 +56,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); * The board info passed can safely be __initdata, but be careful of embedded * pointers (for platform_data, functions, etc) since that won't be copied. */ -int __init -i2c_register_board_info(int busnum, - struct i2c_board_info const *info, unsigned len) +int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { int status; |
