Skip to content

Commit 71507aa

Browse files
JiakunShuaiAvenger-285714
authored andcommitted
i2c: phytium: Add i2c driver for Phytium I2C adapter
Add a driver for Phytium I2C controller with SMBus alert interrupt support. Signed-off-by: Cheng Quan <[email protected]> Signed-off-by: Feng Jun <[email protected]> Signed-off-by: Chen Baozi <[email protected]> Signed-off-by: Wang Yinfeng <[email protected]> Signed-off-by: Jiakun Shuai <[email protected]>
1 parent 9437fe7 commit 71507aa

File tree

8 files changed

+1955
-0
lines changed

8 files changed

+1955
-0
lines changed

drivers/i2c/busses/Kconfig

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,34 @@ config I2C_PCA_PLATFORM
938938
This driver can also be built as a module. If so, the module
939939
will be called i2c-pca-platform.
940940

941+
config I2C_PHYTIUM_CORE
942+
tristate
943+
944+
config I2C_PHYTIUM_PCI
945+
tristate "Phytium I2C PCI"
946+
depends on PCI && ARCH_PHYTIUM
947+
select I2C_PHYTIUM_CORE
948+
select I2C_SMBUS
949+
help
950+
If you say yes to this option, support will be included for the
951+
Phytium I2C adapter. Only master mode is supported.
952+
953+
This driver can also be built as a module. If so, the module
954+
will be called i2c-phytium-pci.
955+
956+
config I2C_PHYTIUM_PLATFORM
957+
tristate "Phytium I2C Platform"
958+
depends on (ACPI && COMMON_CLK) || !ACPI
959+
select I2C_SLAVE
960+
select I2C_PHYTIUM_CORE
961+
select I2C_SMBUS
962+
help
963+
If you say yes to this option, support will be included for the
964+
Phytium I2C adapter. Only master mode is supported.
965+
966+
This driver can also be built as a module. If so, the module
967+
will be called i2c-phytium-platform.
968+
941969
config I2C_PNX
942970
tristate "I2C bus support for Philips PNX and NXP LPC targets"
943971
depends on ARCH_LPC32XX || COMPILE_TEST

drivers/i2c/busses/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ obj-$(CONFIG_I2C_OWL) += i2c-owl.o
9393
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi-core.o i2c-pasemi-pci.o
9494
obj-$(CONFIG_I2C_APPLE) += i2c-pasemi-core.o i2c-pasemi-platform.o
9595
obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
96+
obj-$(CONFIG_I2C_PHYTIUM_CORE) += i2c-phytium-core.o
97+
i2c-phytium-core-objs := i2c-phytium-common.o i2c-phytium-master.o i2c-phytium-slave.o
98+
obj-$(CONFIG_I2C_PHYTIUM_PCI) += i2c-phytium-pci.o
99+
obj-$(CONFIG_I2C_PHYTIUM_PLATFORM) += i2c-phytium-platform.o
96100
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
97101
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
98102
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Phytium I2C adapter driver.
4+
*
5+
* Derived from Synopysys I2C driver.
6+
* Copyright (C) 2006 Texas Instruments.
7+
* Copyright (C) 2007 MontaVista Software Inc.
8+
* Copyright (C) 2009 Provigent Ltd.
9+
*
10+
* Copyright (C) 2021-2023, Phytium Technology Co., Ltd.
11+
*/
12+
#include <linux/clk.h>
13+
#include <linux/delay.h>
14+
#include <linux/export.h>
15+
#include <linux/errno.h>
16+
#include <linux/err.h>
17+
#include <linux/i2c.h>
18+
#include <linux/interrupt.h>
19+
#include <linux/io.h>
20+
#include <linux/module.h>
21+
#include <linux/pm_runtime.h>
22+
#include <linux/swab.h>
23+
24+
#include "i2c-phytium-core.h"
25+
26+
static char *abort_sources[] = {
27+
[ABRT_7B_ADDR_NOACK] =
28+
"slave address not acknowledged (7bit mode)",
29+
[ABRT_10ADDR1_NOACK] =
30+
"first address byte not acknowledged (10bit mode)",
31+
[ABRT_10ADDR2_NOACK] =
32+
"second address byte not acknowledged (10bit mode)",
33+
[ABRT_TXDATA_NOACK] =
34+
"data not acknowledged",
35+
[ABRT_GCALL_NOACK] =
36+
"no acknowledgment for a general call",
37+
[ABRT_GCALL_READ] =
38+
"read after general call",
39+
[ABRT_SBYTE_ACKDET] =
40+
"start byte acknowledged",
41+
[ABRT_SBYTE_NORSTRT] =
42+
"trying to send start byte when restart is disabled",
43+
[ABRT_10B_RD_NORSTRT] =
44+
"trying to read when restart is disabled (10bit mode)",
45+
[ABRT_MASTER_DIS] =
46+
"trying to use disabled adapter",
47+
[ARB_LOST] =
48+
"lost arbitration",
49+
[ABRT_SLAVE_FLUSH_TXFIFO] =
50+
"read command so flush old data in the TX FIFO",
51+
[ABRT_SLAVE_ARBLOST] =
52+
"slave lost the bus while transmitting data to a remote master",
53+
[ABRT_SLAVE_RD_INTX] =
54+
"incorrect slave-transmitter mode configuration",
55+
};
56+
57+
u32 phytium_readl(struct phytium_i2c_dev *dev, int offset)
58+
{
59+
return readl_relaxed(dev->base + offset);
60+
}
61+
62+
void phytium_writel(struct phytium_i2c_dev *dev, u32 b, int offset)
63+
{
64+
writel_relaxed(b, dev->base + offset);
65+
}
66+
67+
u32 i2c_phytium_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
68+
{
69+
if (cond)
70+
return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
71+
else
72+
return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000 - 3 + offset;
73+
}
74+
75+
u32 i2c_phytium_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
76+
{
77+
return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
78+
}
79+
80+
int i2c_phytium_set_sda_hold(struct phytium_i2c_dev *dev)
81+
{
82+
if (!dev->sda_hold_time) {
83+
/* Keep previous hold time setting if no one set it */
84+
dev->sda_hold_time = phytium_readl(dev, IC_SDA_HOLD);
85+
}
86+
87+
if (!(dev->sda_hold_time & IC_SDA_HOLD_RX_MASK))
88+
dev->sda_hold_time |= 1 << IC_SDA_HOLD_RX_SHIFT;
89+
90+
dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n",
91+
dev->sda_hold_time & ~(u32)IC_SDA_HOLD_RX_MASK,
92+
dev->sda_hold_time >> IC_SDA_HOLD_RX_SHIFT);
93+
94+
return 0;
95+
}
96+
97+
void __i2c_phytium_disable(struct phytium_i2c_dev *dev)
98+
{
99+
int timeout = 100;
100+
101+
do {
102+
__i2c_phytium_disable_nowait(dev);
103+
if ((phytium_readl(dev, IC_ENABLE_STATUS) & 1) == 0)
104+
return;
105+
106+
/*
107+
* Wait 10 times the signaling period of the highest I2C
108+
* transfer supported by the driver (for 400KHz this is
109+
* 25us).
110+
*/
111+
usleep_range(25, 250);
112+
} while (timeout--);
113+
114+
dev_warn(dev->dev, "timeout in disabling adapter\n");
115+
}
116+
117+
unsigned long i2c_phytium_clk_rate(struct phytium_i2c_dev *dev)
118+
{
119+
if (WARN_ON_ONCE(!dev->get_clk_rate_khz))
120+
return 0;
121+
return dev->get_clk_rate_khz(dev);
122+
}
123+
124+
int i2c_phytium_prepare_clk(struct phytium_i2c_dev *dev, bool prepare)
125+
{
126+
if (IS_ERR(dev->clk))
127+
return PTR_ERR(dev->clk);
128+
129+
if (prepare)
130+
return clk_prepare_enable(dev->clk);
131+
132+
clk_disable_unprepare(dev->clk);
133+
return 0;
134+
}
135+
EXPORT_SYMBOL_GPL(i2c_phytium_prepare_clk);
136+
137+
int i2c_phytium_wait_bus_not_busy(struct phytium_i2c_dev *dev)
138+
{
139+
int timeout = 20; /* 20 ms */
140+
141+
while (phytium_readl(dev, IC_STATUS) & IC_STATUS_ACTIVITY) {
142+
if (timeout <= 0) {
143+
dev_warn(dev->dev, "timeout waiting for bus ready\n");
144+
i2c_recover_bus(&dev->adapter);
145+
146+
if (phytium_readl(dev, IC_STATUS) & IC_STATUS_ACTIVITY)
147+
return -ETIMEDOUT;
148+
return 0;
149+
}
150+
timeout--;
151+
usleep_range(1000, 1100);
152+
}
153+
154+
return 0;
155+
}
156+
157+
int i2c_phytium_handle_tx_abort(struct phytium_i2c_dev *dev)
158+
{
159+
unsigned long abort_source = dev->abort_source;
160+
int i;
161+
162+
if (abort_source & IC_TX_ABRT_NOACK) {
163+
for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
164+
dev_dbg(dev->dev,
165+
"%s: %s\n", __func__, abort_sources[i]);
166+
return -EREMOTEIO;
167+
}
168+
169+
for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
170+
dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
171+
172+
if (abort_source & IC_TX_ARB_LOST)
173+
return -EAGAIN;
174+
else if (abort_source & IC_TX_ABRT_GCALL_READ)
175+
return -EINVAL;
176+
else
177+
return -EIO;
178+
179+
return 0;
180+
}
181+
182+
u32 i2c_phytium_func(struct i2c_adapter *adapter)
183+
{
184+
struct phytium_i2c_dev *dev = i2c_get_adapdata(adapter);
185+
186+
return dev->functionality;
187+
}
188+
189+
void i2c_phytium_disable(struct phytium_i2c_dev *dev)
190+
{
191+
/* Disable controller */
192+
__i2c_phytium_disable(dev);
193+
194+
/* Disable all interrupts */
195+
phytium_writel(dev, 0, IC_INTR_MASK);
196+
phytium_readl(dev, IC_CLR_INTR);
197+
}
198+
199+
void i2c_phytium_disable_int(struct phytium_i2c_dev *dev)
200+
{
201+
phytium_writel(dev, 0, IC_INTR_MASK);
202+
}
203+
204+
MODULE_AUTHOR("Cheng Quan <[email protected]>");
205+
MODULE_DESCRIPTION("Phytium I2C bus adapter core");
206+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)