i2c-at91-slave.c (3571B)
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 15static 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 65static 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 89static 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 107static 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 113static 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 119int 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 136void 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}