summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-msm-v2.c124
-rw-r--r--drivers/i2c/busses/i2c-scmi.c4
-rw-r--r--drivers/i2c/i2c-boardinfo.c4
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;