linux/drivers/i2c/busses/i2c-at91-slave.c
<<
>>
Prefs
   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}
 144