Merge branch 'i2c/for-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wilfram Sang:
 "I2C has the following updates for you:

   - an immutable cross-subsystem branch fixing PMIC access on Intel
     Baytrail

   - bigger driver updates to the designware, meson, exynos5 drivers

   - new i2c_acpi_new_device() function to create devices from ACPI

   - struct i2c_driver has now a flag 'disable_i2c_core_irq_mapping' to
     allow custom IRQ mapping in case the default does not fit

   - mux subsystem centralized error messages in its core

   - new driver for ltc4306 i2c mux

   - usual set of small updates"

* 'i2c/for-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (44 commits)
  i2c: thunderx: Enable HWMON class probing
  i2c: rcar: clarify PM handling with more comments
  i2c: rcar: fix resume by always initializing registers before transfer
  i2c: tegra: fix spelling mistake: "contoller" -> "controller"
  i2c: exynos5: use core helper to get driver data
  i2c: exynos5: de-duplicate error logs on clock setup
  i2c: exynos5: simplify clock frequency handling
  i2c: exynos5: simplify timings calculation
  i2c: designware-baytrail: fix potential null pointer dereference on dev
  i2c: designware: Get selected speed mode sda-hold-time via ACPI
  [media] cx231xx: stop double error reporting
  i2c: core: Allow drivers to disable i2c-core irq mapping
  i2c: core: Add new i2c_acpi_new_device helper function
  i2c: core: Allow getting ACPI info by index
  i2c: img-scb: use setup_timer
  i2c: i2c-scmi: add a MS HID
  i2c: mux: ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
  dt-bindings: i2c: mux: ltc4306: Add dt-bindings for I2C multiplexer/switch
  i2c: mux: reg: stop double error reporting
  i2c: mux: pinctrl: stop double error reporting
  ...
This commit is contained in:
Linus Torvalds
2017-05-03 12:18:47 -07:00
31 changed files with 674 additions and 259 deletions
@@ -8,6 +8,8 @@ Required properties:
- #address-cells: should be <1>
- #size-cells: should be <0>
For details regarding the following core I2C bindings see also i2c.txt.
Optional properties:
- clock-frequency: the desired I2C bus clock frequency in Hz; in
absence of this property the default value is used (100 kHz).
@@ -0,0 +1,61 @@
* Linear Technology / Analog Devices I2C bus switch
Required Properties:
- compatible: Must contain one of the following.
"lltc,ltc4305", "lltc,ltc4306"
- reg: The I2C address of the device.
The following required properties are defined externally:
- Standard I2C mux properties. See i2c-mux.txt in this directory.
- I2C child bus nodes. See i2c-mux.txt in this directory.
Optional Properties:
- enable-gpios: Reference to the GPIO connected to the enable input.
- i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
children in idle state. This is necessary for example, if there are several
multiplexers on the bus and the devices behind them use same I2C addresses.
- gpio-controller: Marks the device node as a GPIO Controller.
- #gpio-cells: Should be two. The first cell is the pin number and
the second cell is used to specify flags.
See ../gpio/gpio.txt for more information.
- ltc,downstream-accelerators-enable: Enables the rise time accelerators
on the downstream port.
- ltc,upstream-accelerators-enable: Enables the rise time accelerators
on the upstream port.
Example:
ltc4306: i2c-mux@4a {
compatible = "lltc,ltc4306";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x4a>;
gpio-controller;
#gpio-cells = <2>;
i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
eeprom@50 {
compatible = "at,24c02";
reg = <0x50>;
};
};
i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
eeprom@50 {
compatible = "at,24c02";
reg = <0x50>;
};
};
};
@@ -11,6 +11,7 @@ Required properties :
- "rockchip,rk3188-i2c": for rk3188
- "rockchip,rk3228-i2c": for rk3228
- "rockchip,rk3288-i2c": for rk3288
- "rockchip,rk3328-i2c", "rockchip,rk3399-i2c": for rk3328
- "rockchip,rk3399-i2c": for rk3399
- interrupts : interrupt number
- clocks: See ../clock/clock-bindings.txt
+8
View File
@@ -7775,6 +7775,14 @@ S: Maintained
F: Documentation/hwmon/ltc4261
F: drivers/hwmon/ltc4261.c
LTC4306 I2C MULTIPLEXER DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
W: http://ez.analog.com/community/linux-device-drivers
L: linux-i2c@vger.kernel.org
S: Supported
F: drivers/i2c/muxes/i2c-mux-ltc4306.c
F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
LTP (Linux Test Project)
M: Mike Frysinger <vapier@gentoo.org>
M: Cyril Hrubis <chrubis@suse.cz>
+2 -1
View File
@@ -933,6 +933,7 @@ config I2C_TEGRA
config I2C_TEGRA_BPMP
tristate "NVIDIA Tegra BPMP I2C controller"
depends on TEGRA_BPMP
default y
help
If you say yes to this option, support will be included for the I2C
controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
@@ -1021,7 +1022,7 @@ config I2C_XLR
config I2C_XLP9XX
tristate "XLP9XX I2C support"
depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST
depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST
help
This driver enables support for the on-chip I2C interface of
the Broadcom XLP9xx/XLP5xx MIPS and Vulcan ARM64 processors.
+5 -3
View File
@@ -22,7 +22,7 @@
#include "i2c-designware-core.h"
#define SEMAPHORE_TIMEOUT 100
#define SEMAPHORE_TIMEOUT 500
#define PUNIT_SEMAPHORE 0x7
#define PUNIT_SEMAPHORE_CHT 0x10e
#define PUNIT_SEMAPHORE_BIT BIT(0)
@@ -70,7 +70,7 @@ static void reset_semaphore(struct dw_i2c_dev *dev)
static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
{
u32 addr = get_sem_addr(dev);
u32 addr;
u32 sem = PUNIT_SEMAPHORE_ACQUIRE;
int ret;
unsigned long start, end;
@@ -94,6 +94,8 @@ static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
*/
pm_qos_update_request(&dev->pm_qos, 0);
addr = get_sem_addr(dev);
/* host driver writes to side band semaphore register */
ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, addr, sem);
if (ret) {
@@ -170,7 +172,7 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
dev_info(dev->dev, "I2C bus managed by PUNIT\n");
dev->acquire_lock = baytrail_i2c_acquire;
dev->release_lock = baytrail_i2c_release;
dev->pm_runtime_disabled = true;
dev->pm_disabled = true;
pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
+9 -2
View File
@@ -960,6 +960,7 @@ EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
struct i2c_adapter *adap = &dev->adapter;
unsigned long irq_flags;
int r;
init_completion(&dev->cmd_complete);
@@ -975,9 +976,15 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev);
if (dev->pm_disabled) {
dev_pm_syscore_device(dev->dev, true);
irq_flags = IRQF_NO_SUSPEND;
} else {
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
}
i2c_dw_disable_int(dev);
r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
IRQF_SHARED | IRQF_COND_SUSPEND,
r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
dev_name(dev->dev), dev);
if (r) {
dev_err(dev->dev, "failure requesting irq %i: %d\n",
+2 -2
View File
@@ -79,7 +79,7 @@
* @pm_qos: pm_qos_request used while holding a hardware lock on the bus
* @acquire_lock: function to acquire a hardware lock on the bus
* @release_lock: function to release a hardware lock on the bus
* @pm_runtime_disabled: true if pm runtime is disabled
* @pm_disabled: true if power-management should be disabled for this i2c-bus
*
* HCNT and LCNT parameters can be used if the platform knows more accurate
* values than the one computed based only on the input clock frequency.
@@ -128,7 +128,7 @@ struct dw_i2c_dev {
struct pm_qos_request pm_qos;
int (*acquire_lock)(struct dw_i2c_dev *dev);
void (*release_lock)(struct dw_i2c_dev *dev);
bool pm_runtime_disabled;
bool pm_disabled;
};
#define ACCESS_SWAP 0x00000001
+41 -15
View File
@@ -85,8 +85,7 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
*hcnt = (u16)objs[0].integer.value;
*lcnt = (u16)objs[1].integer.value;
if (sda_hold)
*sda_hold = (u32)objs[2].integer.value;
*sda_hold = (u32)objs[2].integer.value;
}
kfree(buf.pointer);
@@ -95,26 +94,55 @@ static void dw_i2c_acpi_params(struct platform_device *pdev, char method[],
static int dw_i2c_acpi_configure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
const struct acpi_device_id *id;
struct acpi_device *adev;
const char *uid;
dev->adapter.nr = -1;
dev->tx_fifo_depth = 32;
dev->rx_fifo_depth = 32;
/*
* Try to get SDA hold time and *CNT values from an ACPI method if
* it exists for both supported speed modes.
* Try to get SDA hold time and *CNT values from an ACPI method for
* selected speed modes.
*/
dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, NULL);
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
&dev->sda_hold_time);
dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, NULL);
dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, NULL);
switch (dev->clk_freq) {
case 100000:
dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt,
&dev->sda_hold_time);
break;
case 1000000:
dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt,
&dev->sda_hold_time);
break;
case 3400000:
dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt,
&dev->sda_hold_time);
break;
case 400000:
default:
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
&dev->sda_hold_time);
break;
}
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id && id->driver_data)
dev->flags |= (u32)id->driver_data;
if (acpi_bus_get_device(handle, &adev))
return -ENODEV;
/*
* Cherrytrail I2C7 gets used for the PMIC which gets accessed
* through ACPI opregions during late suspend / early resume
* disable pm for it.
*/
uid = adev->pnp.unique_id;
if ((dev->flags & MODEL_CHERRYTRAIL) && !strcmp(uid, "7"))
dev->pm_disabled = true;
return 0;
}
@@ -286,7 +314,7 @@ 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_runtime_disabled) {
if (dev->pm_disabled) {
pm_runtime_forbid(&pdev->dev);
} else {
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
@@ -302,7 +330,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
return r;
exit_probe:
if (!dev->pm_runtime_disabled)
if (!dev->pm_disabled)
pm_runtime_disable(&pdev->dev);
exit_reset:
if (!IS_ERR_OR_NULL(dev->rst))
@@ -322,7 +350,7 @@ 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_runtime_disabled)
if (!dev->pm_disabled)
pm_runtime_disable(&pdev->dev);
if (!IS_ERR_OR_NULL(dev->rst))
reset_control_assert(dev->rst);
@@ -374,9 +402,7 @@ static int dw_i2c_plat_resume(struct device *dev)
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
i2c_dw_plat_prepare_clk(i_dev, true);
if (!i_dev->pm_runtime_disabled)
i2c_dw_init(i_dev);
i2c_dw_init(i_dev);
return 0;
}
+32 -84
View File
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
@@ -168,8 +169,6 @@
*/
#define HSI2C_HS_TX_CLOCK 1000000
#define HSI2C_FS_TX_CLOCK 100000
#define HSI2C_HIGH_SPD 1
#define HSI2C_FAST_SPD 0
#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -200,18 +199,10 @@ struct exynos5_i2c {
int trans_done;
/* Controller operating frequency */
unsigned int fs_clock;
unsigned int hs_clock;
/*
* HSI2C Controller can operate in
* 1. High speed upto 3.4Mbps
* 2. Fast speed upto 1Mbps
*/
int speed_mode;
unsigned int op_clock;
/* Version of HS-I2C Hardware */
struct exynos_hsi2c_variant *variant;
const struct exynos_hsi2c_variant *variant;
};
/**
@@ -257,15 +248,6 @@ static const struct of_device_id exynos5_i2c_match[] = {
};
MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant
(struct platform_device *pdev)
{
const struct of_device_id *match;
match = of_match_node(exynos5_i2c_match, pdev->dev.of_node);
return (struct exynos_hsi2c_variant *)match->data;
}
static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c)
{
writel(readl(i2c->regs + HSI2C_INT_STATUS),
@@ -279,7 +261,7 @@ static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c)
* Returns 0 on success, -EINVAL if the cycle length cannot
* be calculated.
*/
static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)
{
u32 i2c_timing_s1;
u32 i2c_timing_s2;
@@ -292,9 +274,10 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
unsigned int t_sr_release;
unsigned int t_ftl_cycle;
unsigned int clkin = clk_get_rate(i2c->clk);
unsigned int div, utemp0 = 0, utemp1 = 0, clk_cycle;
unsigned int op_clk = (mode == HSI2C_HIGH_SPD) ?
i2c->hs_clock : i2c->fs_clock;
unsigned int op_clk = hs_timings ? i2c->op_clock :
(i2c->op_clock >= HSI2C_HS_TX_CLOCK) ? HSI2C_FS_TX_CLOCK :
i2c->op_clock;
int div, clk_cycle, temp;
/*
* In case of HSI2C controller in Exynos5 series
@@ -305,33 +288,22 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
* FPCLK / FI2C =
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE
*
* utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
* utemp1 = (TSCLK_L + TSCLK_H + 2)
* clk_cycle := TSCLK_L + TSCLK_H
* temp := (CLK_DIV + 1) * (clk_cycle + 2)
*
* Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510
*
*/
t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;
utemp0 = (clkin / op_clk) - 8;
if (i2c->variant->hw == HSI2C_EXYNOS7)
utemp0 -= t_ftl_cycle;
else
utemp0 -= 2 * t_ftl_cycle;
/* CLK_DIV max is 256 */
for (div = 0; div < 256; div++) {
utemp1 = utemp0 / (div + 1);
/*
* SCL_L and SCL_H each has max value of 255
* Hence, For the clk_cycle to the have right value
* utemp1 has to be less then 512 and more than 4.
*/
if ((utemp1 < 512) && (utemp1 > 4)) {
clk_cycle = utemp1 - 2;
break;
} else if (div == 255) {
dev_warn(i2c->dev, "Failed to calculate divisor");
return -EINVAL;
}
temp = clkin / op_clk - 8 - t_ftl_cycle;
if (i2c->variant->hw != HSI2C_EXYNOS7)
temp -= t_ftl_cycle;
div = temp / 512;
clk_cycle = temp / (div + 1) - 2;
if (temp < 4 || div >= 256 || clk_cycle < 2) {
dev_err(i2c->dev, "%s clock set-up failed\n",
hs_timings ? "HS" : "FS");
return -EINVAL;
}
t_scl_l = clk_cycle / 2;
@@ -356,7 +328,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
div, t_sr_release);
dev_dbg(i2c->dev, "tDATA_HD: %X\n", t_data_hd);
if (mode == HSI2C_HIGH_SPD) {
if (hs_timings) {
writel(i2c_timing_s1, i2c->regs + HSI2C_TIMING_HS1);
writel(i2c_timing_s2, i2c->regs + HSI2C_TIMING_HS2);
writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3);
@@ -372,24 +344,13 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
static int exynos5_hsi2c_clock_setup(struct exynos5_i2c *i2c)
{
/*
* Configure the Fast speed timing values
* Even the High Speed mode initially starts with Fast mode
*/
if (exynos5_i2c_set_timing(i2c, HSI2C_FAST_SPD)) {
dev_err(i2c->dev, "HSI2C FS Clock set up failed\n");
return -EINVAL;
}
/* always set Fast Speed timings */
int ret = exynos5_i2c_set_timing(i2c, false);
/* configure the High speed timing values */
if (i2c->speed_mode == HSI2C_HIGH_SPD) {
if (exynos5_i2c_set_timing(i2c, HSI2C_HIGH_SPD)) {
dev_err(i2c->dev, "HSI2C HS Clock set up failed\n");
return -EINVAL;
}
}
if (ret < 0 || i2c->op_clock < HSI2C_HS_TX_CLOCK)
return ret;
return 0;
return exynos5_i2c_set_timing(i2c, true);
}
/*
@@ -409,7 +370,7 @@ static void exynos5_i2c_init(struct exynos5_i2c *i2c)
i2c->regs + HSI2C_CTL);
writel(HSI2C_TRAILING_COUNT, i2c->regs + HSI2C_TRAILIG_CTL);
if (i2c->speed_mode == HSI2C_HIGH_SPD) {
if (i2c->op_clock >= HSI2C_HS_TX_CLOCK) {
writel(HSI2C_MASTER_ID(MASTER_ID(i2c->adap.nr)),
i2c->regs + HSI2C_ADDR);
i2c_conf |= HSI2C_HS_MODE;
@@ -747,26 +708,14 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct exynos5_i2c *i2c;
struct resource *mem;
unsigned int op_clock;
int ret;
i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
if (of_property_read_u32(np, "clock-frequency", &op_clock)) {
i2c->speed_mode = HSI2C_FAST_SPD;
i2c->fs_clock = HSI2C_FS_TX_CLOCK;
} else {
if (op_clock >= HSI2C_HS_TX_CLOCK) {
i2c->speed_mode = HSI2C_HIGH_SPD;
i2c->fs_clock = HSI2C_FS_TX_CLOCK;
i2c->hs_clock = op_clock;
} else {
i2c->speed_mode = HSI2C_FAST_SPD;
i2c->fs_clock = op_clock;
}
}
if (of_property_read_u32(np, "clock-frequency", &i2c->op_clock))
i2c->op_clock = HSI2C_FS_TX_CLOCK;
strlcpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
@@ -817,8 +766,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
goto err_clk;
}
/* Need to check the variant before setting up. */
i2c->variant = exynos5_i2c_get_variant(pdev);
i2c->variant = of_device_get_match_data(&pdev->dev);
ret = exynos5_hsi2c_clock_setup(i2c);
if (ret)
+2 -3
View File
@@ -1362,9 +1362,8 @@ static int img_i2c_probe(struct platform_device *pdev)
}
/* Set up the exception check timer */
init_timer(&i2c->check_timer);
i2c->check_timer.function = img_i2c_check_timer;
i2c->check_timer.data = (unsigned long)i2c;
setup_timer(&i2c->check_timer, img_i2c_check_timer,
(unsigned long)i2c);
i2c->bitrate = timings[0].max_bitrate;
if (!of_property_read_u32(node, "clock-frequency", &val))
+52 -82
View File
@@ -35,10 +35,11 @@
#define REG_CTRL_STATUS BIT(2)
#define REG_CTRL_ERROR BIT(3)
#define REG_CTRL_CLKDIV_SHIFT 12
#define REG_CTRL_CLKDIV_MASK ((BIT(10) - 1) << REG_CTRL_CLKDIV_SHIFT)
#define REG_CTRL_CLKDIV_MASK GENMASK(21, 12)
#define REG_CTRL_CLKDIVEXT_SHIFT 28
#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, 28)
#define I2C_TIMEOUT_MS 500
#define DEFAULT_FREQ 100000
enum {
TOKEN_END = 0,
@@ -54,7 +55,6 @@ enum {
STATE_IDLE,
STATE_READ,
STATE_WRITE,
STATE_STOP,
};
/**
@@ -73,7 +73,6 @@ enum {
* @error: Flag set when an error is received
* @lock: To avoid race conditions between irq handler and xfer code
* @done: Completion used to wait for transfer termination
* @frequency: Operating frequency of I2C bus clock
* @tokens: Sequence of tokens to be written to the device
* @num_tokens: Number of tokens
*/
@@ -82,7 +81,6 @@ struct meson_i2c {
struct device *dev;
void __iomem *regs;
struct clk *clk;
int irq;
struct i2c_msg *msg;
int state;
@@ -93,7 +91,6 @@ struct meson_i2c {
spinlock_t lock;
struct completion done;
unsigned int frequency;
u32 tokens[2];
int num_tokens;
};
@@ -126,23 +123,27 @@ static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
i2c->num_tokens++;
}
static void meson_i2c_write_tokens(struct meson_i2c *i2c)
{
writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0);
writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1);
}
static void meson_i2c_set_clk_div(struct meson_i2c *i2c)
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, i2c->frequency * 4);
div = DIV_ROUND_UP(clk_rate, freq * 4);
/* clock divider has 12 bits */
if (div >= (1 << 12)) {
dev_err(i2c->dev, "requested bus frequency too low\n");
div = (1 << 12) - 1;
}
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
div << REG_CTRL_CLKDIV_SHIFT);
(div & GENMASK(9, 0)) << REG_CTRL_CLKDIV_SHIFT);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
(div >> 10) << REG_CTRL_CLKDIVEXT_SHIFT);
dev_dbg(i2c->dev, "%s: clk %lu, freq %u, div %u\n", __func__,
clk_rate, i2c->frequency, div);
clk_rate, freq, div);
}
static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len)
@@ -156,10 +157,10 @@ static void meson_i2c_get_data(struct meson_i2c *i2c, char *buf, int len)
dev_dbg(i2c->dev, "%s: data %08x %08x len %d\n", __func__,
rdata0, rdata1, len);
for (i = 0; i < min_t(int, 4, len); i++)
for (i = 0; i < min(4, len); i++)
*buf++ = (rdata0 >> i * 8) & 0xff;
for (i = 4; i < min_t(int, 8, len); i++)
for (i = 4; i < min(8, len); i++)
*buf++ = (rdata1 >> (i - 4) * 8) & 0xff;
}
@@ -168,10 +169,10 @@ static void meson_i2c_put_data(struct meson_i2c *i2c, char *buf, int len)
u32 wdata0 = 0, wdata1 = 0;
int i;
for (i = 0; i < min_t(int, 4, len); i++)
for (i = 0; i < min(4, len); i++)
wdata0 |= *buf++ << (i * 8);
for (i = 4; i < min_t(int, 8, len); i++)
for (i = 4; i < min(8, len); i++)
wdata1 |= *buf++ << ((i - 4) * 8);
writel(wdata0, i2c->regs + REG_TOK_WDATA0);
@@ -186,7 +187,7 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
bool write = !(i2c->msg->flags & I2C_M_RD);
int i;
i2c->count = min_t(int, i2c->msg->len - i2c->pos, 8);
i2c->count = min(i2c->msg->len - i2c->pos, 8);
for (i = 0; i < i2c->count - 1; i++)
meson_i2c_add_token(i2c, TOKEN_DATA);
@@ -200,19 +201,12 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
if (write)
meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
}
static void meson_i2c_stop(struct meson_i2c *i2c)
{
dev_dbg(i2c->dev, "%s: last %d\n", __func__, i2c->last);
if (i2c->last) {
i2c->state = STATE_STOP;
if (i2c->last && i2c->pos + i2c->count >= i2c->msg->len)
meson_i2c_add_token(i2c, TOKEN_STOP);
} else {
i2c->state = STATE_IDLE;
complete(&i2c->done);
}
writel(i2c->tokens[0], i2c->regs + REG_TOK_LIST0);
writel(i2c->tokens[1], i2c->regs + REG_TOK_LIST1);
}
static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
@@ -223,12 +217,18 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
spin_lock(&i2c->lock);
meson_i2c_reset_tokens(i2c);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
ctrl = readl(i2c->regs + REG_CTRL);
dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n",
i2c->state, i2c->pos, i2c->count, ctrl);
if (ctrl & REG_CTRL_ERROR && i2c->state != STATE_IDLE) {
if (i2c->state == STATE_IDLE) {
spin_unlock(&i2c->lock);
return IRQ_NONE;
}
if (ctrl & REG_CTRL_ERROR) {
/*
* The bit is set when the IGNORE_NAK bit is cleared
* and the device didn't respond. In this case, the
@@ -242,48 +242,21 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
goto out;
}
switch (i2c->state) {
case STATE_READ:
if (i2c->count > 0) {
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos,
i2c->count);
i2c->pos += i2c->count;
}
if (i2c->state == STATE_READ && i2c->count)
meson_i2c_get_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
if (i2c->pos >= i2c->msg->len) {
meson_i2c_stop(i2c);
break;
}
i2c->pos += i2c->count;
meson_i2c_prepare_xfer(i2c);
break;
case STATE_WRITE:
i2c->pos += i2c->count;
if (i2c->pos >= i2c->msg->len) {
meson_i2c_stop(i2c);
break;
}
meson_i2c_prepare_xfer(i2c);
break;
case STATE_STOP:
if (i2c->pos >= i2c->msg->len) {
i2c->state = STATE_IDLE;
complete(&i2c->done);
break;
case STATE_IDLE:
break;
goto out;
}
/* Restart the processing */
meson_i2c_prepare_xfer(i2c);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, REG_CTRL_START);
out:
if (i2c->state != STATE_IDLE) {
/* Restart the processing */
meson_i2c_write_tokens(i2c);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0);
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START,
REG_CTRL_START);
}
spin_unlock(&i2c->lock);
return IRQ_HANDLED;
@@ -323,7 +296,6 @@ static int meson_i2c_xfer_msg(struct meson_i2c *i2c, struct i2c_msg *msg,
i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
meson_i2c_prepare_xfer(i2c);
meson_i2c_write_tokens(i2c);
reinit_completion(&i2c->done);
/* Start the transfer */
@@ -359,21 +331,19 @@ static int meson_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num)
{
struct meson_i2c *i2c = adap->algo_data;
int i, ret = 0, count = 0;
int i, ret = 0;
clk_enable(i2c->clk);
meson_i2c_set_clk_div(i2c);
for (i = 0; i < num; i++) {
ret = meson_i2c_xfer_msg(i2c, msgs + i, i == num - 1);
if (ret)
break;
count++;
}
clk_disable(i2c->clk);
return ret ? ret : count;
return ret ?: i;
}
static u32 meson_i2c_func(struct i2c_adapter *adap)
@@ -391,15 +361,14 @@ static int meson_i2c_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct meson_i2c *i2c;
struct resource *mem;
int ret = 0;
struct i2c_timings timings;
int irq, ret = 0;
i2c = devm_kzalloc(&pdev->dev, sizeof(struct meson_i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&i2c->frequency))
i2c->frequency = DEFAULT_FREQ;
i2c_parse_fw_timings(&pdev->dev, &timings, true);
i2c->dev = &pdev->dev;
platform_set_drvdata(pdev, i2c);
@@ -418,14 +387,13 @@ static int meson_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c->regs))
return PTR_ERR(i2c->regs);
i2c->irq = platform_get_irq(pdev, 0);
if (i2c->irq < 0) {
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "can't find IRQ\n");
return i2c->irq;
return irq;
}
ret = devm_request_irq(&pdev->dev, i2c->irq, meson_i2c_irq,
0, dev_name(&pdev->dev), i2c);
ret = devm_request_irq(&pdev->dev, irq, meson_i2c_irq, 0, NULL, i2c);
if (ret < 0) {
dev_err(&pdev->dev, "can't request IRQ\n");
return ret;
@@ -457,6 +425,8 @@ static int meson_i2c_probe(struct platform_device *pdev)
return ret;
}
meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
return 0;
}
+5 -10
View File
@@ -823,13 +823,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
drv_data->rstc = devm_reset_control_get_optional(dev, NULL);
if (IS_ERR(drv_data->rstc)) {
if (PTR_ERR(drv_data->rstc) == -EPROBE_DEFER) {
rc = -EPROBE_DEFER;
goto out;
}
} else {
reset_control_deassert(drv_data->rstc);
rc = PTR_ERR(drv_data->rstc);
goto out;
}
reset_control_deassert(drv_data->rstc);
/* Its not yet defined how timeouts will be specified in device tree.
* So hard code the value to 1 second.
@@ -951,8 +948,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
exit_free_irq:
free_irq(drv_data->irq, drv_data);
exit_reset:
if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc);
reset_control_assert(drv_data->rstc);
exit_clk:
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk))
@@ -968,8 +964,7 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data);
if (!IS_ERR_OR_NULL(drv_data->rstc))
reset_control_assert(drv_data->rstc);
reset_control_assert(drv_data->rstc);
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk))
clk_disable_unprepare(drv_data->clk);
+5 -3
View File
@@ -700,6 +700,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
pm_runtime_get_sync(dev);
rcar_i2c_init(priv);
ret = rcar_i2c_bus_barrier(priv);
if (ret < 0)
goto out;
@@ -751,6 +753,7 @@ static int rcar_reg_slave(struct i2c_client *slave)
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
/* Keep device active for slave address detection logic */
pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv));
priv->slave = slave;
@@ -854,15 +857,14 @@ static int rcar_i2c_probe(struct platform_device *pdev)
priv->dma_direction = DMA_NONE;
priv->dma_rx = priv->dma_tx = ERR_PTR(-EPROBE_DEFER);
/* Activate device for clock calculation */
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
ret = rcar_i2c_clock_calculate(priv, &i2c_t);
if (ret < 0)
goto out_pm_put;
rcar_i2c_init(priv);
/* Don't suspend when multi-master to keep arbitration working */
/* Stay always active when multi-master to keep arbitration working */
if (of_property_read_bool(dev->of_node, "multi-master"))
priv->flags |= ID_P_PM_BLOCKED;
else
+4
View File
@@ -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);
+1 -1
View File
@@ -340,7 +340,7 @@ static struct platform_driver tegra_bpmp_i2c_driver = {
};
module_platform_driver(tegra_bpmp_i2c_driver);
MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus contoller driver");
MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus controller driver");
MODULE_AUTHOR("Shardar Shariff Md <smohammed@nvidia.com>");
MODULE_AUTHOR("Juha-Matti Tilli");
MODULE_LICENSE("GPL v2");
+16 -9
View File
@@ -85,16 +85,22 @@ static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c)
{
int ret;
i2c->clk = clk_get(dev, NULL);
if (IS_ERR(i2c->clk)) {
i2c->clk = NULL;
goto skip;
}
if (acpi_disabled) {
/* DT */
i2c->clk = clk_get(dev, NULL);
if (IS_ERR(i2c->clk)) {
i2c->clk = NULL;
goto skip;
}
ret = clk_prepare_enable(i2c->clk);
if (ret)
goto skip;
i2c->sys_freq = clk_get_rate(i2c->clk);
ret = clk_prepare_enable(i2c->clk);
if (ret)
goto skip;
i2c->sys_freq = clk_get_rate(i2c->clk);
} else {
/* ACPI */
device_property_read_u32(dev, "sclk", &i2c->sys_freq);
}
skip:
if (!i2c->sys_freq)
@@ -205,6 +211,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
i2c->adap = thunderx_i2c_ops;
i2c->adap.retries = 5;
i2c->adap.class = I2C_CLASS_HWMON;
i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info;
i2c->adap.dev.parent = dev;
i2c->adap.dev.of_node = pdev->dev.of_node;
+1
View File
@@ -432,6 +432,7 @@ MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = {
{"BRCM9007", 0},
{"CAV9007", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, xlp9xx_i2c_acpi_ids);
+59 -3
View File
@@ -112,6 +112,8 @@ struct i2c_acpi_lookup {
acpi_handle adapter_handle;
acpi_handle device_handle;
acpi_handle search_handle;
int n;
int index;
u32 speed;
u32 min_speed;
};
@@ -130,6 +132,9 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
return 1;
if (lookup->index != -1 && lookup->n++ != lookup->index)
return 1;
status = acpi_get_handle(lookup->device_handle,
sb->resource_source.string_ptr,
&lookup->adapter_handle);
@@ -182,6 +187,7 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
memset(&lookup, 0, sizeof(lookup));
lookup.info = info;
lookup.index = -1;
ret = i2c_acpi_do_lookup(adev, &lookup);
if (ret)
@@ -328,6 +334,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
lookup.search_handle = ACPI_HANDLE(dev);
lookup.min_speed = UINT_MAX;
lookup.info = &dummy;
lookup.index = -1;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
I2C_ACPI_MAX_SCAN_DEPTH,
@@ -414,6 +421,55 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
static struct notifier_block i2c_acpi_notifier = {
.notifier_call = i2c_acpi_notify,
};
/**
* i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource
* @dev: Device owning the ACPI resources to get the client from
* @index: Index of ACPI resource to get
* @info: describes the I2C device; note this is modified (addr gets set)
* Context: can sleep
*
* By default the i2c subsys creates an i2c-client for the first I2cSerialBus
* resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus
* resources, in that case this function can be used to create an i2c-client
* for other I2cSerialBus resources in the Current Resource Settings table.
*
* Also see i2c_new_device, which this function calls to create the i2c-client.
*
* Returns a pointer to the new i2c-client, or NULL if the adapter is not found.
*/
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
struct i2c_board_info *info)
{
struct i2c_acpi_lookup lookup;
struct i2c_adapter *adapter;
struct acpi_device *adev;
LIST_HEAD(resource_list);
int ret;
adev = ACPI_COMPANION(dev);
if (!adev)
return NULL;
memset(&lookup, 0, sizeof(lookup));
lookup.info = info;
lookup.device_handle = acpi_device_handle(adev);
lookup.index = index;
ret = acpi_dev_get_resources(adev, &resource_list,
i2c_acpi_fill_info, &lookup);
acpi_dev_free_resource_list(&resource_list);
if (ret < 0 || !info->addr)
return NULL;
adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
if (!adapter)
return NULL;
return i2c_new_device(adapter, info);
}
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
#else /* CONFIG_ACPI */
static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { }
extern struct notifier_block i2c_acpi_notifier;
@@ -929,7 +985,9 @@ static int i2c_device_probe(struct device *dev)
if (!client)
return 0;
if (!client->irq) {
driver = to_i2c_driver(dev->driver);
if (!client->irq && !driver->disable_i2c_core_irq_mapping) {
int irq = -ENOENT;
if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
@@ -951,8 +1009,6 @@ static int i2c_device_probe(struct device *dev)
client->irq = irq;
}
driver = to_i2c_driver(dev->driver);
/*
* An I2C ID table is not mandatory, if and only if, a suitable Device
* Tree match table entry is supplied for the probing device.
+6 -3
View File
@@ -395,13 +395,16 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
if (force_nr) {
priv->adap.nr = force_nr;
ret = i2c_add_numbered_adapter(&priv->adap);
dev_err(&parent->dev,
"failed to add mux-adapter %u as bus %u (error=%d)\n",
chan_id, force_nr, ret);
} else {
ret = i2c_add_adapter(&priv->adap);
dev_err(&parent->dev,
"failed to add mux-adapter %u (error=%d)\n",
chan_id, ret);
}
if (ret < 0) {
dev_err(&parent->dev,
"failed to add mux-adapter (error=%d)\n",
ret);
kfree(priv);
return ret;
}

Some files were not shown because too many files have changed in this diff Show More