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:
Linus Torvalds 2025-04-01 14:21:02 -07:00
commit 28a1b05678
43 changed files with 1112 additions and 461 deletions

View File

@ -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

View File

@ -30,6 +30,7 @@ properties:
- items:
- enum:
- samsung,exynos5433-hsi2c
- samsung,exynos7870-hsi2c
- tesla,fsd-hsi2c
- const: samsung,exynos7-hsi2c
- items:

View File

@ -26,6 +26,7 @@ properties:
- fsl,imx8qm-lpi2c
- fsl,imx8ulp-lpi2c
- fsl,imx93-lpi2c
- fsl,imx94-lpi2c
- fsl,imx95-lpi2c
- const: fsl,imx7ulp-lpi2c

View File

@ -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

View File

@ -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>;

View File

@ -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

View File

@ -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

View 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>;
};
...

View File

@ -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>;
};

View File

@ -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.

View File

@ -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

View File

@ -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,
};

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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 = {

View File

@ -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);
}
/*

View File

@ -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,
};

View File

@ -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);

View File

@ -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)

View File

@ -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) {

View File

@ -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
View 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");

View File

@ -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;
}

View File

@ -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. */

View File

@ -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)) {

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -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");

View File

@ -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)
{

View File

@ -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;

View File

@ -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},
{},
};

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -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);
}

View File

@ -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,
},
};

View File

@ -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,

View File

@ -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);

View File

@ -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)