mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
i2c-for-6.15-rc1
i2c-core updates (collected by Wolfram) - remove last user and unexport i2c_of_match_device() - irq usage cleanup from Jiri i2c-host updates (collected by Andi) Refactoring and cleanups - octeon, cadence, i801, pasemi, mlxbf, bcm-iproc: general refactorings - octeon: remove 10-bit address support Improvements - amd-asf: improved error handling - designware: use guard(mutex) - amd-asf, designware: update naming to follow latest specs - cadence: fix cleanup path in probe - i801: use MMIO and I/O mapping helpers to access registers - pxa: handle error after clk_prepare_enable New features - added i2c_10bit_addr_*_from_msg() and updated multiple drivers - omap: added multiplexer state handling - qcom-geni: update frequency configuration - qup: introduce DMA usage policy New hardware support - exynos: add support for Samsung exynos7870 - k1: add support for spacemit k1 (new driver) - imx: add support for i.mx94 lpi2c - rk3x: add support for rk3562 - designware: add support for Renesas RZ/N1D Multiplexers - ltc4306, reg: fix assignment in platform_driver structure at24 eeprom updates (collected by Bartosz) - add two new compatible entries to the DT binding document - drop of_match_ptr() and ACPI_PTR() macros -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmfoBuwACgkQFA3kzBSg KbZ+xg/9EEJIae2OVU1o7Ea4kPeyQEdLd2c6wjdrBWRdKuMcBMXR5y16yNI73bWZ greZpQDM3AQDNDoJQRe0502pjY/IzVmG6cgDqEdkI0/9x09e2Tk4UJacJttWbcS1 eCvfvn+yIC2XFoDH/kQozoxSnADXF7yA4XFjF0ljosk+kbtTj6VYV4P0iOkyTaM6 yWiU55X7x6S6P4pLtY+KByTFEfwV5YLBIJZv4U7sGR+XghUkFfa5mg3ZfblKDIe3 7SU1XLwSpLbLDf5xn1GMJEHZoq+Glqvrg32TSwbPcV6Aqf67LGXcTvUd+lPxWDsk rrpylo4XCfSgBn26NuCJBVWXmtraa1QEKrKvNw+7jIakxJ32YuAo/Lvc2Jk3KMcy bdOLR3C5RXNJAE2QDgsIspp3VJSMk43aeLhJm/zATu4sEjOUc0tNwQueXeuVXbp2 X9wX9ErPBpwn9f2jCZ1+v4vRbQbmQZREo6xVzNUd/AJf3muthKBP7tLokxq9pNlx q/x6N4PGy+x9MFT8BIwNgPpP4i8bVtWh+RJL68jh3WQoqNigkDGD0qmO/MZkHUeW n+pdI1MpoMaB+BH3HmWuTCOMYGNo4hfdrrAhmdh3fqQRrikgEXxXp3jicRBjoih+ vSgjQ5Q4bwhHzYqRNbBWVIvgSayQKVbaLqkbWjoWdngJCOUU7Tw= =q/EK -----END PGP SIGNATURE----- Merge tag 'i2c-for-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux Pull i2c updates from Wolfram Sang: "i2c-core updates (collected by Wolfram): - remove last user and unexport i2c_of_match_device() - irq usage cleanup from Jiri i2c-host updates (collected by Andi): Refactoring and cleanups: - octeon, cadence, i801, pasemi, mlxbf, bcm-iproc: general refactorings - octeon: remove 10-bit address support Improvements: - amd-asf: improved error handling - designware: use guard(mutex) - amd-asf, designware: update naming to follow latest specs - cadence: fix cleanup path in probe - i801: use MMIO and I/O mapping helpers to access registers - pxa: handle error after clk_prepare_enable New features: - added i2c_10bit_addr_*_from_msg() and updated multiple drivers - omap: added multiplexer state handling - qcom-geni: update frequency configuration - qup: introduce DMA usage policy New hardware support: - exynos: add support for Samsung exynos7870 - k1: add support for spacemit k1 (new driver) - imx: add support for i.mx94 lpi2c - rk3x: add support for rk3562 - designware: add support for Renesas RZ/N1D Multiplexers: - ltc4306, reg: fix assignment in platform_driver structure at24 eeprom updates (collected by Bartosz): - add two new compatible entries to the DT binding document - drop of_match_ptr() and ACPI_PTR() macros" * tag 'i2c-for-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (50 commits) dt-bindings: i2c: snps,designware-i2c: describe Renesas RZ/N1D variant irqdomain: i2c: Switch to irq_find_mapping() i2c: iproc: Refactor prototype and remove redundant error checks i2c: qcom-geni: Update i2c frequency table to match hardware guidance i2c: mlxbf: Use readl_poll_timeout_atomic() for polling i2c: pasemi: Add registers bits and switch to BIT() i2c: k1: Initialize variable before use i2c: spacemit: add support for SpacemiT K1 SoC dt-bindings: i2c: spacemit: add support for K1 SoC i2c: omap: Add support for setting mux dt-bindings: i2c: omap: Add mux-states property i2c: octeon: remove 10-bit addressing support i2c: octeon: fix return commenting i2c: i801: Use MMIO if available i2c: i801: Switch to iomapped register access i2c: i801: Improve too small kill wait time in i801_check_post i2c: i801: Move i801_wait_intr and i801_wait_byte_done in the code i2c: i801: Cosmetic improvements i2c: cadence: Move reset_control_assert after pm_runtime_set_suspended in probe error path i2c: cadence: Simplify using devm_clk_get_enabled() ...
This commit is contained in:
commit
28a1b05678
@ -130,10 +130,13 @@ properties:
|
||||
- const: giantec,gt24c32a
|
||||
- const: atmel,24c32
|
||||
- items:
|
||||
- const: onnn,n24s64b
|
||||
- enum:
|
||||
- onnn,n24s64b
|
||||
- puya,p24c64f
|
||||
- const: atmel,24c64
|
||||
- items:
|
||||
- enum:
|
||||
- giantec,gt24p128e
|
||||
- giantec,gt24p128f
|
||||
- renesas,r1ex24128
|
||||
- samsung,s524ad0xd1
|
||||
|
@ -30,6 +30,7 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- samsung,exynos5433-hsi2c
|
||||
- samsung,exynos7870-hsi2c
|
||||
- tesla,fsd-hsi2c
|
||||
- const: samsung,exynos7-hsi2c
|
||||
- items:
|
||||
|
@ -26,6 +26,7 @@ properties:
|
||||
- fsl,imx8qm-lpi2c
|
||||
- fsl,imx8ulp-lpi2c
|
||||
- fsl,imx93-lpi2c
|
||||
- fsl,imx94-lpi2c
|
||||
- fsl,imx95-lpi2c
|
||||
- const: fsl,imx7ulp-lpi2c
|
||||
|
||||
|
@ -37,6 +37,7 @@ properties:
|
||||
- rockchip,px30-i2c
|
||||
- rockchip,rk3308-i2c
|
||||
- rockchip,rk3328-i2c
|
||||
- rockchip,rk3562-i2c
|
||||
- rockchip,rk3568-i2c
|
||||
- rockchip,rk3576-i2c
|
||||
- rockchip,rk3588-i2c
|
||||
|
@ -40,6 +40,9 @@ properties:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
interconnects:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
@ -52,9 +55,15 @@ properties:
|
||||
- const: default
|
||||
- const: sleep
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required-opps:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clock-names
|
||||
@ -67,7 +76,9 @@ unevaluatedProperties: false
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-msm8998.h>
|
||||
#include <dt-bindings/interconnect/qcom,msm8996.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/qcom-rpmpd.h>
|
||||
|
||||
i2c@c175000 {
|
||||
compatible = "qcom,i2c-qup-v2.2.1";
|
||||
@ -82,6 +93,9 @@ examples:
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&blsp1_i2c1_default>;
|
||||
pinctrl-1 = <&blsp1_i2c1_sleep>;
|
||||
power-domains = <&rpmpd MSM8909_VDDCX>;
|
||||
required-opps = <&rpmpd_opp_svs_krait>;
|
||||
interconnects = <&pnoc MASTER_BLSP_1 &bimc SLAVE_EBI_CH0>;
|
||||
clock-frequency = <400000>;
|
||||
|
||||
#address-cells = <1>;
|
||||
|
@ -22,6 +22,7 @@ properties:
|
||||
- samsung,exynos5-sata-phy-i2c
|
||||
- items:
|
||||
- enum:
|
||||
- samsung,exynos7870-i2c
|
||||
- samsung,exynos7885-i2c
|
||||
- samsung,exynos850-i2c
|
||||
- const: samsung,s3c2440-i2c
|
||||
|
@ -27,6 +27,11 @@ properties:
|
||||
oneOf:
|
||||
- description: Generic Synopsys DesignWare I2C controller
|
||||
const: snps,designware-i2c
|
||||
- description: Renesas RZ/N1D I2C controller
|
||||
items:
|
||||
- const: renesas,r9a06g032-i2c # RZ/N1D
|
||||
- const: renesas,rzn1-i2c # RZ/N1
|
||||
- const: snps,designware-i2c
|
||||
- description: Microsemi Ocelot SoCs I2C controller
|
||||
items:
|
||||
- const: mscc,ocelot-i2c
|
||||
|
61
Documentation/devicetree/bindings/i2c/spacemit,k1-i2c.yaml
Normal file
61
Documentation/devicetree/bindings/i2c/spacemit,k1-i2c.yaml
Normal file
@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/spacemit,k1-i2c.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: I2C controller embedded in SpacemiT's K1 SoC
|
||||
|
||||
maintainers:
|
||||
- Troy Mitchell <troymitchell988@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: spacemit,k1-i2c
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: I2C Functional Clock
|
||||
- description: APB Bus Clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: func
|
||||
- const: bus
|
||||
|
||||
clock-frequency:
|
||||
description: |
|
||||
K1 support three different modes which running different frequencies
|
||||
standard speed mode: up to 100000 (100Hz)
|
||||
fast speed mode : up to 400000 (400Hz)
|
||||
high speed mode : up to 3300000 (3.3Mhz)
|
||||
default: 400000
|
||||
maximum: 3300000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c@d4010800 {
|
||||
compatible = "spacemit,k1-i2c";
|
||||
reg = <0xd4010800 0x38>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <36>;
|
||||
clocks =<&ccu 32>, <&ccu 84>;
|
||||
clock-names = "func", "bus";
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
...
|
@ -47,6 +47,11 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
deprecated: true
|
||||
|
||||
mux-states:
|
||||
description:
|
||||
mux controller node to route the I2C signals from SoC to clients.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -87,4 +92,5 @@ examples:
|
||||
interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
mux-states = <&i2c_mux 1>;
|
||||
};
|
||||
|
@ -783,6 +783,23 @@ config I2C_JZ4780
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
config I2C_K1
|
||||
tristate "SpacemiT K1 I2C adapter"
|
||||
depends on ARCH_SPACEMIT || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
This option enables support for the I2C interface on the SpacemiT K1
|
||||
platform.
|
||||
|
||||
If you enable this configuration, the kernel will include support for
|
||||
the I2C adapter specific to the SpacemiT K1 platform. This driver can
|
||||
be used to manage I2C bus transactions, which are necessary for
|
||||
interfacing with I2C peripherals such as sensors, EEPROMs, and other
|
||||
devices.
|
||||
|
||||
This driver can also be built as a module. If so, the
|
||||
module will be called `i2c-k1`.
|
||||
|
||||
config I2C_KEBA
|
||||
tristate "KEBA I2C controller support"
|
||||
depends on HAS_IOMEM
|
||||
@ -940,6 +957,7 @@ config I2C_OMAP
|
||||
tristate "OMAP I2C adapter"
|
||||
depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST
|
||||
default MACH_OMAP_OSK
|
||||
select MULTIPLEXER
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
I2C interface on the Texas Instruments OMAP1/2 family of processors.
|
||||
|
@ -74,6 +74,7 @@ obj-$(CONFIG_I2C_IMX) += i2c-imx.o
|
||||
obj-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o
|
||||
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
|
||||
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
|
||||
obj-$(CONFIG_I2C_K1) += i2c-k1.o
|
||||
obj-$(CONFIG_I2C_KEBA) += i2c-keba.o
|
||||
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
|
||||
obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o
|
||||
|
@ -69,7 +69,7 @@ static void amd_asf_process_target(struct work_struct *work)
|
||||
/* Check if no error bits are set in target status register */
|
||||
if (reg & ASF_ERROR_STATUS) {
|
||||
/* Set bank as full */
|
||||
cmd = 0;
|
||||
cmd = 1;
|
||||
reg |= GENMASK(3, 2);
|
||||
outb_p(reg, ASFDATABNKSEL);
|
||||
} else {
|
||||
@ -272,9 +272,9 @@ static u32 amd_asf_func(struct i2c_adapter *adapter)
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm amd_asf_smbus_algorithm = {
|
||||
.master_xfer = amd_asf_xfer,
|
||||
.reg_slave = amd_asf_reg_target,
|
||||
.unreg_slave = amd_asf_unreg_target,
|
||||
.xfer = amd_asf_xfer,
|
||||
.reg_target = amd_asf_reg_target,
|
||||
.unreg_target = amd_asf_unreg_target,
|
||||
.functionality = amd_asf_func,
|
||||
};
|
||||
|
||||
|
@ -255,11 +255,6 @@ static int i2c_m_rd(const struct i2c_msg *msg)
|
||||
return (msg->flags & I2C_M_RD) != 0;
|
||||
}
|
||||
|
||||
static int i2c_m_ten(const struct i2c_msg *msg)
|
||||
{
|
||||
return (msg->flags & I2C_M_TEN) != 0;
|
||||
}
|
||||
|
||||
static int i2c_m_recv_len(const struct i2c_msg *msg)
|
||||
{
|
||||
return (msg->flags & I2C_M_RECV_LEN) != 0;
|
||||
@ -439,20 +434,10 @@ static void axxia_i2c_set_addr(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
||||
{
|
||||
u32 addr_1, addr_2;
|
||||
|
||||
if (i2c_m_ten(msg)) {
|
||||
/* 10-bit address
|
||||
* addr_1: 5'b11110 | addr[9:8] | (R/nW)
|
||||
* addr_2: addr[7:0]
|
||||
*/
|
||||
addr_1 = 0xF0 | ((msg->addr >> 7) & 0x06);
|
||||
if (i2c_m_rd(msg))
|
||||
addr_1 |= 1; /* Set the R/nW bit of the address */
|
||||
addr_2 = msg->addr & 0xFF;
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
addr_1 = i2c_10bit_addr_hi_from_msg(msg);
|
||||
addr_2 = i2c_10bit_addr_lo_from_msg(msg);
|
||||
} else {
|
||||
/* 7-bit address
|
||||
* addr_1: addr[6:0] | (R/nW)
|
||||
* addr_2: dont care
|
||||
*/
|
||||
addr_1 = i2c_8bit_addr_from_msg(msg);
|
||||
addr_2 = 0;
|
||||
}
|
||||
|
@ -678,7 +678,7 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
|
||||
static void bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
@ -706,8 +706,6 @@ static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
|
||||
|
||||
/* clear all pending interrupts */
|
||||
iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, 0xffffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
|
||||
@ -1081,9 +1079,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
|
||||
bcm_iproc_algo.unreg_slave = NULL;
|
||||
}
|
||||
|
||||
ret = bcm_iproc_i2c_init(iproc_i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
bcm_iproc_i2c_init(iproc_i2c);
|
||||
|
||||
ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
|
||||
if (ret)
|
||||
@ -1162,16 +1158,13 @@ static int bcm_iproc_i2c_suspend(struct device *dev)
|
||||
static int bcm_iproc_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* Power domain could have been shut off completely in system deep
|
||||
* sleep, so re-initialize the block here
|
||||
*/
|
||||
ret = bcm_iproc_i2c_init(iproc_i2c);
|
||||
if (ret)
|
||||
return ret;
|
||||
bcm_iproc_i2c_init(iproc_i2c);
|
||||
|
||||
/* configure to the desired bus speed */
|
||||
val = iproc_i2c_rd_reg(iproc_i2c, TIM_CFG_OFFSET);
|
||||
|
@ -471,12 +471,12 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
|
||||
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
/* First byte is 11110XX0 where XX is upper 2 bits */
|
||||
addr = 0xF0 | ((msg->addr & 0x300) >> 7);
|
||||
addr = i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD;
|
||||
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
/* Second byte is the remaining 8 bits */
|
||||
addr = msg->addr & 0xFF;
|
||||
addr = i2c_10bit_addr_lo_from_msg(msg);
|
||||
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
@ -486,7 +486,7 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev,
|
||||
return -EREMOTEIO;
|
||||
|
||||
/* Then re-send the first byte with the read bit set */
|
||||
addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01;
|
||||
addr = i2c_10bit_addr_hi_from_msg(msg);
|
||||
if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
@ -414,23 +414,22 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev,
|
||||
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
/* First byte is 11110XX0 where XX is upper 2 bits */
|
||||
addr = 0xF0 | ((msg->addr & 0x300) >> 7);
|
||||
addr = i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD;
|
||||
bsc_writel(dev, addr, chip_address);
|
||||
|
||||
/* Second byte is the remaining 8 bits */
|
||||
addr = msg->addr & 0xFF;
|
||||
addr = i2c_10bit_addr_lo_from_msg(msg);
|
||||
if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
if (msg->flags & I2C_M_RD) {
|
||||
/* For read, send restart without stop condition */
|
||||
brcmstb_set_i2c_start_stop(dev, COND_RESTART
|
||||
| COND_NOSTOP);
|
||||
brcmstb_set_i2c_start_stop(dev, COND_RESTART | COND_NOSTOP);
|
||||
|
||||
/* Then re-send the first byte with the read bit set */
|
||||
addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01;
|
||||
addr = i2c_10bit_addr_hi_from_msg(msg);
|
||||
if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
}
|
||||
} else {
|
||||
addr = i2c_8bit_addr_from_msg(msg);
|
||||
|
@ -1541,7 +1541,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||
snprintf(id->adap.name, sizeof(id->adap.name),
|
||||
"Cadence I2C at %08lx", (unsigned long)r_mem->start);
|
||||
|
||||
id->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
id->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(id->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(id->clk),
|
||||
"input clock not found.\n");
|
||||
@ -1551,16 +1551,10 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(id->reset),
|
||||
"Failed to request reset.\n");
|
||||
|
||||
ret = clk_prepare_enable(id->clk);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "Unable to enable clock.\n");
|
||||
|
||||
ret = reset_control_deassert(id->reset);
|
||||
if (ret) {
|
||||
dev_err_probe(&pdev->dev, ret,
|
||||
"Failed to de-assert reset.\n");
|
||||
goto err_clk_dis;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Failed to de-assert reset.\n");
|
||||
|
||||
pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(id->dev);
|
||||
@ -1615,11 +1609,9 @@ static int cdns_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
err_clk_notifier_unregister:
|
||||
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
|
||||
reset_control_assert(id->reset);
|
||||
err_clk_dis:
|
||||
clk_disable_unprepare(id->clk);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
reset_control_assert(id->reset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1642,7 +1634,6 @@ static void cdns_i2c_remove(struct platform_device *pdev)
|
||||
i2c_del_adapter(&id->adap);
|
||||
clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
|
||||
reset_control_assert(id->reset);
|
||||
clk_disable_unprepare(id->clk);
|
||||
}
|
||||
|
||||
static struct platform_driver cdns_i2c_drv = {
|
||||
|
@ -151,19 +151,16 @@ static void release_bus(void)
|
||||
|
||||
static void psp_release_i2c_bus_deferred(struct work_struct *work)
|
||||
{
|
||||
mutex_lock(&psp_i2c_access_mutex);
|
||||
guard(mutex)(&psp_i2c_access_mutex);
|
||||
|
||||
/*
|
||||
* If there is any pending transaction, cannot release the bus here.
|
||||
* psp_release_i2c_bus() will take care of this later.
|
||||
*/
|
||||
if (psp_i2c_access_count)
|
||||
goto cleanup;
|
||||
return;
|
||||
|
||||
release_bus();
|
||||
|
||||
cleanup:
|
||||
mutex_unlock(&psp_i2c_access_mutex);
|
||||
}
|
||||
static DECLARE_DELAYED_WORK(release_queue, psp_release_i2c_bus_deferred);
|
||||
|
||||
@ -171,11 +168,11 @@ static int psp_acquire_i2c_bus(void)
|
||||
{
|
||||
int status;
|
||||
|
||||
mutex_lock(&psp_i2c_access_mutex);
|
||||
guard(mutex)(&psp_i2c_access_mutex);
|
||||
|
||||
/* Return early if mailbox malfunctioned */
|
||||
if (psp_i2c_mbox_fail)
|
||||
goto cleanup;
|
||||
return 0;
|
||||
|
||||
psp_i2c_access_count++;
|
||||
|
||||
@ -184,11 +181,11 @@ static int psp_acquire_i2c_bus(void)
|
||||
* reservation period.
|
||||
*/
|
||||
if (psp_i2c_sem_acquired)
|
||||
goto cleanup;
|
||||
return 0;
|
||||
|
||||
status = psp_send_i2c_req(PSP_I2C_REQ_ACQUIRE);
|
||||
if (status)
|
||||
goto cleanup;
|
||||
return 0;
|
||||
|
||||
psp_i2c_sem_acquired = jiffies;
|
||||
|
||||
@ -201,18 +198,16 @@ static int psp_acquire_i2c_bus(void)
|
||||
* communication with PSP. At any case i2c bus is granted to the caller,
|
||||
* thus always return success.
|
||||
*/
|
||||
cleanup:
|
||||
mutex_unlock(&psp_i2c_access_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void psp_release_i2c_bus(void)
|
||||
{
|
||||
mutex_lock(&psp_i2c_access_mutex);
|
||||
guard(mutex)(&psp_i2c_access_mutex);
|
||||
|
||||
/* Return early if mailbox was malfunctioned */
|
||||
if (psp_i2c_mbox_fail)
|
||||
goto cleanup;
|
||||
return;
|
||||
|
||||
/*
|
||||
* If we are last owner of PSP semaphore, need to release arbitration
|
||||
@ -220,7 +215,7 @@ static void psp_release_i2c_bus(void)
|
||||
*/
|
||||
psp_i2c_access_count--;
|
||||
if (psp_i2c_access_count)
|
||||
goto cleanup;
|
||||
return;
|
||||
|
||||
/*
|
||||
* Send a release command to PSP if the semaphore reservation timeout
|
||||
@ -228,9 +223,6 @@ static void psp_release_i2c_bus(void)
|
||||
*/
|
||||
if (!delayed_work_pending(&release_queue))
|
||||
release_bus();
|
||||
|
||||
cleanup:
|
||||
mutex_unlock(&psp_i2c_access_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -907,7 +907,7 @@ done_nolock:
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm i2c_dw_algo = {
|
||||
.master_xfer = i2c_dw_xfer,
|
||||
.xfer = i2c_dw_xfer,
|
||||
.functionality = i2c_dw_func,
|
||||
};
|
||||
|
||||
|
@ -48,8 +48,6 @@
|
||||
|
||||
#define BUS_IDLE_TIMEOUT 20
|
||||
#define PCH_I2CCTL_I2CMEN 0x0080
|
||||
#define TEN_BIT_ADDR_DEFAULT 0xF000
|
||||
#define TEN_BIT_ADDR_MASK 0xF0
|
||||
#define PCH_START 0x0020
|
||||
#define PCH_RESTART 0x0004
|
||||
#define PCH_ESR_START 0x0001
|
||||
@ -58,7 +56,6 @@
|
||||
#define PCH_ACK 0x0008
|
||||
#define PCH_GETACK 0x0001
|
||||
#define CLR_REG 0x0
|
||||
#define I2C_RD 0x1
|
||||
#define I2CMCF_BIT 0x0080
|
||||
#define I2CMIF_BIT 0x0002
|
||||
#define I2CMAL_BIT 0x0010
|
||||
@ -76,8 +73,6 @@
|
||||
#define I2CMBB_BIT 0x0020
|
||||
#define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \
|
||||
I2CBMTO_BIT | I2CBMIS_BIT)
|
||||
#define I2C_ADDR_MSK 0xFF
|
||||
#define I2C_MSB_2B_MSK 0x300
|
||||
#define FAST_MODE_CLK 400
|
||||
#define FAST_MODE_EN 0x0001
|
||||
#define SUB_ADDR_LEN_MAX 4
|
||||
@ -371,16 +366,12 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
|
||||
u8 *buf;
|
||||
u32 length;
|
||||
u32 addr;
|
||||
u32 addr_2_msb;
|
||||
u32 addr_8_lsb;
|
||||
s32 wrcount;
|
||||
s32 rtn;
|
||||
void __iomem *p = adap->pch_base_address;
|
||||
|
||||
length = msgs->len;
|
||||
buf = msgs->buf;
|
||||
addr = msgs->addr;
|
||||
|
||||
/* enable master tx */
|
||||
pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
|
||||
@ -394,8 +385,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
|
||||
}
|
||||
|
||||
if (msgs->flags & I2C_M_TEN) {
|
||||
addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06;
|
||||
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
|
||||
iowrite32(i2c_10bit_addr_hi_from_msg(msgs), p + PCH_I2CDR);
|
||||
if (first)
|
||||
pch_i2c_start(adap);
|
||||
|
||||
@ -403,8 +393,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
|
||||
if (rtn)
|
||||
return rtn;
|
||||
|
||||
addr_8_lsb = (addr & I2C_ADDR_MSK);
|
||||
iowrite32(addr_8_lsb, p + PCH_I2CDR);
|
||||
iowrite32(i2c_10bit_addr_lo_from_msg(msgs), p + PCH_I2CDR);
|
||||
} else {
|
||||
/* set 7 bit slave address and R/W bit as 0 */
|
||||
iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
|
||||
@ -490,15 +479,11 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
u8 *buf;
|
||||
u32 count;
|
||||
u32 length;
|
||||
u32 addr;
|
||||
u32 addr_2_msb;
|
||||
u32 addr_8_lsb;
|
||||
void __iomem *p = adap->pch_base_address;
|
||||
s32 rtn;
|
||||
|
||||
length = msgs->len;
|
||||
buf = msgs->buf;
|
||||
addr = msgs->addr;
|
||||
|
||||
/* enable master reception */
|
||||
pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
|
||||
@ -509,8 +494,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
}
|
||||
|
||||
if (msgs->flags & I2C_M_TEN) {
|
||||
addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
|
||||
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
|
||||
iowrite32(i2c_10bit_addr_hi_from_msg(msgs) & ~I2C_M_RD, p + PCH_I2CDR);
|
||||
if (first)
|
||||
pch_i2c_start(adap);
|
||||
|
||||
@ -518,8 +502,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
if (rtn)
|
||||
return rtn;
|
||||
|
||||
addr_8_lsb = (addr & I2C_ADDR_MSK);
|
||||
iowrite32(addr_8_lsb, p + PCH_I2CDR);
|
||||
iowrite32(i2c_10bit_addr_lo_from_msg(msgs), p + PCH_I2CDR);
|
||||
|
||||
pch_i2c_restart(adap);
|
||||
|
||||
@ -527,8 +510,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
|
||||
if (rtn)
|
||||
return rtn;
|
||||
|
||||
addr_2_msb |= I2C_RD;
|
||||
iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
|
||||
iowrite32(i2c_10bit_addr_hi_from_msg(msgs), p + PCH_I2CDR);
|
||||
} else {
|
||||
/* 7 address bits + R/W bit */
|
||||
iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR);
|
||||
|
@ -814,7 +814,7 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
|
||||
ret = i2c->state;
|
||||
|
||||
/*
|
||||
* If this is the last message to be transfered (stop == 1)
|
||||
* If this is the last message to be transferred (stop == 1)
|
||||
* Then check if the bus can be brought back to idle.
|
||||
*/
|
||||
if (ret == 0 && stop)
|
||||
|
@ -144,6 +144,7 @@
|
||||
#define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */
|
||||
|
||||
/* PCI Address Constants */
|
||||
#define SMBBAR_MMIO 0
|
||||
#define SMBBAR 4
|
||||
#define SMBHSTCFG 0x040
|
||||
#define TCOBASE 0x050
|
||||
@ -276,7 +277,7 @@ struct i801_mux_config {
|
||||
|
||||
struct i801_priv {
|
||||
struct i2c_adapter adapter;
|
||||
unsigned long smba;
|
||||
void __iomem *smba;
|
||||
unsigned char original_hstcfg;
|
||||
unsigned char original_hstcnt;
|
||||
unsigned char original_slvcmd;
|
||||
@ -337,9 +338,43 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n"
|
||||
"\t\t 0x10 don't use interrupts\n"
|
||||
"\t\t 0x20 disable SMBus Host Notify ");
|
||||
|
||||
/* Wait for BUSY being cleared and either INTR or an error flag being set */
|
||||
static int i801_wait_intr(struct i801_priv *priv)
|
||||
{
|
||||
unsigned long timeout = jiffies + priv->adapter.timeout;
|
||||
int status, busy;
|
||||
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = ioread8(SMBHSTSTS(priv));
|
||||
busy = status & SMBHSTSTS_HOST_BUSY;
|
||||
status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
|
||||
if (!busy && status)
|
||||
return status & STATUS_ERROR_FLAGS;
|
||||
} while (time_is_after_eq_jiffies(timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Wait for either BYTE_DONE or an error flag being set */
|
||||
static int i801_wait_byte_done(struct i801_priv *priv)
|
||||
{
|
||||
unsigned long timeout = jiffies + priv->adapter.timeout;
|
||||
int status;
|
||||
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = ioread8(SMBHSTSTS(priv));
|
||||
if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE))
|
||||
return status & STATUS_ERROR_FLAGS;
|
||||
} while (time_is_after_eq_jiffies(timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int i801_get_block_len(struct i801_priv *priv)
|
||||
{
|
||||
u8 len = inb_p(SMBHSTDAT0(priv));
|
||||
u8 len = ioread8(SMBHSTDAT0(priv));
|
||||
|
||||
if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
|
||||
pci_err(priv->pci_dev, "Illegal SMBus block read size %u\n", len);
|
||||
@ -356,9 +391,9 @@ static int i801_check_and_clear_pec_error(struct i801_priv *priv)
|
||||
if (!(priv->features & FEATURE_SMBUS_PEC))
|
||||
return 0;
|
||||
|
||||
status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
|
||||
status = ioread8(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
|
||||
if (status) {
|
||||
outb_p(status, SMBAUXSTS(priv));
|
||||
iowrite8(status, SMBAUXSTS(priv));
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
@ -371,7 +406,7 @@ static int i801_check_pre(struct i801_priv *priv)
|
||||
{
|
||||
int status, result;
|
||||
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
status = ioread8(SMBHSTSTS(priv));
|
||||
if (status & SMBHSTSTS_HOST_BUSY) {
|
||||
pci_err(priv->pci_dev, "SMBus is busy, can't use it!\n");
|
||||
return -EBUSY;
|
||||
@ -380,7 +415,7 @@ static int i801_check_pre(struct i801_priv *priv)
|
||||
status &= STATUS_FLAGS;
|
||||
if (status) {
|
||||
pci_dbg(priv->pci_dev, "Clearing status flags (%02x)\n", status);
|
||||
outb_p(status, SMBHSTSTS(priv));
|
||||
iowrite8(status, SMBHSTSTS(priv));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -406,22 +441,19 @@ static int i801_check_post(struct i801_priv *priv, int status)
|
||||
*/
|
||||
if (unlikely(status < 0)) {
|
||||
/* try to stop the current command */
|
||||
outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv));
|
||||
usleep_range(1000, 2000);
|
||||
outb_p(0, SMBHSTCNT(priv));
|
||||
iowrite8(SMBHSTCNT_KILL, SMBHSTCNT(priv));
|
||||
status = i801_wait_intr(priv);
|
||||
iowrite8(0, SMBHSTCNT(priv));
|
||||
|
||||
/* Check if it worked */
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
if ((status & SMBHSTSTS_HOST_BUSY) ||
|
||||
!(status & SMBHSTSTS_FAILED))
|
||||
dev_dbg(&priv->pci_dev->dev,
|
||||
"Failed terminating the transaction\n");
|
||||
if (status < 0 || !(status & SMBHSTSTS_FAILED))
|
||||
pci_dbg(priv->pci_dev, "Failed terminating the transaction\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (status & SMBHSTSTS_FAILED) {
|
||||
result = -EIO;
|
||||
dev_err(&priv->pci_dev->dev, "Transaction failed\n");
|
||||
pci_err(priv->pci_dev, "Transaction failed\n");
|
||||
}
|
||||
if (status & SMBHSTSTS_DEV_ERR) {
|
||||
/*
|
||||
@ -449,46 +481,12 @@ static int i801_check_post(struct i801_priv *priv, int status)
|
||||
}
|
||||
if (status & SMBHSTSTS_BUS_ERR) {
|
||||
result = -EAGAIN;
|
||||
dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
|
||||
pci_dbg(priv->pci_dev, "Lost arbitration\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Wait for BUSY being cleared and either INTR or an error flag being set */
|
||||
static int i801_wait_intr(struct i801_priv *priv)
|
||||
{
|
||||
unsigned long timeout = jiffies + priv->adapter.timeout;
|
||||
int status, busy;
|
||||
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
busy = status & SMBHSTSTS_HOST_BUSY;
|
||||
status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
|
||||
if (!busy && status)
|
||||
return status & STATUS_ERROR_FLAGS;
|
||||
} while (time_is_after_eq_jiffies(timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Wait for either BYTE_DONE or an error flag being set */
|
||||
static int i801_wait_byte_done(struct i801_priv *priv)
|
||||
{
|
||||
unsigned long timeout = jiffies + priv->adapter.timeout;
|
||||
int status;
|
||||
|
||||
do {
|
||||
usleep_range(250, 500);
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE))
|
||||
return status & STATUS_ERROR_FLAGS;
|
||||
} while (time_is_after_eq_jiffies(timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int i801_transaction(struct i801_priv *priv, int xact)
|
||||
{
|
||||
unsigned long result;
|
||||
@ -496,13 +494,13 @@ static int i801_transaction(struct i801_priv *priv, int xact)
|
||||
|
||||
if (priv->features & FEATURE_IRQ) {
|
||||
reinit_completion(&priv->done);
|
||||
outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
|
||||
iowrite8(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
|
||||
SMBHSTCNT(priv));
|
||||
result = wait_for_completion_timeout(&priv->done, adap->timeout);
|
||||
return result ? priv->status : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
iowrite8(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
|
||||
return i801_wait_intr(priv);
|
||||
}
|
||||
@ -511,7 +509,7 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
|
||||
union i2c_smbus_data *data,
|
||||
char read_write, int command)
|
||||
{
|
||||
int i, len, status, xact;
|
||||
int len, status, xact;
|
||||
|
||||
switch (command) {
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
@ -525,14 +523,13 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
|
||||
}
|
||||
|
||||
/* Set block buffer mode */
|
||||
outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
|
||||
iowrite8(ioread8(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = data->block[0];
|
||||
outb_p(len, SMBHSTDAT0(priv));
|
||||
inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
|
||||
for (i = 0; i < len; i++)
|
||||
outb_p(data->block[i+1], SMBBLKDAT(priv));
|
||||
iowrite8(len, SMBHSTDAT0(priv));
|
||||
ioread8(SMBHSTCNT(priv)); /* reset the data buffer index */
|
||||
iowrite8_rep(SMBBLKDAT(priv), data->block + 1, len);
|
||||
}
|
||||
|
||||
status = i801_transaction(priv, xact);
|
||||
@ -548,12 +545,11 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
|
||||
}
|
||||
|
||||
data->block[0] = len;
|
||||
inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
|
||||
for (i = 0; i < len; i++)
|
||||
data->block[i + 1] = inb_p(SMBBLKDAT(priv));
|
||||
ioread8(SMBHSTCNT(priv)); /* reset the data buffer index */
|
||||
ioread8_rep(SMBBLKDAT(priv), data->block + 1, len);
|
||||
}
|
||||
out:
|
||||
outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_E32B, SMBAUXCTL(priv));
|
||||
iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_E32B, SMBAUXCTL(priv));
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -576,18 +572,17 @@ static void i801_isr_byte_done(struct i801_priv *priv)
|
||||
|
||||
/* Read next byte */
|
||||
if (priv->count < priv->len)
|
||||
priv->data[priv->count++] = inb(SMBBLKDAT(priv));
|
||||
priv->data[priv->count++] = ioread8(SMBBLKDAT(priv));
|
||||
else
|
||||
dev_dbg(&priv->pci_dev->dev,
|
||||
"Discarding extra byte on block read\n");
|
||||
pci_dbg(priv->pci_dev, "Discarding extra byte on block read\n");
|
||||
|
||||
/* Set LAST_BYTE for last byte of read transaction */
|
||||
if (priv->count == priv->len - 1)
|
||||
outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE,
|
||||
iowrite8(priv->cmd | SMBHSTCNT_LAST_BYTE,
|
||||
SMBHSTCNT(priv));
|
||||
} else if (priv->count < priv->len - 1) {
|
||||
/* Write next byte, except for IRQ after last byte */
|
||||
outb_p(priv->data[++priv->count], SMBBLKDAT(priv));
|
||||
iowrite8(priv->data[++priv->count], SMBBLKDAT(priv));
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,7 +590,7 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
|
||||
{
|
||||
unsigned short addr;
|
||||
|
||||
addr = inb_p(SMBNTFDADD(priv)) >> 1;
|
||||
addr = ioread8(SMBNTFDADD(priv)) >> 1;
|
||||
|
||||
/*
|
||||
* With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba)
|
||||
@ -605,7 +600,7 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv)
|
||||
i2c_handle_smbus_host_notify(&priv->adapter, addr);
|
||||
|
||||
/* clear Host Notify bit and return */
|
||||
outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
|
||||
iowrite8(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -636,12 +631,12 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
|
||||
return IRQ_NONE;
|
||||
|
||||
if (priv->features & FEATURE_HOST_NOTIFY) {
|
||||
status = inb_p(SMBSLVSTS(priv));
|
||||
status = ioread8(SMBSLVSTS(priv));
|
||||
if (status & SMBSLVSTS_HST_NTFY_STS)
|
||||
return i801_host_notify_isr(priv);
|
||||
}
|
||||
|
||||
status = inb_p(SMBHSTSTS(priv));
|
||||
status = ioread8(SMBHSTSTS(priv));
|
||||
if ((status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS)) == SMBHSTSTS_BYTE_DONE)
|
||||
i801_isr_byte_done(priv);
|
||||
|
||||
@ -651,7 +646,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
|
||||
* so clear it always when the status is set.
|
||||
*/
|
||||
status &= STATUS_FLAGS | SMBHSTSTS_SMBALERT_STS;
|
||||
outb_p(status, SMBHSTSTS(priv));
|
||||
iowrite8(status, SMBHSTSTS(priv));
|
||||
|
||||
status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR;
|
||||
if (status) {
|
||||
@ -683,8 +678,8 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
||||
len = data->block[0];
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
outb_p(len, SMBHSTDAT0(priv));
|
||||
outb_p(data->block[1], SMBBLKDAT(priv));
|
||||
iowrite8(len, SMBHSTDAT0(priv));
|
||||
iowrite8(data->block[1], SMBBLKDAT(priv));
|
||||
}
|
||||
|
||||
if (command == I2C_SMBUS_I2C_BLOCK_DATA &&
|
||||
@ -703,14 +698,14 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
||||
priv->data = &data->block[1];
|
||||
|
||||
reinit_completion(&priv->done);
|
||||
outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
iowrite8(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
result = wait_for_completion_timeout(&priv->done, adap->timeout);
|
||||
return result ? priv->status : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (len == 1 && read_write == I2C_SMBUS_READ)
|
||||
smbcmd |= SMBHSTCNT_LAST_BYTE;
|
||||
outb_p(smbcmd | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
iowrite8(smbcmd | SMBHSTCNT_START, SMBHSTCNT(priv));
|
||||
|
||||
for (i = 1; i <= len; i++) {
|
||||
status = i801_wait_byte_done(priv);
|
||||
@ -726,27 +721,27 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
||||
len = i801_get_block_len(priv);
|
||||
if (len < 0) {
|
||||
/* Recover */
|
||||
while (inb_p(SMBHSTSTS(priv)) &
|
||||
while (ioread8(SMBHSTSTS(priv)) &
|
||||
SMBHSTSTS_HOST_BUSY)
|
||||
outb_p(SMBHSTSTS_BYTE_DONE,
|
||||
iowrite8(SMBHSTSTS_BYTE_DONE,
|
||||
SMBHSTSTS(priv));
|
||||
outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
|
||||
iowrite8(SMBHSTSTS_INTR, SMBHSTSTS(priv));
|
||||
return -EPROTO;
|
||||
}
|
||||
data->block[0] = len;
|
||||
}
|
||||
|
||||
if (read_write == I2C_SMBUS_READ) {
|
||||
data->block[i] = inb_p(SMBBLKDAT(priv));
|
||||
data->block[i] = ioread8(SMBBLKDAT(priv));
|
||||
if (i == len - 1)
|
||||
outb_p(smbcmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv));
|
||||
iowrite8(smbcmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv));
|
||||
}
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
|
||||
outb_p(data->block[i+1], SMBBLKDAT(priv));
|
||||
iowrite8(data->block[i+1], SMBBLKDAT(priv));
|
||||
|
||||
/* signals SMBBLKDAT ready */
|
||||
outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
|
||||
iowrite8(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv));
|
||||
}
|
||||
|
||||
return i801_wait_intr(priv);
|
||||
@ -754,7 +749,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
|
||||
|
||||
static void i801_set_hstadd(struct i801_priv *priv, u8 addr, char read_write)
|
||||
{
|
||||
outb_p((addr << 1) | (read_write & 0x01), SMBHSTADD(priv));
|
||||
iowrite8((addr << 1) | (read_write & 0x01), SMBHSTADD(priv));
|
||||
}
|
||||
|
||||
/* Single value transaction function */
|
||||
@ -771,30 +766,30 @@ static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data
|
||||
case I2C_SMBUS_BYTE:
|
||||
i801_set_hstadd(priv, addr, read_write);
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
outb_p(hstcmd, SMBHSTCMD(priv));
|
||||
iowrite8(hstcmd, SMBHSTCMD(priv));
|
||||
xact = I801_BYTE;
|
||||
break;
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
i801_set_hstadd(priv, addr, read_write);
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
outb_p(data->byte, SMBHSTDAT0(priv));
|
||||
outb_p(hstcmd, SMBHSTCMD(priv));
|
||||
iowrite8(data->byte, SMBHSTDAT0(priv));
|
||||
iowrite8(hstcmd, SMBHSTCMD(priv));
|
||||
xact = I801_BYTE_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
i801_set_hstadd(priv, addr, read_write);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
outb_p(data->word & 0xff, SMBHSTDAT0(priv));
|
||||
outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
|
||||
iowrite8(data->word & 0xff, SMBHSTDAT0(priv));
|
||||
iowrite8((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
|
||||
}
|
||||
outb_p(hstcmd, SMBHSTCMD(priv));
|
||||
iowrite8(hstcmd, SMBHSTCMD(priv));
|
||||
xact = I801_WORD_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
|
||||
outb_p(data->word & 0xff, SMBHSTDAT0(priv));
|
||||
outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
|
||||
outb_p(hstcmd, SMBHSTCMD(priv));
|
||||
iowrite8(data->word & 0xff, SMBHSTDAT0(priv));
|
||||
iowrite8((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
|
||||
iowrite8(hstcmd, SMBHSTCMD(priv));
|
||||
read_write = I2C_SMBUS_READ;
|
||||
xact = I801_PROC_CALL;
|
||||
break;
|
||||
@ -810,12 +805,12 @@ static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data
|
||||
switch (command) {
|
||||
case I2C_SMBUS_BYTE:
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
data->byte = inb_p(SMBHSTDAT0(priv));
|
||||
data->byte = ioread8(SMBHSTDAT0(priv));
|
||||
break;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
data->word = inb_p(SMBHSTDAT0(priv)) +
|
||||
(inb_p(SMBHSTDAT1(priv)) << 8);
|
||||
data->word = ioread8(SMBHSTDAT0(priv)) +
|
||||
(ioread8(SMBHSTDAT1(priv)) << 8);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -836,7 +831,7 @@ static int i801_smbus_block_transaction(struct i801_priv *priv, union i2c_smbus_
|
||||
i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE);
|
||||
else
|
||||
i801_set_hstadd(priv, addr, read_write);
|
||||
outb_p(hstcmd, SMBHSTCMD(priv));
|
||||
iowrite8(hstcmd, SMBHSTCMD(priv));
|
||||
|
||||
if (priv->features & FEATURE_BLOCK_BUFFER)
|
||||
return i801_block_transaction_by_block(priv, data, read_write, command);
|
||||
@ -862,9 +857,9 @@ static int i801_i2c_block_transaction(struct i801_priv *priv, union i2c_smbus_da
|
||||
|
||||
/* NB: page 240 of ICH5 datasheet shows that DATA1 is the cmd field when reading */
|
||||
if (read_write == I2C_SMBUS_READ)
|
||||
outb_p(hstcmd, SMBHSTDAT1(priv));
|
||||
iowrite8(hstcmd, SMBHSTDAT1(priv));
|
||||
else
|
||||
outb_p(hstcmd, SMBHSTCMD(priv));
|
||||
iowrite8(hstcmd, SMBHSTCMD(priv));
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
/* set I2C_EN bit in configuration register */
|
||||
@ -907,9 +902,9 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
||||
&& size != I2C_SMBUS_I2C_BLOCK_DATA;
|
||||
|
||||
if (hwpec) /* enable/disable hardware PEC */
|
||||
outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
|
||||
iowrite8(ioread8(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
|
||||
else
|
||||
outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
|
||||
iowrite8(ioread8(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
|
||||
SMBAUXCTL(priv));
|
||||
|
||||
if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_BLOCK_PROC_CALL)
|
||||
@ -925,13 +920,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
|
||||
* time, so we forcibly disable it after every transaction.
|
||||
*/
|
||||
if (hwpec)
|
||||
outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
|
||||
iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
|
||||
out:
|
||||
/*
|
||||
* Unlock the SMBus device for use by BIOS/ACPI,
|
||||
* and clear status flags if not done already.
|
||||
*/
|
||||
outb_p(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
|
||||
iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
|
||||
|
||||
pm_runtime_mark_last_busy(&priv->pci_dev->dev);
|
||||
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
|
||||
@ -968,11 +963,11 @@ static void i801_enable_host_notify(struct i2c_adapter *adapter)
|
||||
* from the SMB_ALERT signal because the driver does not support
|
||||
* SMBus Alert.
|
||||
*/
|
||||
outb_p(SMBSLVCMD_HST_NTFY_INTREN | SMBSLVCMD_SMBALERT_DISABLE |
|
||||
iowrite8(SMBSLVCMD_HST_NTFY_INTREN | SMBSLVCMD_SMBALERT_DISABLE |
|
||||
priv->original_slvcmd, SMBSLVCMD(priv));
|
||||
|
||||
/* clear Host Notify bit to allow a new notification */
|
||||
outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
|
||||
iowrite8(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
|
||||
}
|
||||
|
||||
static void i801_disable_host_notify(struct i801_priv *priv)
|
||||
@ -980,7 +975,7 @@ static void i801_disable_host_notify(struct i801_priv *priv)
|
||||
if (!(priv->features & FEATURE_HOST_NOTIFY))
|
||||
return;
|
||||
|
||||
outb_p(priv->original_slvcmd, SMBSLVCMD(priv));
|
||||
iowrite8(priv->original_slvcmd, SMBSLVCMD(priv));
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
@ -1438,14 +1433,14 @@ static void i801_add_tco(struct i801_priv *priv)
|
||||
priv->tco_pdev = i801_add_tco_spt(pci_dev, tco_res);
|
||||
|
||||
if (IS_ERR(priv->tco_pdev))
|
||||
dev_warn(&pci_dev->dev, "failed to create iTCO device\n");
|
||||
pci_warn(pci_dev, "failed to create iTCO device\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
|
||||
acpi_physical_address address)
|
||||
{
|
||||
return address >= priv->smba &&
|
||||
return address >= pci_resource_start(priv->pci_dev, SMBBAR) &&
|
||||
address <= pci_resource_end(priv->pci_dev, SMBBAR);
|
||||
}
|
||||
|
||||
@ -1467,8 +1462,8 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
|
||||
if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
|
||||
priv->acpi_reserved = true;
|
||||
|
||||
dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
|
||||
dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n");
|
||||
pci_warn(pdev, "BIOS is accessing SMBus registers\n");
|
||||
pci_warn(pdev, "Driver SMBus register access inhibited\n");
|
||||
|
||||
/*
|
||||
* BIOS is accessing the host controller so prevent it from
|
||||
@ -1522,13 +1517,13 @@ static void i801_setup_hstcfg(struct i801_priv *priv)
|
||||
|
||||
static void i801_restore_regs(struct i801_priv *priv)
|
||||
{
|
||||
outb_p(priv->original_hstcnt, SMBHSTCNT(priv));
|
||||
iowrite8(priv->original_hstcnt, SMBHSTCNT(priv));
|
||||
pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg);
|
||||
}
|
||||
|
||||
static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
int err, i;
|
||||
int err, i, bar = SMBBAR;
|
||||
struct i801_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
@ -1549,8 +1544,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
/* Disable features on user request */
|
||||
for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
|
||||
if (priv->features & disable_features & (1 << i))
|
||||
dev_notice(&dev->dev, "%s disabled by user\n",
|
||||
i801_feature_names[i]);
|
||||
pci_notice(dev, "%s disabled by user\n", i801_feature_names[i]);
|
||||
}
|
||||
priv->features &= ~disable_features;
|
||||
|
||||
@ -1564,48 +1558,46 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
*/
|
||||
err = pci_enable_device(dev);
|
||||
if (err) {
|
||||
dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
|
||||
err);
|
||||
pci_err(dev, "Failed to enable SMBus PCI device (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Determine the address of the SMBus area */
|
||||
priv->smba = pci_resource_start(dev, SMBBAR);
|
||||
if (!priv->smba) {
|
||||
dev_err(&dev->dev,
|
||||
"SMBus base address uninitialized, upgrade BIOS\n");
|
||||
if (!pci_resource_start(dev, SMBBAR)) {
|
||||
pci_err(dev, "SMBus base address uninitialized, upgrade BIOS\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (i801_acpi_probe(priv))
|
||||
return -ENODEV;
|
||||
|
||||
err = pcim_iomap_regions(dev, 1 << SMBBAR, DRV_NAME);
|
||||
if (err) {
|
||||
dev_err(&dev->dev,
|
||||
"Failed to request SMBus region 0x%lx-0x%Lx\n",
|
||||
priv->smba,
|
||||
(unsigned long long)pci_resource_end(dev, SMBBAR));
|
||||
if (pci_resource_flags(dev, SMBBAR_MMIO) & IORESOURCE_MEM)
|
||||
bar = SMBBAR_MMIO;
|
||||
|
||||
priv->smba = pcim_iomap_region(dev, bar, DRV_NAME);
|
||||
if (IS_ERR(priv->smba)) {
|
||||
pci_err(dev, "Failed to request SMBus region %pr\n",
|
||||
pci_resource_n(dev, bar));
|
||||
i801_acpi_remove(priv);
|
||||
return err;
|
||||
return PTR_ERR(priv->smba);
|
||||
}
|
||||
|
||||
pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg);
|
||||
pci_read_config_byte(dev, SMBHSTCFG, &priv->original_hstcfg);
|
||||
i801_setup_hstcfg(priv);
|
||||
if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN))
|
||||
dev_info(&dev->dev, "Enabling SMBus device\n");
|
||||
pci_info(dev, "Enabling SMBus device\n");
|
||||
|
||||
if (priv->original_hstcfg & SMBHSTCFG_SMB_SMI_EN) {
|
||||
dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
|
||||
pci_dbg(dev, "SMBus using interrupt SMI#\n");
|
||||
/* Disable SMBus interrupt feature if SMBus using SMI# */
|
||||
priv->features &= ~FEATURE_IRQ;
|
||||
}
|
||||
if (priv->original_hstcfg & SMBHSTCFG_SPD_WD)
|
||||
dev_info(&dev->dev, "SPD Write Disable is set\n");
|
||||
pci_info(dev, "SPD Write Disable is set\n");
|
||||
|
||||
/* Clear special mode bits */
|
||||
if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
|
||||
outb_p(inb_p(SMBAUXCTL(priv)) &
|
||||
iowrite8(ioread8(SMBAUXCTL(priv)) &
|
||||
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
|
||||
|
||||
/* Default timeout in interrupt mode: 200 ms */
|
||||
@ -1620,7 +1612,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
/* Complain if an interrupt is already pending */
|
||||
pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists);
|
||||
if (pcists & PCI_STATUS_INTERRUPT)
|
||||
dev_warn(&dev->dev, "An interrupt is pending!\n");
|
||||
pci_warn(dev, "An interrupt is pending!\n");
|
||||
}
|
||||
|
||||
if (priv->features & FEATURE_IRQ) {
|
||||
@ -1629,12 +1621,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
|
||||
IRQF_SHARED, DRV_NAME, priv);
|
||||
if (err) {
|
||||
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
|
||||
dev->irq, err);
|
||||
pci_err(dev, "Failed to allocate irq %d: %d\n", dev->irq, err);
|
||||
priv->features &= ~FEATURE_IRQ;
|
||||
}
|
||||
}
|
||||
dev_info(&dev->dev, "SMBus using %s\n",
|
||||
pci_info(dev, "SMBus using %s\n",
|
||||
priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling");
|
||||
|
||||
/* Host notification uses an interrupt */
|
||||
@ -1642,9 +1633,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
priv->features &= ~FEATURE_HOST_NOTIFY;
|
||||
|
||||
/* Remember original Interrupt and Host Notify settings */
|
||||
priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
|
||||
priv->original_hstcnt = ioread8(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
|
||||
if (priv->features & FEATURE_HOST_NOTIFY)
|
||||
priv->original_slvcmd = inb_p(SMBSLVCMD(priv));
|
||||
priv->original_slvcmd = ioread8(SMBSLVCMD(priv));
|
||||
|
||||
i801_add_tco(priv);
|
||||
|
||||
@ -1653,9 +1644,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
* to instantiante i2c_clients, do not change.
|
||||
*/
|
||||
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
|
||||
"SMBus %s adapter at %04lx",
|
||||
"SMBus %s adapter at %s",
|
||||
(priv->features & FEATURE_IDF) ? "I801 IDF" : "I801",
|
||||
priv->smba);
|
||||
pci_name(dev));
|
||||
|
||||
err = i2c_add_adapter(&priv->adapter);
|
||||
if (err) {
|
||||
|
@ -512,19 +512,17 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
|
||||
static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
|
||||
{
|
||||
volatile struct iic_regs __iomem *iic = dev->vaddr;
|
||||
u16 addr = msg->addr;
|
||||
|
||||
DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
|
||||
addr, msg->flags & I2C_M_TEN ? 10 : 7);
|
||||
msg->addr, msg->flags & I2C_M_TEN ? 10 : 7);
|
||||
|
||||
if (msg->flags & I2C_M_TEN){
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
out_8(&iic->cntl, CNTL_AMD);
|
||||
out_8(&iic->lmadr, addr);
|
||||
out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06));
|
||||
}
|
||||
else {
|
||||
out_8(&iic->lmadr, i2c_10bit_addr_lo_from_msg(msg));
|
||||
out_8(&iic->hmadr, i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD);
|
||||
} else {
|
||||
out_8(&iic->cntl, 0);
|
||||
out_8(&iic->lmadr, addr << 1);
|
||||
out_8(&iic->lmadr, i2c_8bit_addr_from_msg(msg) & ~I2C_M_RD);
|
||||
}
|
||||
}
|
||||
|
||||
|
602
drivers/i2c/busses/i2c-k1.c
Normal file
602
drivers/i2c/busses/i2c-k1.c
Normal file
@ -0,0 +1,602 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2024-2025 Troy Mitchell <troymitchell988@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* spacemit i2c registers */
|
||||
#define SPACEMIT_ICR 0x0 /* Control register */
|
||||
#define SPACEMIT_ISR 0x4 /* Status register */
|
||||
#define SPACEMIT_IDBR 0xc /* Data buffer register */
|
||||
#define SPACEMIT_IBMR 0x1c /* Bus monitor register */
|
||||
|
||||
/* SPACEMIT_ICR register fields */
|
||||
#define SPACEMIT_CR_START BIT(0) /* start bit */
|
||||
#define SPACEMIT_CR_STOP BIT(1) /* stop bit */
|
||||
#define SPACEMIT_CR_ACKNAK BIT(2) /* send ACK(0) or NAK(1) */
|
||||
#define SPACEMIT_CR_TB BIT(3) /* transfer byte bit */
|
||||
/* Bits 4-7 are reserved */
|
||||
#define SPACEMIT_CR_MODE_FAST BIT(8) /* bus mode (master operation) */
|
||||
/* Bit 9 is reserved */
|
||||
#define SPACEMIT_CR_UR BIT(10) /* unit reset */
|
||||
/* Bits 11-12 are reserved */
|
||||
#define SPACEMIT_CR_SCLE BIT(13) /* master clock enable */
|
||||
#define SPACEMIT_CR_IUE BIT(14) /* unit enable */
|
||||
/* Bits 15-17 are reserved */
|
||||
#define SPACEMIT_CR_ALDIE BIT(18) /* enable arbitration interrupt */
|
||||
#define SPACEMIT_CR_DTEIE BIT(19) /* enable TX interrupts */
|
||||
#define SPACEMIT_CR_DRFIE BIT(20) /* enable RX interrupts */
|
||||
#define SPACEMIT_CR_GCD BIT(21) /* general call disable */
|
||||
#define SPACEMIT_CR_BEIE BIT(22) /* enable bus error ints */
|
||||
/* Bits 23-24 are reserved */
|
||||
#define SPACEMIT_CR_MSDIE BIT(25) /* master STOP detected int enable */
|
||||
#define SPACEMIT_CR_MSDE BIT(26) /* master STOP detected enable */
|
||||
#define SPACEMIT_CR_TXDONEIE BIT(27) /* transaction done int enable */
|
||||
#define SPACEMIT_CR_TXEIE BIT(28) /* transmit FIFO empty int enable */
|
||||
#define SPACEMIT_CR_RXHFIE BIT(29) /* receive FIFO half-full int enable */
|
||||
#define SPACEMIT_CR_RXFIE BIT(30) /* receive FIFO full int enable */
|
||||
#define SPACEMIT_CR_RXOVIE BIT(31) /* receive FIFO overrun int enable */
|
||||
|
||||
#define SPACEMIT_I2C_INT_CTRL_MASK (SPACEMIT_CR_ALDIE | SPACEMIT_CR_DTEIE | \
|
||||
SPACEMIT_CR_DRFIE | SPACEMIT_CR_BEIE | \
|
||||
SPACEMIT_CR_TXDONEIE | SPACEMIT_CR_TXEIE | \
|
||||
SPACEMIT_CR_RXHFIE | SPACEMIT_CR_RXFIE | \
|
||||
SPACEMIT_CR_RXOVIE | SPACEMIT_CR_MSDIE)
|
||||
|
||||
/* SPACEMIT_ISR register fields */
|
||||
/* Bits 0-13 are reserved */
|
||||
#define SPACEMIT_SR_ACKNAK BIT(14) /* ACK/NACK status */
|
||||
#define SPACEMIT_SR_UB BIT(15) /* unit busy */
|
||||
#define SPACEMIT_SR_IBB BIT(16) /* i2c bus busy */
|
||||
#define SPACEMIT_SR_EBB BIT(17) /* early bus busy */
|
||||
#define SPACEMIT_SR_ALD BIT(18) /* arbitration loss detected */
|
||||
#define SPACEMIT_SR_ITE BIT(19) /* TX buffer empty */
|
||||
#define SPACEMIT_SR_IRF BIT(20) /* RX buffer full */
|
||||
#define SPACEMIT_SR_GCAD BIT(21) /* general call address detected */
|
||||
#define SPACEMIT_SR_BED BIT(22) /* bus error no ACK/NAK */
|
||||
#define SPACEMIT_SR_SAD BIT(23) /* slave address detected */
|
||||
#define SPACEMIT_SR_SSD BIT(24) /* slave stop detected */
|
||||
/* Bit 25 is reserved */
|
||||
#define SPACEMIT_SR_MSD BIT(26) /* master stop detected */
|
||||
#define SPACEMIT_SR_TXDONE BIT(27) /* transaction done */
|
||||
#define SPACEMIT_SR_TXE BIT(28) /* TX FIFO empty */
|
||||
#define SPACEMIT_SR_RXHF BIT(29) /* RX FIFO half-full */
|
||||
#define SPACEMIT_SR_RXF BIT(30) /* RX FIFO full */
|
||||
#define SPACEMIT_SR_RXOV BIT(31) /* RX FIFO overrun */
|
||||
|
||||
#define SPACEMIT_I2C_INT_STATUS_MASK (SPACEMIT_SR_RXOV | SPACEMIT_SR_RXF | SPACEMIT_SR_RXHF | \
|
||||
SPACEMIT_SR_TXE | SPACEMIT_SR_TXDONE | SPACEMIT_SR_MSD | \
|
||||
SPACEMIT_SR_SSD | SPACEMIT_SR_SAD | SPACEMIT_SR_BED | \
|
||||
SPACEMIT_SR_GCAD | SPACEMIT_SR_IRF | SPACEMIT_SR_ITE | \
|
||||
SPACEMIT_SR_ALD)
|
||||
|
||||
/* SPACEMIT_IBMR register fields */
|
||||
#define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */
|
||||
#define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */
|
||||
|
||||
/* i2c bus recover timeout: us */
|
||||
#define SPACEMIT_I2C_BUS_BUSY_TIMEOUT 100000
|
||||
|
||||
#define SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ 100000 /* Hz */
|
||||
#define SPACEMIT_I2C_MAX_FAST_MODE_FREQ 400000 /* Hz */
|
||||
|
||||
#define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD)
|
||||
|
||||
enum spacemit_i2c_state {
|
||||
SPACEMIT_STATE_IDLE,
|
||||
SPACEMIT_STATE_START,
|
||||
SPACEMIT_STATE_READ,
|
||||
SPACEMIT_STATE_WRITE,
|
||||
};
|
||||
|
||||
/* i2c-spacemit driver's main struct */
|
||||
struct spacemit_i2c_dev {
|
||||
struct device *dev;
|
||||
struct i2c_adapter adapt;
|
||||
|
||||
/* hardware resources */
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
u32 clock_freq;
|
||||
|
||||
struct i2c_msg *msgs;
|
||||
u32 msg_num;
|
||||
|
||||
/* index of the current message being processed */
|
||||
u32 msg_idx;
|
||||
u8 *msg_buf;
|
||||
/* the number of unprocessed bytes remaining in the current message */
|
||||
u32 unprocessed;
|
||||
|
||||
enum spacemit_i2c_state state;
|
||||
bool read;
|
||||
struct completion complete;
|
||||
u32 status;
|
||||
};
|
||||
|
||||
static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val |= SPACEMIT_CR_IUE;
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val &= ~SPACEMIT_CR_IUE;
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR);
|
||||
udelay(5);
|
||||
writel(0, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
|
||||
static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status);
|
||||
|
||||
if (i2c->status & (SPACEMIT_SR_BED | SPACEMIT_SR_ALD)) {
|
||||
spacemit_i2c_reset(i2c);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO;
|
||||
}
|
||||
|
||||
static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
/* if bus is locked, reset unit. 0: locked */
|
||||
status = readl(i2c->base + SPACEMIT_IBMR);
|
||||
if ((status & SPACEMIT_BMR_SDA) && (status & SPACEMIT_BMR_SCL))
|
||||
return;
|
||||
|
||||
spacemit_i2c_reset(i2c);
|
||||
usleep_range(10, 20);
|
||||
|
||||
/* check scl status again */
|
||||
status = readl(i2c->base + SPACEMIT_IBMR);
|
||||
if (!(status & SPACEMIT_BMR_SCL))
|
||||
dev_warn_ratelimited(i2c->dev, "unit reset failed\n");
|
||||
}
|
||||
|
||||
static int spacemit_i2c_wait_bus_idle(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
val = readl(i2c->base + SPACEMIT_ISR);
|
||||
if (!(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)))
|
||||
return 0;
|
||||
|
||||
ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,
|
||||
val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
|
||||
1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT);
|
||||
if (ret)
|
||||
spacemit_i2c_reset(i2c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
/* in case bus is not released after transfer completes */
|
||||
if (readl(i2c->base + SPACEMIT_ISR) & SPACEMIT_SR_EBB) {
|
||||
spacemit_i2c_conditionally_reset_bus(i2c);
|
||||
usleep_range(90, 150);
|
||||
}
|
||||
}
|
||||
|
||||
static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* Unmask interrupt bits for all xfer mode:
|
||||
* bus error, arbitration loss detected.
|
||||
* For transaction complete signal, we use master stop
|
||||
* interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.
|
||||
*/
|
||||
val = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;
|
||||
|
||||
/*
|
||||
* Unmask interrupt bits for interrupt xfer mode:
|
||||
* When IDBR receives a byte, an interrupt is triggered.
|
||||
*
|
||||
* For the tx empty interrupt, it will be enabled in the
|
||||
* i2c_start function.
|
||||
* Otherwise, it will cause an erroneous empty interrupt before i2c_start.
|
||||
*/
|
||||
val |= SPACEMIT_CR_DRFIE;
|
||||
|
||||
if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
|
||||
val |= SPACEMIT_CR_MODE_FAST;
|
||||
|
||||
/* disable response to general call */
|
||||
val |= SPACEMIT_CR_GCD;
|
||||
|
||||
/* enable SCL clock output */
|
||||
val |= SPACEMIT_CR_SCLE;
|
||||
|
||||
/* enable master stop detected */
|
||||
val |= SPACEMIT_CR_MSDE | SPACEMIT_CR_MSDIE;
|
||||
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
|
||||
static inline void
|
||||
spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask)
|
||||
{
|
||||
writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 target_addr_rw, val;
|
||||
struct i2c_msg *cur_msg = i2c->msgs + i2c->msg_idx;
|
||||
|
||||
i2c->read = !!(cur_msg->flags & I2C_M_RD);
|
||||
|
||||
i2c->state = SPACEMIT_STATE_START;
|
||||
|
||||
target_addr_rw = (cur_msg->addr & 0x7f) << 1;
|
||||
if (cur_msg->flags & I2C_M_RD)
|
||||
target_addr_rw |= 1;
|
||||
|
||||
writel(target_addr_rw, i2c->base + SPACEMIT_IDBR);
|
||||
|
||||
/* send start pulse */
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val &= ~SPACEMIT_CR_STOP;
|
||||
val |= SPACEMIT_CR_START | SPACEMIT_CR_TB | SPACEMIT_CR_DTEIE;
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_stop(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val |= SPACEMIT_CR_STOP | SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
|
||||
|
||||
if (i2c->read)
|
||||
val |= SPACEMIT_CR_ACKNAK;
|
||||
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
|
||||
static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
unsigned long time_left;
|
||||
struct i2c_msg *msg;
|
||||
|
||||
for (i2c->msg_idx = 0; i2c->msg_idx < i2c->msg_num; i2c->msg_idx++) {
|
||||
msg = &i2c->msgs[i2c->msg_idx];
|
||||
i2c->msg_buf = msg->buf;
|
||||
i2c->unprocessed = msg->len;
|
||||
i2c->status = 0;
|
||||
|
||||
reinit_completion(&i2c->complete);
|
||||
|
||||
spacemit_i2c_start(i2c);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c->complete,
|
||||
i2c->adapt.timeout);
|
||||
if (!time_left) {
|
||||
dev_err(i2c->dev, "msg completion timeout\n");
|
||||
spacemit_i2c_conditionally_reset_bus(i2c);
|
||||
spacemit_i2c_reset(i2c);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (i2c->status & SPACEMIT_SR_ERR)
|
||||
return spacemit_i2c_handle_err(i2c);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool spacemit_i2c_is_last_msg(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
if (i2c->msg_idx != i2c->msg_num - 1)
|
||||
return false;
|
||||
|
||||
if (i2c->read)
|
||||
return i2c->unprocessed == 1;
|
||||
|
||||
return !i2c->unprocessed;
|
||||
}
|
||||
|
||||
static void spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
/* if transfer completes, SPACEMIT_ISR will handle it */
|
||||
if (i2c->status & SPACEMIT_SR_MSD)
|
||||
return;
|
||||
|
||||
if (i2c->unprocessed) {
|
||||
writel(*i2c->msg_buf++, i2c->base + SPACEMIT_IDBR);
|
||||
i2c->unprocessed--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* SPACEMIT_STATE_IDLE avoids trigger next byte */
|
||||
i2c->state = SPACEMIT_STATE_IDLE;
|
||||
complete(&i2c->complete);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_handle_read(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
if (i2c->unprocessed) {
|
||||
*i2c->msg_buf++ = readl(i2c->base + SPACEMIT_IDBR);
|
||||
i2c->unprocessed--;
|
||||
}
|
||||
|
||||
/* if transfer completes, SPACEMIT_ISR will handle it */
|
||||
if (i2c->status & (SPACEMIT_SR_MSD | SPACEMIT_SR_ACKNAK))
|
||||
return;
|
||||
|
||||
/* it has to append stop bit in icr that read last byte */
|
||||
if (i2c->unprocessed)
|
||||
return;
|
||||
|
||||
/* SPACEMIT_STATE_IDLE avoids trigger next byte */
|
||||
i2c->state = SPACEMIT_STATE_IDLE;
|
||||
complete(&i2c->complete);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_handle_start(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
i2c->state = i2c->read ? SPACEMIT_STATE_READ : SPACEMIT_STATE_WRITE;
|
||||
if (i2c->state == SPACEMIT_STATE_WRITE)
|
||||
spacemit_i2c_handle_write(i2c);
|
||||
}
|
||||
|
||||
static void spacemit_i2c_err_check(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* Send transaction complete signal:
|
||||
* error happens, detect master stop
|
||||
*/
|
||||
if (!(i2c->status & (SPACEMIT_SR_ERR | SPACEMIT_SR_MSD)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Here the transaction is already done, we don't need any
|
||||
* other interrupt signals from now, in case any interrupt
|
||||
* happens before spacemit_i2c_xfer to disable irq and i2c unit,
|
||||
* we mask all the interrupt signals and clear the interrupt
|
||||
* status.
|
||||
*/
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val &= ~SPACEMIT_I2C_INT_CTRL_MASK;
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
|
||||
spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
|
||||
|
||||
i2c->state = SPACEMIT_STATE_IDLE;
|
||||
complete(&i2c->complete);
|
||||
}
|
||||
|
||||
static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = devid;
|
||||
u32 status, val;
|
||||
|
||||
status = readl(i2c->base + SPACEMIT_ISR);
|
||||
if (!status)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
i2c->status = status;
|
||||
|
||||
spacemit_i2c_clear_int_status(i2c, status);
|
||||
|
||||
if (i2c->status & SPACEMIT_SR_ERR)
|
||||
goto err_out;
|
||||
|
||||
val = readl(i2c->base + SPACEMIT_ICR);
|
||||
val &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK | SPACEMIT_CR_STOP | SPACEMIT_CR_START);
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
|
||||
switch (i2c->state) {
|
||||
case SPACEMIT_STATE_START:
|
||||
spacemit_i2c_handle_start(i2c);
|
||||
break;
|
||||
case SPACEMIT_STATE_READ:
|
||||
spacemit_i2c_handle_read(i2c);
|
||||
break;
|
||||
case SPACEMIT_STATE_WRITE:
|
||||
spacemit_i2c_handle_write(i2c);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (i2c->state != SPACEMIT_STATE_IDLE) {
|
||||
if (spacemit_i2c_is_last_msg(i2c)) {
|
||||
/* trigger next byte with stop */
|
||||
spacemit_i2c_stop(i2c);
|
||||
} else {
|
||||
/* trigger next byte */
|
||||
val |= SPACEMIT_CR_ALDIE | SPACEMIT_CR_TB;
|
||||
writel(val, i2c->base + SPACEMIT_ICR);
|
||||
}
|
||||
}
|
||||
|
||||
err_out:
|
||||
spacemit_i2c_err_check(i2c);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void spacemit_i2c_calc_timeout(struct spacemit_i2c_dev *i2c)
|
||||
{
|
||||
unsigned long timeout;
|
||||
int idx = 0, cnt = 0;
|
||||
|
||||
for (; idx < i2c->msg_num; idx++)
|
||||
cnt += (i2c->msgs + idx)->len + 1;
|
||||
|
||||
/*
|
||||
* Multiply by 9 because each byte in I2C transmission requires
|
||||
* 9 clock cycles: 8 bits of data plus 1 ACK/NACK bit.
|
||||
*/
|
||||
timeout = cnt * 9 * USEC_PER_SEC / i2c->clock_freq;
|
||||
|
||||
i2c->adapt.timeout = usecs_to_jiffies(timeout + USEC_PER_SEC / 10) / i2c->msg_num;
|
||||
}
|
||||
|
||||
static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = i2c_get_adapdata(adapt);
|
||||
int ret;
|
||||
|
||||
i2c->msgs = msgs;
|
||||
i2c->msg_num = num;
|
||||
|
||||
spacemit_i2c_calc_timeout(i2c);
|
||||
|
||||
spacemit_i2c_init(i2c);
|
||||
|
||||
spacemit_i2c_enable(i2c);
|
||||
|
||||
ret = spacemit_i2c_wait_bus_idle(i2c);
|
||||
if (!ret)
|
||||
spacemit_i2c_xfer_msg(i2c);
|
||||
else if (ret < 0)
|
||||
dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret);
|
||||
else
|
||||
spacemit_i2c_check_bus_release(i2c);
|
||||
|
||||
spacemit_i2c_disable(i2c);
|
||||
|
||||
if (ret == -ETIMEDOUT || ret == -EAGAIN)
|
||||
dev_err(i2c->dev, "i2c transfer failed, ret %d err 0x%lx\n",
|
||||
ret, i2c->status & SPACEMIT_SR_ERR);
|
||||
|
||||
return ret < 0 ? ret : num;
|
||||
}
|
||||
|
||||
static u32 spacemit_i2c_func(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm spacemit_i2c_algo = {
|
||||
.xfer = spacemit_i2c_xfer,
|
||||
.functionality = spacemit_i2c_func,
|
||||
};
|
||||
|
||||
static int spacemit_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *of_node = pdev->dev.of_node;
|
||||
struct spacemit_i2c_dev *i2c;
|
||||
int ret;
|
||||
|
||||
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
|
||||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq);
|
||||
if (ret && ret != -EINVAL)
|
||||
dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
|
||||
|
||||
/* For now, this driver doesn't support high-speed. */
|
||||
if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
|
||||
dev_warn(dev, "unsupported clock frequency %u; using %u\n",
|
||||
i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
|
||||
i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
|
||||
} else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
|
||||
dev_warn(dev, "unsupported clock frequency %u; using %u\n",
|
||||
i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
|
||||
i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
|
||||
}
|
||||
|
||||
i2c->dev = &pdev->dev;
|
||||
|
||||
i2c->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->base))
|
||||
return dev_err_probe(dev, PTR_ERR(i2c->base), "failed to do ioremap");
|
||||
|
||||
i2c->irq = platform_get_irq(pdev, 0);
|
||||
if (i2c->irq < 0)
|
||||
return dev_err_probe(dev, i2c->irq, "failed to get irq resource");
|
||||
|
||||
ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
|
||||
IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(i2c->dev), i2c);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to request irq");
|
||||
|
||||
clk = devm_clk_get_enabled(dev, "func");
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
|
||||
|
||||
clk = devm_clk_get_enabled(dev, "bus");
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
|
||||
|
||||
spacemit_i2c_reset(i2c);
|
||||
|
||||
i2c_set_adapdata(&i2c->adapt, i2c);
|
||||
i2c->adapt.owner = THIS_MODULE;
|
||||
i2c->adapt.algo = &spacemit_i2c_algo;
|
||||
i2c->adapt.dev.parent = i2c->dev;
|
||||
i2c->adapt.nr = pdev->id;
|
||||
|
||||
i2c->adapt.dev.of_node = of_node;
|
||||
|
||||
strscpy(i2c->adapt.name, "spacemit-i2c-adapter", sizeof(i2c->adapt.name));
|
||||
|
||||
init_completion(&i2c->complete);
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
ret = i2c_add_numbered_adapter(&i2c->adapt);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to add i2c adapter");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void spacemit_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spacemit_i2c_dev *i2c = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&i2c->adapt);
|
||||
}
|
||||
|
||||
static const struct of_device_id spacemit_i2c_of_match[] = {
|
||||
{ .compatible = "spacemit,k1-i2c", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spacemit_i2c_of_match);
|
||||
|
||||
static struct platform_driver spacemit_i2c_driver = {
|
||||
.probe = spacemit_i2c_probe,
|
||||
.remove = spacemit_i2c_remove,
|
||||
.driver = {
|
||||
.name = "i2c-k1",
|
||||
.of_match_table = spacemit_i2c_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(spacemit_i2c_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("I2C bus driver for SpacemiT K1 SoC");
|
@ -115,9 +115,7 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c)
|
||||
if (i2c->state == STATE_ADDR) {
|
||||
/* 10 bit address? */
|
||||
if (i2c->msg->flags & I2C_M_TEN) {
|
||||
addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6);
|
||||
/* Set read bit if necessary */
|
||||
addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
|
||||
addr = i2c_10bit_addr_hi_from_msg(msg);
|
||||
i2c->state = STATE_ADDR10;
|
||||
} else {
|
||||
addr = i2c_8bit_addr_from_msg(i2c->msg);
|
||||
@ -132,10 +130,12 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c)
|
||||
|
||||
/* Second part of 10 bit addressing */
|
||||
if (i2c->state == STATE_ADDR10) {
|
||||
kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff);
|
||||
addr = i2c_10bit_addr_lo_from_msg(msg);
|
||||
i2c->state = STATE_START;
|
||||
|
||||
kempld_write8(pld, KEMPLD_I2C_DATA, addr);
|
||||
kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
|
||||
|
||||
i2c->state = STATE_START;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
@ -495,65 +496,6 @@ static u8 mlxbf_i2c_bus_count;
|
||||
|
||||
static struct mutex mlxbf_i2c_bus_lock;
|
||||
|
||||
/*
|
||||
* Function to poll a set of bits at a specific address; it checks whether
|
||||
* the bits are equal to zero when eq_zero is set to 'true', and not equal
|
||||
* to zero when eq_zero is set to 'false'.
|
||||
* Note that the timeout is given in microseconds.
|
||||
*/
|
||||
static u32 mlxbf_i2c_poll(void __iomem *io, u32 addr, u32 mask,
|
||||
bool eq_zero, u32 timeout)
|
||||
{
|
||||
u32 bits;
|
||||
|
||||
timeout = (timeout / MLXBF_I2C_POLL_FREQ_IN_USEC) + 1;
|
||||
|
||||
do {
|
||||
bits = readl(io + addr) & mask;
|
||||
if (eq_zero ? bits == 0 : bits != 0)
|
||||
return eq_zero ? 1 : bits;
|
||||
udelay(MLXBF_I2C_POLL_FREQ_IN_USEC);
|
||||
} while (timeout-- != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SW must make sure that the SMBus Master GW is idle before starting
|
||||
* a transaction. Accordingly, this function polls the Master FSM stop
|
||||
* bit; it returns false when the bit is asserted, true if not.
|
||||
*/
|
||||
static bool mlxbf_i2c_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv)
|
||||
{
|
||||
u32 mask = MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK;
|
||||
u32 addr = priv->chip->smbus_master_fsm_off;
|
||||
u32 timeout = MLXBF_I2C_SMBUS_TIMEOUT;
|
||||
|
||||
if (mlxbf_i2c_poll(priv->mst->io, addr, mask, true, timeout))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* wait for the lock to be released before acquiring it.
|
||||
*/
|
||||
static bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv)
|
||||
{
|
||||
if (mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW,
|
||||
MLXBF_I2C_MASTER_LOCK_BIT, true,
|
||||
MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void mlxbf_i2c_smbus_master_unlock(struct mlxbf_i2c_priv *priv)
|
||||
{
|
||||
/* Clear the gw to clear the lock */
|
||||
writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW);
|
||||
}
|
||||
|
||||
static bool mlxbf_i2c_smbus_transaction_success(u32 master_status,
|
||||
u32 cause_status)
|
||||
{
|
||||
@ -583,6 +525,7 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv)
|
||||
{
|
||||
u32 master_status_bits;
|
||||
u32 cause_status_bits;
|
||||
u32 bits;
|
||||
|
||||
/*
|
||||
* GW busy bit is raised by the driver and cleared by the HW
|
||||
@ -591,9 +534,9 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv)
|
||||
* then read the cause and master status bits to determine if
|
||||
* errors occurred during the transaction.
|
||||
*/
|
||||
mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW,
|
||||
MLXBF_I2C_MASTER_BUSY_BIT, true,
|
||||
MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
readl_poll_timeout_atomic(priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW,
|
||||
bits, !(bits & MLXBF_I2C_MASTER_BUSY_BIT),
|
||||
MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
|
||||
/* Read cause status bits. */
|
||||
cause_status_bits = readl(priv->mst_cause->io +
|
||||
@ -740,7 +683,8 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
|
||||
u8 read_en, write_en, block_en, pec_en;
|
||||
u8 slave, flags, addr;
|
||||
u8 *read_buf;
|
||||
int ret = 0;
|
||||
u32 bits;
|
||||
int ret;
|
||||
|
||||
if (request->operation_cnt > MLXBF_I2C_SMBUS_MAX_OP_CNT)
|
||||
return -EINVAL;
|
||||
@ -760,11 +704,22 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
|
||||
* Try to acquire the smbus gw lock before any reads of the GW register since
|
||||
* a read sets the lock.
|
||||
*/
|
||||
if (WARN_ON(!mlxbf_i2c_smbus_master_lock(priv)))
|
||||
ret = readl_poll_timeout_atomic(priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW,
|
||||
bits, !(bits & MLXBF_I2C_MASTER_LOCK_BIT),
|
||||
MLXBF_I2C_POLL_FREQ_IN_USEC,
|
||||
MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT);
|
||||
if (WARN_ON(ret))
|
||||
return -EBUSY;
|
||||
|
||||
/* Check whether the HW is idle */
|
||||
if (WARN_ON(!mlxbf_i2c_smbus_master_wait_for_idle(priv))) {
|
||||
/*
|
||||
* SW must make sure that the SMBus Master GW is idle before starting
|
||||
* a transaction. Accordingly, this call polls the Master FSM stop bit;
|
||||
* it returns -ETIMEDOUT when the bit is asserted, 0 if not.
|
||||
*/
|
||||
ret = readl_poll_timeout_atomic(priv->mst->io + priv->chip->smbus_master_fsm_off,
|
||||
bits, !(bits & MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK),
|
||||
MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
if (WARN_ON(ret)) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
@ -855,7 +810,8 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mlxbf_i2c_smbus_master_unlock(priv);
|
||||
/* Clear the gw to clear the lock */
|
||||
writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1829,18 +1785,6 @@ static bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool mlxbf_i2c_slave_wait_for_idle(struct mlxbf_i2c_priv *priv,
|
||||
u32 timeout)
|
||||
{
|
||||
u32 mask = MLXBF_I2C_CAUSE_S_GW_BUSY_FALL;
|
||||
u32 addr = MLXBF_I2C_CAUSE_ARBITER;
|
||||
|
||||
if (mlxbf_i2c_poll(priv->slv_cause->io, addr, mask, false, timeout))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct i2c_client *mlxbf_i2c_get_slave_from_addr(
|
||||
struct mlxbf_i2c_priv *priv, u8 addr)
|
||||
{
|
||||
@ -1943,7 +1887,9 @@ static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
||||
* Wait until the transfer is completed; the driver will wait
|
||||
* until the GW is idle, a cause will rise on fall of GW busy.
|
||||
*/
|
||||
mlxbf_i2c_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
readl_poll_timeout_atomic(priv->slv_cause->io + MLXBF_I2C_CAUSE_ARBITER,
|
||||
data32, data32 & MLXBF_I2C_CAUSE_S_GW_BUSY_FALL,
|
||||
MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
|
||||
clear_csr:
|
||||
/* Release the Slave GW. */
|
||||
|
@ -164,22 +164,18 @@ static int mtk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
/* write address */
|
||||
if (pmsg->flags & I2C_M_TEN) {
|
||||
/* 10 bits address */
|
||||
addr = 0xf0 | ((pmsg->addr >> 7) & 0x06);
|
||||
addr |= (pmsg->addr & 0xff) << 8;
|
||||
if (pmsg->flags & I2C_M_RD)
|
||||
addr |= 1;
|
||||
iowrite32(addr, i2c->base + REG_SM0D0_REG);
|
||||
ret = mtk_i2c_cmd(i2c, SM0CTL1_WRITE, 2);
|
||||
if (ret)
|
||||
goto err_timeout;
|
||||
addr = i2c_10bit_addr_hi_from_msg(pmsg);
|
||||
addr |= i2c_10bit_addr_lo_from_msg(pmsg) << 8;
|
||||
len = 2;
|
||||
} else {
|
||||
/* 7 bits address */
|
||||
addr = i2c_8bit_addr_from_msg(pmsg);
|
||||
iowrite32(addr, i2c->base + REG_SM0D0_REG);
|
||||
ret = mtk_i2c_cmd(i2c, SM0CTL1_WRITE, 1);
|
||||
if (ret)
|
||||
goto err_timeout;
|
||||
len = 1;
|
||||
}
|
||||
iowrite32(addr, i2c->base + REG_SM0D0_REG);
|
||||
ret = mtk_i2c_cmd(i2c, SM0CTL1_WRITE, len);
|
||||
if (ret)
|
||||
goto err_timeout;
|
||||
|
||||
/* check address ACK */
|
||||
if (!(pmsg->flags & I2C_M_IGNORE_NAK)) {
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1)
|
||||
#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7)
|
||||
#define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3)
|
||||
|
||||
@ -176,22 +175,17 @@ static void
|
||||
mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
|
||||
struct i2c_msg *msg)
|
||||
{
|
||||
u32 dir = 0;
|
||||
|
||||
drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
|
||||
MV64XXX_I2C_REG_CONTROL_TWSIEN;
|
||||
|
||||
if (!drv_data->atomic)
|
||||
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_INTEN;
|
||||
|
||||
if (msg->flags & I2C_M_RD)
|
||||
dir = 1;
|
||||
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
|
||||
drv_data->addr2 = (u32)msg->addr & 0xff;
|
||||
drv_data->addr1 = i2c_10bit_addr_hi_from_msg(msg);
|
||||
drv_data->addr2 = i2c_10bit_addr_lo_from_msg(msg);
|
||||
} else {
|
||||
drv_data->addr1 = MV64XXX_I2C_ADDR_ADDR((u32)msg->addr) | dir;
|
||||
drv_data->addr1 = i2c_8bit_addr_from_msg(msg);
|
||||
drv_data->addr2 = 0;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c)
|
||||
* octeon_i2c_wait - wait for the IFLG to be set
|
||||
* @i2c: The struct octeon_i2c
|
||||
*
|
||||
* Returns 0 on success, otherwise a negative errno.
|
||||
* Returns: 0 on success, otherwise a negative errno.
|
||||
*/
|
||||
static int octeon_i2c_wait(struct octeon_i2c *i2c)
|
||||
{
|
||||
@ -139,7 +139,7 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c)
|
||||
* octeon_i2c_hlc_wait - wait for an HLC operation to complete
|
||||
* @i2c: The struct octeon_i2c
|
||||
*
|
||||
* Returns 0 on success, otherwise -ETIMEDOUT.
|
||||
* Returns: 0 on success, otherwise -ETIMEDOUT.
|
||||
*/
|
||||
static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c)
|
||||
{
|
||||
@ -273,7 +273,7 @@ static int octeon_i2c_recovery(struct octeon_i2c *i2c)
|
||||
* octeon_i2c_start - send START to the bus
|
||||
* @i2c: The struct octeon_i2c
|
||||
*
|
||||
* Returns 0 on success, otherwise a negative errno.
|
||||
* Returns: 0 on success, otherwise a negative errno.
|
||||
*/
|
||||
static int octeon_i2c_start(struct octeon_i2c *i2c)
|
||||
{
|
||||
@ -314,7 +314,7 @@ static void octeon_i2c_stop(struct octeon_i2c *i2c)
|
||||
*
|
||||
* The address is sent over the bus, then the data is read.
|
||||
*
|
||||
* Returns 0 on success, otherwise a negative errno.
|
||||
* Returns: 0 on success, otherwise a negative errno.
|
||||
*/
|
||||
static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
|
||||
u8 *data, u16 *rlength, bool recv_len)
|
||||
@ -382,7 +382,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
|
||||
*
|
||||
* The address is sent over the bus, then the data.
|
||||
*
|
||||
* Returns 0 on success, otherwise a negative errno.
|
||||
* Returns: 0 on success, otherwise a negative errno.
|
||||
*/
|
||||
static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
|
||||
const u8 *data, int length)
|
||||
@ -421,17 +421,12 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
|
||||
octeon_i2c_hlc_enable(i2c);
|
||||
octeon_i2c_hlc_int_clear(i2c);
|
||||
|
||||
cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
|
||||
cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7;
|
||||
/* SIZE */
|
||||
cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
|
||||
/* A */
|
||||
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
|
||||
|
||||
if (msgs[0].flags & I2C_M_TEN)
|
||||
cmd |= SW_TWSI_OP_10;
|
||||
else
|
||||
cmd |= SW_TWSI_OP_7;
|
||||
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
ret = octeon_i2c_hlc_wait(i2c);
|
||||
if (ret)
|
||||
@ -463,17 +458,12 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs)
|
||||
octeon_i2c_hlc_enable(i2c);
|
||||
octeon_i2c_hlc_int_clear(i2c);
|
||||
|
||||
cmd = SW_TWSI_V | SW_TWSI_SOVR;
|
||||
cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7;
|
||||
/* SIZE */
|
||||
cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT;
|
||||
/* A */
|
||||
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
|
||||
|
||||
if (msgs[0].flags & I2C_M_TEN)
|
||||
cmd |= SW_TWSI_OP_10;
|
||||
else
|
||||
cmd |= SW_TWSI_OP_7;
|
||||
|
||||
for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--)
|
||||
cmd |= (u64)msgs[0].buf[j] << (8 * i);
|
||||
|
||||
@ -498,6 +488,45 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Process hlc transaction */
|
||||
static int octeon_i2c_hlc_cmd_send(struct octeon_i2c *i2c, u64 cmd)
|
||||
{
|
||||
octeon_i2c_hlc_int_clear(i2c);
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
|
||||
return octeon_i2c_hlc_wait(i2c);
|
||||
}
|
||||
|
||||
/* Generic consideration for extended internal addresses in i2c hlc r/w ops */
|
||||
static bool octeon_i2c_hlc_ext(struct octeon_i2c *i2c, struct i2c_msg msg, u64 *cmd_in, u64 *ext)
|
||||
{
|
||||
bool set_ext = false;
|
||||
u64 cmd = 0;
|
||||
|
||||
if (msg.len == 2) {
|
||||
cmd |= SW_TWSI_EIA;
|
||||
*ext = (u64)msg.buf[0] << SW_TWSI_IA_SHIFT;
|
||||
cmd |= (u64)msg.buf[1] << SW_TWSI_IA_SHIFT;
|
||||
set_ext = true;
|
||||
} else {
|
||||
cmd |= (u64)msg.buf[0] << SW_TWSI_IA_SHIFT;
|
||||
}
|
||||
|
||||
*cmd_in |= cmd;
|
||||
return set_ext;
|
||||
}
|
||||
|
||||
/* Construct and send i2c transaction core cmd for read ops */
|
||||
static int octeon_i2c_hlc_read_cmd(struct octeon_i2c *i2c, struct i2c_msg msg, u64 cmd)
|
||||
{
|
||||
u64 ext = 0;
|
||||
|
||||
if (octeon_i2c_hlc_ext(i2c, msg, &cmd, &ext))
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
|
||||
|
||||
return octeon_i2c_hlc_cmd_send(i2c, cmd);
|
||||
}
|
||||
|
||||
/* high-level-controller composite write+read, msg0=addr, msg1=data */
|
||||
static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs)
|
||||
{
|
||||
@ -506,32 +535,14 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs
|
||||
|
||||
octeon_i2c_hlc_enable(i2c);
|
||||
|
||||
cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR;
|
||||
cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
|
||||
/* SIZE */
|
||||
cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
|
||||
/* A */
|
||||
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
|
||||
|
||||
if (msgs[0].flags & I2C_M_TEN)
|
||||
cmd |= SW_TWSI_OP_10_IA;
|
||||
else
|
||||
cmd |= SW_TWSI_OP_7_IA;
|
||||
|
||||
if (msgs[0].len == 2) {
|
||||
u64 ext = 0;
|
||||
|
||||
cmd |= SW_TWSI_EIA;
|
||||
ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
|
||||
cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
|
||||
} else {
|
||||
cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
|
||||
}
|
||||
|
||||
octeon_i2c_hlc_int_clear(i2c);
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
|
||||
ret = octeon_i2c_hlc_wait(i2c);
|
||||
/* Send core command */
|
||||
ret = octeon_i2c_hlc_read_cmd(i2c, msgs[0], cmd);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -561,25 +572,14 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
|
||||
|
||||
octeon_i2c_hlc_enable(i2c);
|
||||
|
||||
cmd = SW_TWSI_V | SW_TWSI_SOVR;
|
||||
cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7_IA;
|
||||
/* SIZE */
|
||||
cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT;
|
||||
/* A */
|
||||
cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT;
|
||||
|
||||
if (msgs[0].flags & I2C_M_TEN)
|
||||
cmd |= SW_TWSI_OP_10_IA;
|
||||
else
|
||||
cmd |= SW_TWSI_OP_7_IA;
|
||||
|
||||
if (msgs[0].len == 2) {
|
||||
cmd |= SW_TWSI_EIA;
|
||||
ext |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
|
||||
set_ext = true;
|
||||
cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT;
|
||||
} else {
|
||||
cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT;
|
||||
}
|
||||
/* Set parameters for extended message (if required) */
|
||||
set_ext = octeon_i2c_hlc_ext(i2c, msgs[0], &cmd, &ext);
|
||||
|
||||
for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--)
|
||||
cmd |= (u64)msgs[1].buf[j] << (8 * i);
|
||||
@ -592,10 +592,7 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg
|
||||
if (set_ext)
|
||||
octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c));
|
||||
|
||||
octeon_i2c_hlc_int_clear(i2c);
|
||||
octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c));
|
||||
|
||||
ret = octeon_i2c_hlc_wait(i2c);
|
||||
ret = octeon_i2c_hlc_cmd_send(i2c, cmd);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -613,7 +610,7 @@ err:
|
||||
* @msgs: Pointer to the messages to be processed
|
||||
* @num: Length of the MSGS array
|
||||
*
|
||||
* Returns the number of messages processed, or a negative errno on failure.
|
||||
* Returns: the number of messages processed, or a negative errno on failure.
|
||||
*/
|
||||
int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mux/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_data/i2c-omap.h>
|
||||
@ -211,6 +212,7 @@ struct omap_i2c_dev {
|
||||
u16 syscstate;
|
||||
u16 westate;
|
||||
u16 errata;
|
||||
struct mux_state *mux_state;
|
||||
};
|
||||
|
||||
static const u8 reg_map_ip_v1[] = {
|
||||
@ -1452,6 +1454,23 @@ omap_i2c_probe(struct platform_device *pdev)
|
||||
(1000 * omap->speed / 8);
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "mux-states")) {
|
||||
struct mux_state *mux_state;
|
||||
|
||||
mux_state = devm_mux_state_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(mux_state)) {
|
||||
r = PTR_ERR(mux_state);
|
||||
dev_dbg(&pdev->dev, "failed to get I2C mux: %d\n", r);
|
||||
goto err_disable_pm;
|
||||
}
|
||||
omap->mux_state = mux_state;
|
||||
r = mux_state_select(omap->mux_state);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "failed to select I2C mux: %d\n", r);
|
||||
goto err_disable_pm;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset ASAP, clearing any IRQs */
|
||||
omap_i2c_init(omap);
|
||||
|
||||
@ -1511,6 +1530,9 @@ static void omap_i2c_remove(struct platform_device *pdev)
|
||||
|
||||
i2c_del_adapter(&omap->adapter);
|
||||
|
||||
if (omap->mux_state)
|
||||
mux_state_deselect(omap->mux_state);
|
||||
|
||||
ret = pm_runtime_get_sync(&pdev->dev);
|
||||
if (ret < 0)
|
||||
dev_err(omap->dev, "Failed to resume hardware, skip disable\n");
|
||||
|
@ -5,6 +5,7 @@
|
||||
* SMBus host driver for PA Semi PWRficient
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -26,21 +27,30 @@
|
||||
#define REG_REV 0x28
|
||||
|
||||
/* Register defs */
|
||||
#define MTXFIFO_READ 0x00000400
|
||||
#define MTXFIFO_STOP 0x00000200
|
||||
#define MTXFIFO_START 0x00000100
|
||||
#define MTXFIFO_DATA_M 0x000000ff
|
||||
#define MTXFIFO_READ BIT(10)
|
||||
#define MTXFIFO_STOP BIT(9)
|
||||
#define MTXFIFO_START BIT(8)
|
||||
#define MTXFIFO_DATA_M GENMASK(7, 0)
|
||||
|
||||
#define MRXFIFO_EMPTY 0x00000100
|
||||
#define MRXFIFO_DATA_M 0x000000ff
|
||||
#define MRXFIFO_EMPTY BIT(8)
|
||||
#define MRXFIFO_DATA_M GENMASK(7, 0)
|
||||
|
||||
#define SMSTA_XEN 0x08000000
|
||||
#define SMSTA_MTN 0x00200000
|
||||
#define SMSTA_XIP BIT(28)
|
||||
#define SMSTA_XEN BIT(27)
|
||||
#define SMSTA_JMD BIT(25)
|
||||
#define SMSTA_JAM BIT(24)
|
||||
#define SMSTA_MTO BIT(23)
|
||||
#define SMSTA_MTA BIT(22)
|
||||
#define SMSTA_MTN BIT(21)
|
||||
#define SMSTA_MRNE BIT(19)
|
||||
#define SMSTA_MTE BIT(16)
|
||||
#define SMSTA_TOM BIT(6)
|
||||
|
||||
#define CTL_MRR 0x00000400
|
||||
#define CTL_MTR 0x00000200
|
||||
#define CTL_EN 0x00000800
|
||||
#define CTL_CLK_M 0x000000ff
|
||||
#define CTL_EN BIT(11)
|
||||
#define CTL_MRR BIT(10)
|
||||
#define CTL_MTR BIT(9)
|
||||
#define CTL_UJM BIT(8)
|
||||
#define CTL_CLK_M GENMASK(7, 0)
|
||||
|
||||
static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val)
|
||||
{
|
||||
|
@ -1503,7 +1503,10 @@ static int i2c_pxa_probe(struct platform_device *dev)
|
||||
i2c->adap.name);
|
||||
}
|
||||
|
||||
clk_prepare_enable(i2c->clk);
|
||||
ret = clk_prepare_enable(i2c->clk);
|
||||
if (ret)
|
||||
return dev_err_probe(&dev->dev, ret,
|
||||
"failed to enable clock\n");
|
||||
|
||||
if (i2c->use_pio) {
|
||||
i2c->adap.algo = &i2c_pxa_pio_algorithm;
|
||||
|
@ -148,9 +148,9 @@ struct geni_i2c_clk_fld {
|
||||
* source_clock = 19.2 MHz
|
||||
*/
|
||||
static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = {
|
||||
{KHZ(100), 7, 10, 11, 26},
|
||||
{KHZ(400), 2, 5, 12, 24},
|
||||
{KHZ(1000), 1, 3, 9, 18},
|
||||
{KHZ(100), 7, 10, 12, 26},
|
||||
{KHZ(400), 2, 5, 11, 22},
|
||||
{KHZ(1000), 1, 2, 8, 18},
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interconnect.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
@ -150,6 +151,8 @@
|
||||
/* TAG length for DATA READ in RX FIFO */
|
||||
#define READ_RX_TAGS_LEN 2
|
||||
|
||||
#define QUP_BUS_WIDTH 8
|
||||
|
||||
static unsigned int scl_freq;
|
||||
module_param_named(scl_freq, scl_freq, uint, 0444);
|
||||
MODULE_PARM_DESC(scl_freq, "SCL frequency override");
|
||||
@ -227,6 +230,7 @@ struct qup_i2c_dev {
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
struct clk *pclk;
|
||||
struct icc_path *icc_path;
|
||||
struct i2c_adapter adap;
|
||||
|
||||
int clk_ctl;
|
||||
@ -255,6 +259,10 @@ struct qup_i2c_dev {
|
||||
/* To configure when bus is in run state */
|
||||
u32 config_run;
|
||||
|
||||
/* bandwidth votes */
|
||||
u32 src_clk_freq;
|
||||
u32 cur_bw_clk_freq;
|
||||
|
||||
/* dma parameters */
|
||||
bool is_dma;
|
||||
/* To check if the current transfer is using DMA */
|
||||
@ -453,6 +461,23 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qup_i2c_vote_bw(struct qup_i2c_dev *qup, u32 clk_freq)
|
||||
{
|
||||
u32 needed_peak_bw;
|
||||
int ret;
|
||||
|
||||
if (qup->cur_bw_clk_freq == clk_freq)
|
||||
return 0;
|
||||
|
||||
needed_peak_bw = Bps_to_icc(clk_freq * QUP_BUS_WIDTH);
|
||||
ret = icc_set_bw(qup->icc_path, 0, needed_peak_bw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
qup->cur_bw_clk_freq = clk_freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup)
|
||||
{
|
||||
struct qup_i2c_block *blk = &qup->blk;
|
||||
@ -838,6 +863,10 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
int ret = 0;
|
||||
int idx = 0;
|
||||
|
||||
ret = qup_i2c_vote_bw(qup, qup->src_clk_freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
enable_irq(qup->irq);
|
||||
ret = qup_i2c_req_dma(qup);
|
||||
|
||||
@ -1643,6 +1672,7 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
|
||||
config = readl(qup->base + QUP_CONFIG);
|
||||
config |= QUP_CLOCK_AUTO_GATE;
|
||||
writel(config, qup->base + QUP_CONFIG);
|
||||
qup_i2c_vote_bw(qup, 0);
|
||||
clk_disable_unprepare(qup->pclk);
|
||||
}
|
||||
|
||||
@ -1743,6 +1773,11 @@ static int qup_i2c_probe(struct platform_device *pdev)
|
||||
goto fail_dma;
|
||||
}
|
||||
qup->is_dma = true;
|
||||
|
||||
qup->icc_path = devm_of_icc_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(qup->icc_path))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(qup->icc_path),
|
||||
"failed to get interconnect path\n");
|
||||
}
|
||||
|
||||
nodma:
|
||||
@ -1791,6 +1826,7 @@ nodma:
|
||||
qup_i2c_enable_clocks(qup);
|
||||
src_clk_freq = clk_get_rate(qup->clk);
|
||||
}
|
||||
qup->src_clk_freq = src_clk_freq;
|
||||
|
||||
/*
|
||||
* Bootloaders might leave a pending interrupt on certain QUP's,
|
||||
|
@ -287,20 +287,15 @@ static int rzv2m_i2c_send_address(struct rzv2m_i2c_priv *priv,
|
||||
int ret;
|
||||
|
||||
if (msg->flags & I2C_M_TEN) {
|
||||
/*
|
||||
* 10-bit address
|
||||
* addr_1: 5'b11110 | addr[9:8] | (R/nW)
|
||||
* addr_2: addr[7:0]
|
||||
*/
|
||||
addr = 0xf0 | ((msg->addr & GENMASK(9, 8)) >> 7);
|
||||
addr |= !!(msg->flags & I2C_M_RD);
|
||||
/* Send 1st address(extend code) */
|
||||
/* 10-bit address: Send 1st address(extend code) */
|
||||
addr = i2c_10bit_addr_hi_from_msg(msg);
|
||||
ret = rzv2m_i2c_write_with_ack(priv, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Send 2nd address */
|
||||
ret = rzv2m_i2c_write_with_ack(priv, msg->addr & 0xff);
|
||||
/* 10-bit address: Send 2nd address */
|
||||
addr = i2c_10bit_addr_lo_from_msg(msg);
|
||||
ret = rzv2m_i2c_write_with_ack(priv, addr);
|
||||
} else {
|
||||
/* 7-bit address */
|
||||
addr = i2c_8bit_addr_from_msg(msg);
|
||||
|
@ -157,7 +157,6 @@ const struct of_device_id
|
||||
|
||||
return i2c_of_match_device_sysfs(matches, client);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_of_match_device);
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
|
||||
static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
|
||||
|
@ -84,8 +84,17 @@ static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) {
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
void of_i2c_register_devices(struct i2c_adapter *adap);
|
||||
const struct of_device_id *i2c_of_match_device(const struct of_device_id *matches,
|
||||
struct i2c_client *client);
|
||||
|
||||
#else
|
||||
static inline void of_i2c_register_devices(struct i2c_adapter *adap) { }
|
||||
static inline
|
||||
const struct of_device_id *i2c_of_match_device(const struct of_device_id *matches,
|
||||
struct i2c_client *client)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
extern struct notifier_block i2c_of_notifier;
|
||||
|
||||
|
@ -303,7 +303,7 @@ static void ltc4306_remove(struct i2c_client *client)
|
||||
static struct i2c_driver ltc4306_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4306",
|
||||
.of_match_table = of_match_ptr(ltc4306_of_match),
|
||||
.of_match_table = ltc4306_of_match,
|
||||
},
|
||||
.probe = ltc4306_probe,
|
||||
.remove = ltc4306_remove,
|
||||
|
@ -414,7 +414,7 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
|
||||
|
||||
pending = (ret >> PCA954X_IRQ_OFFSET) & (BIT(data->chip->nchans) - 1);
|
||||
for_each_set_bit(i, &pending, data->chip->nchans)
|
||||
handle_nested_irq(irq_linear_revmap(data->irq, i));
|
||||
handle_nested_irq(irq_find_mapping(data->irq, i));
|
||||
|
||||
return IRQ_RETVAL(pending);
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ static struct platform_driver i2c_mux_reg_driver = {
|
||||
.remove = i2c_mux_reg_remove,
|
||||
.driver = {
|
||||
.name = "i2c-mux-reg",
|
||||
.of_match_table = of_match_ptr(i2c_mux_reg_of_match),
|
||||
.of_match_table = i2c_mux_reg_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -18,8 +18,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -252,7 +250,7 @@ static const struct i2c_device_id at24_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, at24_ids);
|
||||
|
||||
static const struct of_device_id __maybe_unused at24_of_match[] = {
|
||||
static const struct of_device_id at24_of_match[] = {
|
||||
{ .compatible = "atmel,24c00", .data = &at24_data_24c00 },
|
||||
{ .compatible = "atmel,24c01", .data = &at24_data_24c01 },
|
||||
{ .compatible = "atmel,24cs01", .data = &at24_data_24cs01 },
|
||||
@ -286,7 +284,7 @@ static const struct of_device_id __maybe_unused at24_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at24_of_match);
|
||||
|
||||
static const struct acpi_device_id __maybe_unused at24_acpi_ids[] = {
|
||||
static const struct acpi_device_id at24_acpi_ids[] = {
|
||||
{ "INT3499", (kernel_ulong_t)&at24_data_INT3499 },
|
||||
{ "TPF0001", (kernel_ulong_t)&at24_data_24c1024 },
|
||||
{ /* END OF LIST */ }
|
||||
@ -848,8 +846,8 @@ static struct i2c_driver at24_driver = {
|
||||
.driver = {
|
||||
.name = "at24",
|
||||
.pm = &at24_pm_ops,
|
||||
.of_match_table = of_match_ptr(at24_of_match),
|
||||
.acpi_match_table = ACPI_PTR(at24_acpi_ids),
|
||||
.of_match_table = at24_of_match,
|
||||
.acpi_match_table = at24_acpi_ids,
|
||||
},
|
||||
.probe = at24_probe,
|
||||
.remove = at24_remove,
|
||||
|
@ -828,10 +828,9 @@ static void ip5xxx_setup_regs(struct device *dev, struct ip5xxx *ip5xxx,
|
||||
|
||||
static int ip5xxx_power_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct ip5xxx_regfield_config *fields = &ip51xx_fields;
|
||||
const struct ip5xxx_regfield_config *fields;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct device *dev = &client->dev;
|
||||
const struct of_device_id *of_id;
|
||||
struct power_supply *psy;
|
||||
struct ip5xxx *ip5xxx;
|
||||
|
||||
@ -843,9 +842,7 @@ static int ip5xxx_power_probe(struct i2c_client *client)
|
||||
if (IS_ERR(ip5xxx->regmap))
|
||||
return PTR_ERR(ip5xxx->regmap);
|
||||
|
||||
of_id = i2c_of_match_device(dev->driver->of_match_table, client);
|
||||
if (of_id)
|
||||
fields = (const struct ip5xxx_regfield_config *)of_id->data;
|
||||
fields = i2c_get_match_data(client) ?: &ip51xx_fields;
|
||||
ip5xxx_setup_regs(dev, ip5xxx, fields);
|
||||
|
||||
psy_cfg.fwnode = dev_fwnode(dev);
|
||||
|
@ -952,6 +952,21 @@ static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
|
||||
return (msg->addr << 1) | (msg->flags & I2C_M_RD);
|
||||
}
|
||||
|
||||
/*
|
||||
* 10-bit address
|
||||
* addr_1: 5'b11110 | addr[9:8] | (R/nW)
|
||||
* addr_2: addr[7:0]
|
||||
*/
|
||||
static inline u8 i2c_10bit_addr_hi_from_msg(const struct i2c_msg *msg)
|
||||
{
|
||||
return 0xf0 | ((msg->addr & GENMASK(9, 8)) >> 7) | (msg->flags & I2C_M_RD);
|
||||
}
|
||||
|
||||
static inline u8 i2c_10bit_addr_lo_from_msg(const struct i2c_msg *msg)
|
||||
{
|
||||
return msg->addr & GENMASK(7, 0);
|
||||
}
|
||||
|
||||
u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold);
|
||||
void i2c_put_dma_safe_msg_buf(u8 *buf, struct i2c_msg *msg, bool xferred);
|
||||
|
||||
@ -1029,10 +1044,6 @@ static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node
|
||||
return i2c_get_adapter_by_fwnode(of_fwnode_handle(node));
|
||||
}
|
||||
|
||||
const struct of_device_id
|
||||
*i2c_of_match_device(const struct of_device_id *matches,
|
||||
struct i2c_client *client);
|
||||
|
||||
int of_i2c_get_board_info(struct device *dev, struct device_node *node,
|
||||
struct i2c_board_info *info);
|
||||
|
||||
@ -1053,13 +1064,6 @@ static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const struct of_device_id
|
||||
*i2c_of_match_device(const struct of_device_id *matches,
|
||||
struct i2c_client *client)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int of_i2c_get_board_info(struct device *dev,
|
||||
struct device_node *node,
|
||||
struct i2c_board_info *info)
|
||||
|
Loading…
x
Reference in New Issue
Block a user