1111
1212#include <linux/bitops.h>
1313#include <linux/device.h>
14+ #include <linux/devm-helpers.h>
1415#include <linux/errno.h>
1516#include <linux/gfp_types.h>
1617#include <linux/i2c.h>
3334#define ASF_CLK_EN 17
3435
3536/* ASF address offsets */
37+ #define ASFINDEX (0x07 + piix4_smba)
3638#define ASFLISADDR (0x09 + piix4_smba)
3739#define ASFSTA (0x0A + piix4_smba)
3840#define ASFSLVSTA (0x0D + piix4_smba)
41+ #define ASFDATARWPTR (0x11 + piix4_smba)
42+ #define ASFSETDATARDPTR (0x12 + piix4_smba)
3943#define ASFDATABNKSEL (0x13 + piix4_smba)
4044#define ASFSLVEN (0x15 + piix4_smba)
4145
4246#define ASF_BLOCK_MAX_BYTES 72
47+ #define ASF_ERROR_STATUS GENMASK(3, 1)
4348
4449struct amd_asf_dev {
4550 struct i2c_adapter adap ;
4651 struct i2c_client * target ;
52+ struct delayed_work work_buf ;
4753 struct sb800_mmio_cfg mmio_cfg ;
4854 struct resource * port_addr ;
4955};
5056
57+ static void amd_asf_process_target (struct work_struct * work )
58+ {
59+ struct amd_asf_dev * dev = container_of (work , struct amd_asf_dev , work_buf .work );
60+ unsigned short piix4_smba = dev -> port_addr -> start ;
61+ u8 data [ASF_BLOCK_MAX_BYTES ];
62+ u8 bank , reg , cmd ;
63+ u8 len , idx , val ;
64+
65+ /* Read target status register */
66+ reg = inb_p (ASFSLVSTA );
67+
68+ /* Check if no error bits are set in target status register */
69+ if (reg & ASF_ERROR_STATUS ) {
70+ /* Set bank as full */
71+ cmd = 0 ;
72+ reg |= GENMASK (3 , 2 );
73+ outb_p (reg , ASFDATABNKSEL );
74+ } else {
75+ /* Read data bank */
76+ reg = inb_p (ASFDATABNKSEL );
77+ bank = (reg & BIT (3 )) ? 1 : 0 ;
78+
79+ /* Set read data bank */
80+ if (bank ) {
81+ reg |= BIT (4 );
82+ reg &= ~BIT (3 );
83+ } else {
84+ reg &= ~BIT (4 );
85+ reg &= ~BIT (2 );
86+ }
87+
88+ /* Read command register */
89+ outb_p (reg , ASFDATABNKSEL );
90+ cmd = inb_p (ASFINDEX );
91+ len = inb_p (ASFDATARWPTR );
92+ for (idx = 0 ; idx < len ; idx ++ )
93+ data [idx ] = inb_p (ASFINDEX );
94+
95+ /* Clear data bank status */
96+ if (bank ) {
97+ reg |= BIT (3 );
98+ outb_p (reg , ASFDATABNKSEL );
99+ } else {
100+ reg |= BIT (2 );
101+ outb_p (reg , ASFDATABNKSEL );
102+ }
103+ }
104+
105+ outb_p (0 , ASFSETDATARDPTR );
106+ if (cmd & BIT (0 ))
107+ return ;
108+
109+ /*
110+ * Although i2c_slave_event() returns an appropriate error code, we
111+ * don't check it here because we're operating in the workqueue context.
112+ */
113+ i2c_slave_event (dev -> target , I2C_SLAVE_WRITE_REQUESTED , & val );
114+ for (idx = 0 ; idx < len ; idx ++ ) {
115+ val = data [idx ];
116+ i2c_slave_event (dev -> target , I2C_SLAVE_WRITE_RECEIVED , & val );
117+ }
118+ i2c_slave_event (dev -> target , I2C_SLAVE_STOP , & val );
119+ }
120+
51121static void amd_asf_update_ioport_target (unsigned short piix4_smba , u8 bit ,
52122 unsigned long offset , bool set )
53123{
@@ -207,10 +277,29 @@ static const struct i2c_algorithm amd_asf_smbus_algorithm = {
207277 .functionality = amd_asf_func ,
208278};
209279
280+ static irqreturn_t amd_asf_irq_handler (int irq , void * ptr )
281+ {
282+ struct amd_asf_dev * dev = ptr ;
283+ unsigned short piix4_smba = dev -> port_addr -> start ;
284+ u8 target_int = inb_p (ASFSTA );
285+
286+ if (target_int & BIT (6 )) {
287+ /* Target Interrupt */
288+ outb_p (target_int | BIT (6 ), ASFSTA );
289+ schedule_delayed_work (& dev -> work_buf , HZ );
290+ } else {
291+ /* Controller Interrupt */
292+ amd_asf_update_ioport_target (piix4_smba , ASF_SLV_INTR , SMBHSTSTS , true);
293+ }
294+
295+ return IRQ_HANDLED ;
296+ }
297+
210298static int amd_asf_probe (struct platform_device * pdev )
211299{
212300 struct device * dev = & pdev -> dev ;
213301 struct amd_asf_dev * asf_dev ;
302+ int ret , irq ;
214303
215304 asf_dev = devm_kzalloc (dev , sizeof (* asf_dev ), GFP_KERNEL );
216305 if (!asf_dev )
@@ -221,6 +310,18 @@ static int amd_asf_probe(struct platform_device *pdev)
221310 if (!asf_dev -> port_addr )
222311 return dev_err_probe (dev , - EINVAL , "missing IO resources\n" );
223312
313+ ret = devm_delayed_work_autocancel (dev , & asf_dev -> work_buf , amd_asf_process_target );
314+ if (ret )
315+ return dev_err_probe (dev , ret , "failed to create work queue\n" );
316+
317+ irq = platform_get_irq (pdev , 0 );
318+ if (irq < 0 )
319+ return dev_err_probe (dev , irq , "missing IRQ resources\n" );
320+
321+ ret = devm_request_irq (dev , irq , amd_asf_irq_handler , IRQF_SHARED , "amd_asf" , asf_dev );
322+ if (ret )
323+ return dev_err_probe (dev , ret , "Unable to request irq: %d for use\n" , irq );
324+
224325 asf_dev -> adap .owner = THIS_MODULE ;
225326 asf_dev -> adap .algo = & amd_asf_smbus_algorithm ;
226327 asf_dev -> adap .dev .parent = dev ;
0 commit comments