Linux-libre 5.7.6-gnu
[librecmc/linux-libre.git] / drivers / i2c / busses / i2c-at91-slave.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  i2c slave support for Atmel's AT91 Two-Wire Interface (TWI)
4  *
5  *  Copyright (C) 2017 Juergen Fitschen <me@jue.yt>
6  */
7
8 #include <linux/err.h>
9 #include <linux/i2c.h>
10 #include <linux/interrupt.h>
11 #include <linux/pm_runtime.h>
12
13 #include "i2c-at91.h"
14
15 static irqreturn_t atmel_twi_interrupt_slave(int irq, void *dev_id)
16 {
17         struct at91_twi_dev *dev = dev_id;
18         const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
19         const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
20         u8 value;
21
22         if (!irqstatus)
23                 return IRQ_NONE;
24
25         /* slave address has been detected on I2C bus */
26         if (irqstatus & AT91_TWI_SVACC) {
27                 if (status & AT91_TWI_SVREAD) {
28                         i2c_slave_event(dev->slave,
29                                         I2C_SLAVE_READ_REQUESTED, &value);
30                         writeb_relaxed(value, dev->base + AT91_TWI_THR);
31                         at91_twi_write(dev, AT91_TWI_IER,
32                                        AT91_TWI_TXRDY | AT91_TWI_EOSACC);
33                 } else {
34                         i2c_slave_event(dev->slave,
35                                         I2C_SLAVE_WRITE_REQUESTED, &value);
36                         at91_twi_write(dev, AT91_TWI_IER,
37                                        AT91_TWI_RXRDY | AT91_TWI_EOSACC);
38                 }
39                 at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_SVACC);
40         }
41
42         /* byte transmitted to remote master */
43         if (irqstatus & AT91_TWI_TXRDY) {
44                 i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, &value);
45                 writeb_relaxed(value, dev->base + AT91_TWI_THR);
46         }
47
48         /* byte received from remote master */
49         if (irqstatus & AT91_TWI_RXRDY) {
50                 value = readb_relaxed(dev->base + AT91_TWI_RHR);
51                 i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
52         }
53
54         /* master sent stop */
55         if (irqstatus & AT91_TWI_EOSACC) {
56                 at91_twi_write(dev, AT91_TWI_IDR,
57                                AT91_TWI_TXRDY | AT91_TWI_RXRDY | AT91_TWI_EOSACC);
58                 at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_SVACC);
59                 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &value);
60         }
61
62         return IRQ_HANDLED;
63 }
64
65 static int at91_reg_slave(struct i2c_client *slave)
66 {
67         struct at91_twi_dev *dev = i2c_get_adapdata(slave->adapter);
68
69         if (dev->slave)
70                 return -EBUSY;
71
72         if (slave->flags & I2C_CLIENT_TEN)
73                 return -EAFNOSUPPORT;
74
75         /* Make sure twi_clk doesn't get turned off! */
76         pm_runtime_get_sync(dev->dev);
77
78         dev->slave = slave;
79         dev->smr = AT91_TWI_SMR_SADR(slave->addr);
80
81         at91_init_twi_bus(dev);
82         at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_SVACC);
83
84         dev_info(dev->dev, "entered slave mode (ADR=%d)\n", slave->addr);
85
86         return 0;
87 }
88
89 static int at91_unreg_slave(struct i2c_client *slave)
90 {
91         struct at91_twi_dev *dev = i2c_get_adapdata(slave->adapter);
92
93         WARN_ON(!dev->slave);
94
95         dev_info(dev->dev, "leaving slave mode\n");
96
97         dev->slave = NULL;
98         dev->smr = 0;
99
100         at91_init_twi_bus(dev);
101
102         pm_runtime_put(dev->dev);
103
104         return 0;
105 }
106
107 static u32 at91_twi_func(struct i2c_adapter *adapter)
108 {
109         return I2C_FUNC_SLAVE | I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
110                 | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
111 }
112
113 static const struct i2c_algorithm at91_twi_algorithm_slave = {
114         .reg_slave      = at91_reg_slave,
115         .unreg_slave    = at91_unreg_slave,
116         .functionality  = at91_twi_func,
117 };
118
119 int at91_twi_probe_slave(struct platform_device *pdev,
120                          u32 phy_addr, struct at91_twi_dev *dev)
121 {
122         int rc;
123
124         rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt_slave,
125                               0, dev_name(dev->dev), dev);
126         if (rc) {
127                 dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
128                 return rc;
129         }
130
131         dev->adapter.algo = &at91_twi_algorithm_slave;
132
133         return 0;
134 }
135
136 void at91_init_twi_bus_slave(struct at91_twi_dev *dev)
137 {
138         at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSDIS);
139         if (dev->slave_detected && dev->smr) {
140                 at91_twi_write(dev, AT91_TWI_SMR, dev->smr);
141                 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVEN);
142         }
143 }