143 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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;110}111 112static const struct i2c_algorithm at91_twi_algorithm_slave = {113 .reg_slave = at91_reg_slave,114 .unreg_slave = at91_unreg_slave,115 .functionality = at91_twi_func,116};117 118int at91_twi_probe_slave(struct platform_device *pdev,119 u32 phy_addr, struct at91_twi_dev *dev)120{121 int rc;122 123 rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt_slave,124 0, dev_name(dev->dev), dev);125 if (rc) {126 dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);127 return rc;128 }129 130 dev->adapter.algo = &at91_twi_algorithm_slave;131 132 return 0;133}134 135void at91_init_twi_bus_slave(struct at91_twi_dev *dev)136{137 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSDIS);138 if (dev->slave_detected && dev->smr) {139 at91_twi_write(dev, AT91_TWI_SMR, dev->smr);140 at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVEN);141 }142}143