mirror of https://gitee.com/openkylin/linux.git
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:
commit
14b730723a
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,17 @@ config I2C_MUX_GPIO
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-mux-gpio.
|
||||
|
||||
config I2C_MUX_LTC4306
|
||||
tristate "LTC LTC4306/5 I2C multiplexer"
|
||||
select GPIOLIB
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the Analog Devices
|
||||
LTC4306 or LTC4305 I2C mux/switch devices.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-mux-ltc4306.
|
||||
|
||||
config I2C_MUX_PCA9541
|
||||
tristate "NXP PCA9541 I2C Master Selector"
|
||||
help
|
||||
|
|
|
@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
|
|||
obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o
|
||||
|
||||
obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
|
||||
obj-$(CONFIG_I2C_MUX_LTC4306) += i2c-mux-ltc4306.o
|
||||
obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o
|
||||
obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
|
||||
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
|
||||
|
|
|
@ -202,10 +202,8 @@ static int i2c_arbitrator_probe(struct platform_device *pdev)
|
|||
|
||||
/* Actually add the mux adapter */
|
||||
ret = i2c_mux_add_adapter(muxc, 0, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to add adapter\n");
|
||||
if (ret)
|
||||
i2c_put_adapter(muxc->parent);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -245,10 +245,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
|
|||
unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
|
||||
if (ret)
|
||||
goto add_adapter_failed;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "%d port mux on %s adapter\n",
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* Linear Technology LTC4306 and LTC4305 I2C multiplexer/switch
|
||||
*
|
||||
* Copyright (C) 2017 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*
|
||||
* Based on: i2c-mux-pca954x.c
|
||||
*
|
||||
* Datasheet: http://cds.linear.com/docs/en/datasheet/4306.pdf
|
||||
*/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define LTC4305_MAX_NCHANS 2
|
||||
#define LTC4306_MAX_NCHANS 4
|
||||
|
||||
#define LTC_REG_STATUS 0x0
|
||||
#define LTC_REG_CONFIG 0x1
|
||||
#define LTC_REG_MODE 0x2
|
||||
#define LTC_REG_SWITCH 0x3
|
||||
|
||||
#define LTC_DOWNSTREAM_ACCL_EN BIT(6)
|
||||
#define LTC_UPSTREAM_ACCL_EN BIT(7)
|
||||
|
||||
#define LTC_GPIO_ALL_INPUT 0xC0
|
||||
#define LTC_SWITCH_MASK 0xF0
|
||||
|
||||
enum ltc_type {
|
||||
ltc_4305,
|
||||
ltc_4306,
|
||||
};
|
||||
|
||||
struct chip_desc {
|
||||
u8 nchans;
|
||||
u8 num_gpios;
|
||||
};
|
||||
|
||||
struct ltc4306 {
|
||||
struct regmap *regmap;
|
||||
struct gpio_chip gpiochip;
|
||||
const struct chip_desc *chip;
|
||||
};
|
||||
|
||||
static const struct chip_desc chips[] = {
|
||||
[ltc_4305] = {
|
||||
.nchans = LTC4305_MAX_NCHANS,
|
||||
},
|
||||
[ltc_4306] = {
|
||||
.nchans = LTC4306_MAX_NCHANS,
|
||||
.num_gpios = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static bool ltc4306_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return (reg == LTC_REG_CONFIG) ? true : false;
|
||||
}
|
||||
|
||||
static const struct regmap_config ltc4306_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = LTC_REG_SWITCH,
|
||||
.volatile_reg = ltc4306_is_volatile_reg,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct ltc4306 *data = gpiochip_get_data(chip);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, LTC_REG_CONFIG, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(val & BIT(1 - offset));
|
||||
}
|
||||
|
||||
static void ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct ltc4306 *data = gpiochip_get_data(chip);
|
||||
|
||||
regmap_update_bits(data->regmap, LTC_REG_CONFIG, BIT(5 - offset),
|
||||
value ? BIT(5 - offset) : 0);
|
||||
}
|
||||
|
||||
static int ltc4306_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct ltc4306 *data = gpiochip_get_data(chip);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, LTC_REG_MODE, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(val & BIT(7 - offset));
|
||||
}
|
||||
|
||||
static int ltc4306_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct ltc4306 *data = gpiochip_get_data(chip);
|
||||
|
||||
return regmap_update_bits(data->regmap, LTC_REG_MODE,
|
||||
BIT(7 - offset), BIT(7 - offset));
|
||||
}
|
||||
|
||||
static int ltc4306_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct ltc4306 *data = gpiochip_get_data(chip);
|
||||
|
||||
ltc4306_gpio_set(chip, offset, value);
|
||||
return regmap_update_bits(data->regmap, LTC_REG_MODE,
|
||||
BIT(7 - offset), 0);
|
||||
}
|
||||
|
||||
static int ltc4306_gpio_set_config(struct gpio_chip *chip,
|
||||
unsigned int offset, unsigned long config)
|
||||
{
|
||||
struct ltc4306 *data = gpiochip_get_data(chip);
|
||||
unsigned int val;
|
||||
|
||||
switch (pinconf_to_config_param(config)) {
|
||||
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
||||
val = 0;
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
||||
val = BIT(4 - offset);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return regmap_update_bits(data->regmap, LTC_REG_MODE,
|
||||
BIT(4 - offset), val);
|
||||
}
|
||||
|
||||
static int ltc4306_gpio_init(struct ltc4306 *data)
|
||||
{
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
|
||||
if (!data->chip->num_gpios)
|
||||
return 0;
|
||||
|
||||
data->gpiochip.label = dev_name(dev);
|
||||
data->gpiochip.base = -1;
|
||||
data->gpiochip.ngpio = data->chip->num_gpios;
|
||||
data->gpiochip.parent = dev;
|
||||
data->gpiochip.can_sleep = true;
|
||||
data->gpiochip.get_direction = ltc4306_gpio_get_direction;
|
||||
data->gpiochip.direction_input = ltc4306_gpio_direction_input;
|
||||
data->gpiochip.direction_output = ltc4306_gpio_direction_output;
|
||||
data->gpiochip.get = ltc4306_gpio_get;
|
||||
data->gpiochip.set = ltc4306_gpio_set;
|
||||
data->gpiochip.set_config = ltc4306_gpio_set_config;
|
||||
data->gpiochip.owner = THIS_MODULE;
|
||||
|
||||
/* gpiolib assumes all GPIOs default input */
|
||||
regmap_write(data->regmap, LTC_REG_MODE, LTC_GPIO_ALL_INPUT);
|
||||
|
||||
return devm_gpiochip_add_data(dev, &data->gpiochip, data);
|
||||
}
|
||||
|
||||
static int ltc4306_select_mux(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct ltc4306 *data = i2c_mux_priv(muxc);
|
||||
|
||||
return regmap_update_bits(data->regmap, LTC_REG_SWITCH,
|
||||
LTC_SWITCH_MASK, BIT(7 - chan));
|
||||
}
|
||||
|
||||
static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
|
||||
{
|
||||
struct ltc4306 *data = i2c_mux_priv(muxc);
|
||||
|
||||
return regmap_update_bits(data->regmap, LTC_REG_SWITCH,
|
||||
LTC_SWITCH_MASK, 0);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc4306_id[] = {
|
||||
{ "ltc4305", ltc_4305 },
|
||||
{ "ltc4306", ltc_4306 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc4306_id);
|
||||
|
||||
static const struct of_device_id ltc4306_of_match[] = {
|
||||
{ .compatible = "lltc,ltc4305", .data = &chips[ltc_4305] },
|
||||
{ .compatible = "lltc,ltc4306", .data = &chips[ltc_4306] },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc4306_of_match);
|
||||
|
||||
static int ltc4306_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
const struct chip_desc *chip;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct ltc4306 *data;
|
||||
struct gpio_desc *gpio;
|
||||
bool idle_disc;
|
||||
unsigned int val = 0;
|
||||
int num, ret;
|
||||
|
||||
chip = of_device_get_match_data(&client->dev);
|
||||
|
||||
if (!chip)
|
||||
chip = &chips[id->driver_data];
|
||||
|
||||
idle_disc = device_property_read_bool(&client->dev,
|
||||
"i2c-mux-idle-disconnect");
|
||||
|
||||
muxc = i2c_mux_alloc(adap, &client->dev,
|
||||
chip->nchans, sizeof(*data),
|
||||
I2C_MUX_LOCKED, ltc4306_select_mux,
|
||||
idle_disc ? ltc4306_deselect_mux : NULL);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
data = i2c_mux_priv(muxc);
|
||||
data->chip = chip;
|
||||
|
||||
i2c_set_clientdata(client, muxc);
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client, <c4306_regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
ret = PTR_ERR(data->regmap);
|
||||
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reset and enable the mux if an enable GPIO is specified. */
|
||||
gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio))
|
||||
return PTR_ERR(gpio);
|
||||
|
||||
if (gpio) {
|
||||
udelay(1);
|
||||
gpiod_set_value(gpio, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the mux register at addr to verify
|
||||
* that the mux is in fact present. This also
|
||||
* initializes the mux to disconnected state.
|
||||
*/
|
||||
if (regmap_write(data->regmap, LTC_REG_SWITCH, 0) < 0) {
|
||||
dev_warn(&client->dev, "probe failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (device_property_read_bool(&client->dev,
|
||||
"ltc,downstream-accelerators-enable"))
|
||||
val |= LTC_DOWNSTREAM_ACCL_EN;
|
||||
|
||||
if (device_property_read_bool(&client->dev,
|
||||
"ltc,upstream-accelerators-enable"))
|
||||
val |= LTC_UPSTREAM_ACCL_EN;
|
||||
|
||||
if (regmap_write(data->regmap, LTC_REG_CONFIG, val) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
ret = ltc4306_gpio_init(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (num = 0; num < chip->nchans; num++) {
|
||||
ret = i2c_mux_add_adapter(muxc, 0, num, 0);
|
||||
if (ret) {
|
||||
i2c_mux_del_adapters(muxc);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&client->dev,
|
||||
"registered %d multiplexed busses for I2C switch %s\n",
|
||||
num, client->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltc4306_remove(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver ltc4306_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4306",
|
||||
.of_match_table = of_match_ptr(ltc4306_of_match),
|
||||
},
|
||||
.probe = ltc4306_probe,
|
||||
.remove = ltc4306_remove,
|
||||
.id_table = ltc4306_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ltc4306_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
|
||||
MODULE_DESCRIPTION("Linear Technology LTC4306, LTC4305 I2C mux/switch driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -369,10 +369,8 @@ static int pca9541_probe(struct i2c_client *client,
|
|||
i2c_set_clientdata(client, muxc);
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, force, 0, 0);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to register master selector\n");
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "registered master selector for I2C %s\n",
|
||||
client->name);
|
||||
|
|
|
@ -84,7 +84,7 @@ struct pca954x {
|
|||
|
||||
struct irq_domain *irq;
|
||||
unsigned int irq_mask;
|
||||
spinlock_t lock;
|
||||
raw_spinlock_t lock;
|
||||
};
|
||||
|
||||
/* Provide specs for the PCA954x types we know about */
|
||||
|
@ -252,13 +252,13 @@ static void pca954x_irq_mask(struct irq_data *idata)
|
|||
unsigned int pos = idata->hwirq;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
raw_spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
data->irq_mask &= ~BIT(pos);
|
||||
if (!data->irq_mask)
|
||||
disable_irq(data->client->irq);
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&data->lock, flags);
|
||||
}
|
||||
|
||||
static void pca954x_irq_unmask(struct irq_data *idata)
|
||||
|
@ -267,13 +267,13 @@ static void pca954x_irq_unmask(struct irq_data *idata)
|
|||
unsigned int pos = idata->hwirq;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
raw_spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
if (!data->irq_mask)
|
||||
enable_irq(data->client->irq);
|
||||
data->irq_mask |= BIT(pos);
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
raw_spin_unlock_irqrestore(&data->lock, flags);
|
||||
}
|
||||
|
||||
static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
|
||||
|
@ -299,7 +299,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
|
|||
if (!data->chip->has_irq || client->irq <= 0)
|
||||
return 0;
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
raw_spin_lock_init(&data->lock);
|
||||
|
||||
data->irq = irq_domain_add_linear(client->dev.of_node,
|
||||
data->chip->nchans,
|
||||
|
@ -413,13 +413,8 @@ static int pca954x_probe(struct i2c_client *client,
|
|||
idle_disconnect_dt) << num;
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, force, num, class);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register multiplexed adapter"
|
||||
" %d as bus %d\n", num, force);
|
||||
if (ret)
|
||||
goto fail_del_adapters;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&client->dev,
|
||||
|
|
|
@ -245,10 +245,8 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
|
|||
(mux->pdata->base_bus_num + i) : 0;
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, bus, i, 0);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
|
||||
if (ret)
|
||||
goto err_del_adapter;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -222,10 +222,8 @@ static int i2c_mux_reg_probe(struct platform_device *pdev)
|
|||
class = mux->data.classes ? mux->data.classes[i] : 0;
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
|
||||
if (ret)
|
||||
goto add_adapter_failed;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "%d port mux on %s adapter\n",
|
||||
|
|
|
@ -576,17 +576,10 @@ int cx231xx_i2c_mux_create(struct cx231xx *dev)
|
|||
|
||||
int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = i2c_mux_add_adapter(dev->muxc,
|
||||
0,
|
||||
mux_no /* chan_id */,
|
||||
0 /* class */);
|
||||
if (rc)
|
||||
dev_warn(dev->dev,
|
||||
"i2c mux %d register FAILED\n", mux_no);
|
||||
|
||||
return rc;
|
||||
return i2c_mux_add_adapter(dev->muxc,
|
||||
0,
|
||||
mux_no /* chan_id */,
|
||||
0 /* class */);
|
||||
}
|
||||
|
||||
void cx231xx_i2c_mux_unregister(struct cx231xx *dev)
|
||||
|
|
|
@ -149,6 +149,7 @@ enum i2c_alert_protocol {
|
|||
* @detect: Callback for device detection
|
||||
* @address_list: The I2C addresses to probe (for detect)
|
||||
* @clients: List of detected clients we created (for i2c-core use only)
|
||||
* @disable_i2c_core_irq_mapping: Tell the i2c-core to not do irq-mapping
|
||||
*
|
||||
* The driver.owner field should be set to the module owner of this driver.
|
||||
* The driver.name field should be set to the name of this driver.
|
||||
|
@ -212,6 +213,8 @@ struct i2c_driver {
|
|||
int (*detect)(struct i2c_client *, struct i2c_board_info *);
|
||||
const unsigned short *address_list;
|
||||
struct list_head clients;
|
||||
|
||||
bool disable_i2c_core_irq_mapping;
|
||||
};
|
||||
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
|
||||
|
||||
|
@ -824,11 +827,18 @@ static inline const struct of_device_id
|
|||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
u32 i2c_acpi_find_bus_speed(struct device *dev);
|
||||
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
|
||||
struct i2c_board_info *info);
|
||||
#else
|
||||
static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
|
||||
int index, struct i2c_board_info *info)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
#endif /* _LINUX_I2C_H */
|
||||
|
|
Loading…
Reference in New Issue