Skip to content

Commit 78a78b3

Browse files
Shyam Sundar S KAndi Shyti
authored andcommitted
i2c: amd-asf: Add i2c_algorithm operations to support AMD ASF with SMBus
Implement the i2c_algorithm operations to enable support for AMD ASF (Alert Standard Format) with SMBus. This enhancement includes: - Adding functionality to identify and select the supported ASF functions. - Implementing mechanisms for registering and deregistering I2C slave devices. - Providing support for data transfer operations over ASF. Additionally, include a 'select' Kconfig entry as the current patch utilizes .reg_slave() and .unreg_slave() callbacks, which are controlled by CONFIG_I2C_SLAVE. Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
1 parent c509ebd commit 78a78b3

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

drivers/i2c/busses/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ config I2C_AMD_MP2
9898
config I2C_AMD_ASF
9999
tristate "AMD ASF I2C Controller Support"
100100
depends on I2C_PIIX4
101+
select I2C_SLAVE
101102
help
102103
This option enables support for the AMD ASF (Alert Standard Format)
103104
I2C controller. The AMD ASF controller is an SMBus controller with

drivers/i2c/busses/i2c-amd-asf-plat.c

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* Sanket Goswami <Sanket.Goswami@amd.com>
1010
*/
1111

12+
#include <linux/bitops.h>
1213
#include <linux/device.h>
1314
#include <linux/errno.h>
1415
#include <linux/gfp_types.h>
@@ -22,12 +23,190 @@
2223

2324
#include "i2c-piix4.h"
2425

26+
/* ASF register bits */
27+
#define ASF_SLV_LISTN 0
28+
#define ASF_SLV_INTR 1
29+
#define ASF_SLV_RST 4
30+
#define ASF_PEC_SP 5
31+
#define ASF_DATA_EN 7
32+
#define ASF_MSTR_EN 16
33+
#define ASF_CLK_EN 17
34+
35+
/* ASF address offsets */
36+
#define ASFLISADDR (0x09 + piix4_smba)
37+
#define ASFSTA (0x0A + piix4_smba)
38+
#define ASFSLVSTA (0x0D + piix4_smba)
39+
#define ASFDATABNKSEL (0x13 + piix4_smba)
40+
#define ASFSLVEN (0x15 + piix4_smba)
41+
42+
#define ASF_BLOCK_MAX_BYTES 72
43+
2544
struct amd_asf_dev {
2645
struct i2c_adapter adap;
46+
struct i2c_client *target;
2747
struct sb800_mmio_cfg mmio_cfg;
2848
struct resource *port_addr;
2949
};
3050

51+
static void amd_asf_update_ioport_target(unsigned short piix4_smba, u8 bit,
52+
unsigned long offset, bool set)
53+
{
54+
unsigned long reg;
55+
56+
reg = inb_p(offset);
57+
__assign_bit(bit, &reg, set);
58+
outb_p(reg, offset);
59+
}
60+
61+
static void amd_asf_update_mmio_target(struct amd_asf_dev *dev, u8 bit, bool set)
62+
{
63+
unsigned long reg;
64+
65+
reg = ioread32(dev->mmio_cfg.addr);
66+
__assign_bit(bit, &reg, set);
67+
iowrite32(reg, dev->mmio_cfg.addr);
68+
}
69+
70+
static void amd_asf_setup_target(struct amd_asf_dev *dev)
71+
{
72+
unsigned short piix4_smba = dev->port_addr->start;
73+
74+
/* Reset both host and target before setting up */
75+
outb_p(0, SMBHSTSTS);
76+
outb_p(0, ASFSLVSTA);
77+
outb_p(0, ASFSTA);
78+
79+
/* Update target address */
80+
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, true);
81+
/* Enable target and set the clock */
82+
amd_asf_update_mmio_target(dev, ASF_MSTR_EN, false);
83+
amd_asf_update_mmio_target(dev, ASF_CLK_EN, true);
84+
/* Enable target interrupt */
85+
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, true);
86+
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, false);
87+
/* Enable PEC and PEC append */
88+
amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true);
89+
amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true);
90+
}
91+
92+
static int amd_asf_access(struct i2c_adapter *adap, u16 addr, u8 command, u8 *data)
93+
{
94+
struct amd_asf_dev *dev = i2c_get_adapdata(adap);
95+
unsigned short piix4_smba = dev->port_addr->start;
96+
u8 i, len;
97+
98+
outb_p((addr << 1), SMBHSTADD);
99+
outb_p(command, SMBHSTCMD);
100+
len = data[0];
101+
if (len == 0 || len > ASF_BLOCK_MAX_BYTES)
102+
return -EINVAL;
103+
104+
outb_p(len, SMBHSTDAT0);
105+
/* Reset SMBBLKDAT */
106+
inb_p(SMBHSTCNT);
107+
for (i = 1; i <= len; i++)
108+
outb_p(data[i], SMBBLKDAT);
109+
110+
outb_p(PIIX4_BLOCK_DATA, SMBHSTCNT);
111+
/* Enable PEC and PEC append */
112+
amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true);
113+
amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true);
114+
115+
return piix4_transaction(adap, piix4_smba);
116+
}
117+
118+
static int amd_asf_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
119+
{
120+
struct amd_asf_dev *dev = i2c_get_adapdata(adap);
121+
unsigned short piix4_smba = dev->port_addr->start;
122+
u8 asf_data[ASF_BLOCK_MAX_BYTES];
123+
struct i2c_msg *dev_msgs = msgs;
124+
u8 prev_port;
125+
int ret;
126+
127+
if (msgs->flags & I2C_M_RD) {
128+
dev_err(&adap->dev, "ASF: Read not supported\n");
129+
return -EOPNOTSUPP;
130+
}
131+
132+
/* Exclude the receive header and PEC */
133+
if (msgs->len > ASF_BLOCK_MAX_BYTES - 3) {
134+
dev_warn(&adap->dev, "ASF: max message length exceeded\n");
135+
return -EOPNOTSUPP;
136+
}
137+
138+
asf_data[0] = dev_msgs->len;
139+
memcpy(asf_data + 1, dev_msgs[0].buf, dev_msgs->len);
140+
141+
ret = piix4_sb800_region_request(&adap->dev, &dev->mmio_cfg);
142+
if (ret)
143+
return ret;
144+
145+
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true);
146+
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, false);
147+
/* Clear ASF target status */
148+
outb_p(0, ASFSLVSTA);
149+
150+
/* Enable ASF SMBus controller function */
151+
amd_asf_update_mmio_target(dev, ASF_MSTR_EN, true);
152+
prev_port = piix4_sb800_port_sel(0, &dev->mmio_cfg);
153+
ret = amd_asf_access(adap, msgs->addr, msgs[0].buf[0], asf_data);
154+
piix4_sb800_port_sel(prev_port, &dev->mmio_cfg);
155+
amd_asf_setup_target(dev);
156+
piix4_sb800_region_release(&adap->dev, &dev->mmio_cfg);
157+
return ret;
158+
}
159+
160+
static int amd_asf_reg_target(struct i2c_client *target)
161+
{
162+
struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter);
163+
unsigned short piix4_smba = dev->port_addr->start;
164+
int ret;
165+
u8 reg;
166+
167+
if (dev->target)
168+
return -EBUSY;
169+
170+
ret = piix4_sb800_region_request(&target->dev, &dev->mmio_cfg);
171+
if (ret)
172+
return ret;
173+
174+
reg = (target->addr << 1) | I2C_M_RD;
175+
outb_p(reg, ASFLISADDR);
176+
177+
amd_asf_setup_target(dev);
178+
dev->target = target;
179+
amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, ASFDATABNKSEL, false);
180+
piix4_sb800_region_release(&target->dev, &dev->mmio_cfg);
181+
182+
return 0;
183+
}
184+
185+
static int amd_asf_unreg_target(struct i2c_client *target)
186+
{
187+
struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter);
188+
unsigned short piix4_smba = dev->port_addr->start;
189+
190+
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, false);
191+
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true);
192+
dev->target = NULL;
193+
194+
return 0;
195+
}
196+
197+
static u32 amd_asf_func(struct i2c_adapter *adapter)
198+
{
199+
return I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
200+
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_PEC | I2C_FUNC_SLAVE;
201+
}
202+
203+
static const struct i2c_algorithm amd_asf_smbus_algorithm = {
204+
.master_xfer = amd_asf_xfer,
205+
.reg_slave = amd_asf_reg_target,
206+
.unreg_slave = amd_asf_unreg_target,
207+
.functionality = amd_asf_func,
208+
};
209+
31210
static int amd_asf_probe(struct platform_device *pdev)
32211
{
33212
struct device *dev = &pdev->dev;
@@ -43,6 +222,7 @@ static int amd_asf_probe(struct platform_device *pdev)
43222
return dev_err_probe(dev, -EINVAL, "missing IO resources\n");
44223

45224
asf_dev->adap.owner = THIS_MODULE;
225+
asf_dev->adap.algo = &amd_asf_smbus_algorithm;
46226
asf_dev->adap.dev.parent = dev;
47227

48228
i2c_set_adapdata(&asf_dev->adap, asf_dev);
@@ -66,5 +246,6 @@ static struct platform_driver amd_asf_driver = {
66246
};
67247
module_platform_driver(amd_asf_driver);
68248

249+
MODULE_IMPORT_NS(PIIX4_SMBUS);
69250
MODULE_LICENSE("GPL");
70251
MODULE_DESCRIPTION("AMD Alert Standard Format Driver");

0 commit comments

Comments
 (0)