Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: at91: added slave mode support

Slave mode driver is based on the concept of i2c-designware driver.

Signed-off-by: Juergen Fitschen <me@jue.yt>
[ludovic.desroches@microchip.com: rework Kconfig and replace IS_ENABLED
by defined]
Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Juergen Fitschen and committed by
Wolfram Sang
9d3ca54b ad7d142f

+198 -4
+13
drivers/i2c/busses/Kconfig
··· 387 387 the latency to fill the transmission register is too long. If you 388 388 are facing this situation, use the i2c-gpio driver. 389 389 390 + config I2C_AT91_SLAVE_EXPERIMENTAL 391 + tristate "Microchip AT91 I2C experimental slave mode" 392 + depends on I2C_AT91 393 + select I2C_SLAVE 394 + help 395 + If you say yes to this option, support for the slave mode will be 396 + added. Caution: do not use it for production. This feature has not 397 + been tested in a heavy way, help wanted. 398 + There are known bugs: 399 + - It can hang, on a SAMA5D4, after several transfers. 400 + - There are some mismtaches with a SAMA5D4 as slave and a SAMA5D2 as 401 + master. 402 + 390 403 config I2C_AU1550 391 404 tristate "Au1550/Au1200/Au1300 SMBus interface" 392 405 depends on MIPS_ALCHEMY
+3
drivers/i2c/busses/Makefile
··· 36 36 obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o 37 37 obj-$(CONFIG_I2C_AT91) += i2c-at91.o 38 38 i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o 39 + ifeq ($(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL),y) 40 + i2c-at91-objs += i2c-at91-slave.o 41 + endif 39 42 obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o 40 43 obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o 41 44 obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
+10 -3
drivers/i2c/busses/i2c-at91-core.c
··· 56 56 { 57 57 at91_disable_twi_interrupts(dev); 58 58 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST); 59 - 60 - at91_init_twi_bus_master(dev); 59 + if (dev->slave_detected) 60 + at91_init_twi_bus_slave(dev); 61 + else 62 + at91_init_twi_bus_master(dev); 61 63 } 62 64 63 65 static struct at91_twi_pdata at91rm9200_config = { ··· 241 239 dev->adapter.timeout = AT91_I2C_TIMEOUT; 242 240 dev->adapter.dev.of_node = pdev->dev.of_node; 243 241 244 - rc = at91_twi_probe_master(pdev, phy_addr, dev); 242 + dev->slave_detected = i2c_detect_slave_mode(&pdev->dev); 243 + 244 + if (dev->slave_detected) 245 + rc = at91_twi_probe_slave(pdev, phy_addr, dev); 246 + else 247 + rc = at91_twi_probe_master(pdev, phy_addr, dev); 245 248 if (rc) 246 249 return rc; 247 250
+143
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 + }
+29 -1
drivers/i2c/busses/i2c-at91.h
··· 49 49 #define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */ 50 50 #define AT91_TWI_MREAD BIT(12) /* Master Read Direction */ 51 51 52 + #define AT91_TWI_SMR 0x0008 /* Slave Mode Register */ 53 + #define AT91_TWI_SMR_SADR_MAX 0x007f 54 + #define AT91_TWI_SMR_SADR(x) (((x) & AT91_TWI_SMR_SADR_MAX) << 16) 55 + 52 56 #define AT91_TWI_IADR 0x000c /* Internal Address Register */ 53 57 54 58 #define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */ ··· 63 59 #define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */ 64 60 #define AT91_TWI_RXRDY BIT(1) /* Receive Holding Register Ready */ 65 61 #define AT91_TWI_TXRDY BIT(2) /* Transmit Holding Register Ready */ 62 + #define AT91_TWI_SVREAD BIT(3) /* Slave Read */ 63 + #define AT91_TWI_SVACC BIT(4) /* Slave Access */ 66 64 #define AT91_TWI_OVRE BIT(6) /* Overrun Error */ 67 65 #define AT91_TWI_UNRE BIT(7) /* Underrun Error */ 68 66 #define AT91_TWI_NACK BIT(8) /* Not Acknowledged */ 67 + #define AT91_TWI_EOSACC BIT(11) /* End Of Slave Access */ 69 68 #define AT91_TWI_LOCK BIT(23) /* TWI Lock due to Frame Errors */ 70 69 71 70 #define AT91_TWI_INT_MASK \ 72 - (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK) 71 + (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK \ 72 + | AT91_TWI_SVACC | AT91_TWI_EOSACC) 73 73 74 74 #define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */ 75 75 #define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */ ··· 141 133 bool recv_len_abort; 142 134 u32 fifo_size; 143 135 struct at91_twi_dma dma; 136 + bool slave_detected; 137 + #ifdef CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL 138 + unsigned smr; 139 + struct i2c_client *slave; 140 + #endif 144 141 }; 145 142 146 143 unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg); ··· 158 145 void at91_init_twi_bus_master(struct at91_twi_dev *dev); 159 146 int at91_twi_probe_master(struct platform_device *pdev, u32 phy_addr, 160 147 struct at91_twi_dev *dev); 148 + 149 + #ifdef CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL 150 + void at91_init_twi_bus_slave(struct at91_twi_dev *dev); 151 + int at91_twi_probe_slave(struct platform_device *pdev, u32 phy_addr, 152 + struct at91_twi_dev *dev); 153 + 154 + #else 155 + static inline void at91_init_twi_bus_slave(struct at91_twi_dev *dev) {} 156 + static inline int at91_twi_probe_slave(struct platform_device *pdev, 157 + u32 phy_addr, struct at91_twi_dev *dev) 158 + { 159 + return -EINVAL; 160 + } 161 + 162 + #endif