root/drivers/i2c/busses/i2c-designware-slave.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. i2c_dw_configure_fifo_slave
  2. i2c_dw_init_slave
  3. i2c_dw_reg_slave
  4. i2c_dw_unreg_slave
  5. i2c_dw_read_clear_intrbits_slave
  6. i2c_dw_irq_handler_slave
  7. i2c_dw_isr_slave
  8. i2c_dw_probe_slave

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Synopsys DesignWare I2C adapter driver (slave only).
   4  *
   5  * Based on the Synopsys DesignWare I2C adapter driver (master).
   6  *
   7  * Copyright (C) 2016 Synopsys Inc.
   8  */
   9 #include <linux/delay.h>
  10 #include <linux/err.h>
  11 #include <linux/errno.h>
  12 #include <linux/i2c.h>
  13 #include <linux/interrupt.h>
  14 #include <linux/io.h>
  15 #include <linux/module.h>
  16 #include <linux/pm_runtime.h>
  17 
  18 #include "i2c-designware-core.h"
  19 
  20 static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
  21 {
  22         /* Configure Tx/Rx FIFO threshold levels. */
  23         dw_writel(dev, 0, DW_IC_TX_TL);
  24         dw_writel(dev, 0, DW_IC_RX_TL);
  25 
  26         /* Configure the I2C slave. */
  27         dw_writel(dev, dev->slave_cfg, DW_IC_CON);
  28         dw_writel(dev, DW_IC_INTR_SLAVE_MASK, DW_IC_INTR_MASK);
  29 }
  30 
  31 /**
  32  * i2c_dw_init_slave() - Initialize the designware i2c slave hardware
  33  * @dev: device private data
  34  *
  35  * This function configures and enables the I2C in slave mode.
  36  * This function is called during I2C init function, and in case of timeout at
  37  * run time.
  38  */
  39 static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
  40 {
  41         int ret;
  42 
  43         ret = i2c_dw_acquire_lock(dev);
  44         if (ret)
  45                 return ret;
  46 
  47         /* Disable the adapter. */
  48         __i2c_dw_disable(dev);
  49 
  50         /* Write SDA hold time if supported */
  51         if (dev->sda_hold_time)
  52                 dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
  53 
  54         i2c_dw_configure_fifo_slave(dev);
  55         i2c_dw_release_lock(dev);
  56 
  57         return 0;
  58 }
  59 
  60 static int i2c_dw_reg_slave(struct i2c_client *slave)
  61 {
  62         struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
  63 
  64         if (dev->slave)
  65                 return -EBUSY;
  66         if (slave->flags & I2C_CLIENT_TEN)
  67                 return -EAFNOSUPPORT;
  68         pm_runtime_get_sync(dev->dev);
  69 
  70         /*
  71          * Set slave address in the IC_SAR register,
  72          * the address to which the DW_apb_i2c responds.
  73          */
  74         __i2c_dw_disable_nowait(dev);
  75         dw_writel(dev, slave->addr, DW_IC_SAR);
  76         dev->slave = slave;
  77 
  78         __i2c_dw_enable(dev);
  79 
  80         dev->cmd_err = 0;
  81         dev->msg_write_idx = 0;
  82         dev->msg_read_idx = 0;
  83         dev->msg_err = 0;
  84         dev->status = STATUS_IDLE;
  85         dev->abort_source = 0;
  86         dev->rx_outstanding = 0;
  87 
  88         return 0;
  89 }
  90 
  91 static int i2c_dw_unreg_slave(struct i2c_client *slave)
  92 {
  93         struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
  94 
  95         dev->disable_int(dev);
  96         dev->disable(dev);
  97         synchronize_irq(dev->irq);
  98         dev->slave = NULL;
  99         pm_runtime_put(dev->dev);
 100 
 101         return 0;
 102 }
 103 
 104 static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
 105 {
 106         u32 stat;
 107 
 108         /*
 109          * The IC_INTR_STAT register just indicates "enabled" interrupts.
 110          * Ths unmasked raw version of interrupt status bits are available
 111          * in the IC_RAW_INTR_STAT register.
 112          *
 113          * That is,
 114          *   stat = dw_readl(IC_INTR_STAT);
 115          * equals to,
 116          *   stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
 117          *
 118          * The raw version might be useful for debugging purposes.
 119          */
 120         stat = dw_readl(dev, DW_IC_INTR_STAT);
 121 
 122         /*
 123          * Do not use the IC_CLR_INTR register to clear interrupts, or
 124          * you'll miss some interrupts, triggered during the period from
 125          * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
 126          *
 127          * Instead, use the separately-prepared IC_CLR_* registers.
 128          */
 129         if (stat & DW_IC_INTR_TX_ABRT)
 130                 dw_readl(dev, DW_IC_CLR_TX_ABRT);
 131         if (stat & DW_IC_INTR_RX_UNDER)
 132                 dw_readl(dev, DW_IC_CLR_RX_UNDER);
 133         if (stat & DW_IC_INTR_RX_OVER)
 134                 dw_readl(dev, DW_IC_CLR_RX_OVER);
 135         if (stat & DW_IC_INTR_TX_OVER)
 136                 dw_readl(dev, DW_IC_CLR_TX_OVER);
 137         if (stat & DW_IC_INTR_RX_DONE)
 138                 dw_readl(dev, DW_IC_CLR_RX_DONE);
 139         if (stat & DW_IC_INTR_ACTIVITY)
 140                 dw_readl(dev, DW_IC_CLR_ACTIVITY);
 141         if (stat & DW_IC_INTR_STOP_DET)
 142                 dw_readl(dev, DW_IC_CLR_STOP_DET);
 143         if (stat & DW_IC_INTR_START_DET)
 144                 dw_readl(dev, DW_IC_CLR_START_DET);
 145         if (stat & DW_IC_INTR_GEN_CALL)
 146                 dw_readl(dev, DW_IC_CLR_GEN_CALL);
 147 
 148         return stat;
 149 }
 150 
 151 /*
 152  * Interrupt service routine. This gets called whenever an I2C slave interrupt
 153  * occurs.
 154  */
 155 
 156 static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
 157 {
 158         u32 raw_stat, stat, enabled;
 159         u8 val, slave_activity;
 160 
 161         stat = dw_readl(dev, DW_IC_INTR_STAT);
 162         enabled = dw_readl(dev, DW_IC_ENABLE);
 163         raw_stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
 164         slave_activity = ((dw_readl(dev, DW_IC_STATUS) &
 165                 DW_IC_STATUS_SLAVE_ACTIVITY) >> 6);
 166 
 167         if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
 168                 return 0;
 169 
 170         dev_dbg(dev->dev,
 171                 "%#x STATUS SLAVE_ACTIVITY=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n",
 172                 enabled, slave_activity, raw_stat, stat);
 173 
 174         if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
 175                 i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
 176 
 177         if (stat & DW_IC_INTR_RD_REQ) {
 178                 if (slave_activity) {
 179                         if (stat & DW_IC_INTR_RX_FULL) {
 180                                 val = dw_readl(dev, DW_IC_DATA_CMD);
 181 
 182                                 if (!i2c_slave_event(dev->slave,
 183                                                      I2C_SLAVE_WRITE_RECEIVED,
 184                                                      &val)) {
 185                                         dev_vdbg(dev->dev, "Byte %X acked!",
 186                                                  val);
 187                                 }
 188                                 dw_readl(dev, DW_IC_CLR_RD_REQ);
 189                                 stat = i2c_dw_read_clear_intrbits_slave(dev);
 190                         } else {
 191                                 dw_readl(dev, DW_IC_CLR_RD_REQ);
 192                                 dw_readl(dev, DW_IC_CLR_RX_UNDER);
 193                                 stat = i2c_dw_read_clear_intrbits_slave(dev);
 194                         }
 195                         if (!i2c_slave_event(dev->slave,
 196                                              I2C_SLAVE_READ_REQUESTED,
 197                                              &val))
 198                                 dw_writel(dev, val, DW_IC_DATA_CMD);
 199                 }
 200         }
 201 
 202         if (stat & DW_IC_INTR_RX_DONE) {
 203                 if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
 204                                      &val))
 205                         dw_readl(dev, DW_IC_CLR_RX_DONE);
 206 
 207                 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
 208                 stat = i2c_dw_read_clear_intrbits_slave(dev);
 209                 return 1;
 210         }
 211 
 212         if (stat & DW_IC_INTR_RX_FULL) {
 213                 val = dw_readl(dev, DW_IC_DATA_CMD);
 214                 if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
 215                                      &val))
 216                         dev_vdbg(dev->dev, "Byte %X acked!", val);
 217         } else {
 218                 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
 219                 stat = i2c_dw_read_clear_intrbits_slave(dev);
 220         }
 221 
 222         return 1;
 223 }
 224 
 225 static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
 226 {
 227         struct dw_i2c_dev *dev = dev_id;
 228         int ret;
 229 
 230         i2c_dw_read_clear_intrbits_slave(dev);
 231         ret = i2c_dw_irq_handler_slave(dev);
 232         if (ret > 0)
 233                 complete(&dev->cmd_complete);
 234 
 235         return IRQ_RETVAL(ret);
 236 }
 237 
 238 static const struct i2c_algorithm i2c_dw_algo = {
 239         .functionality = i2c_dw_func,
 240         .reg_slave = i2c_dw_reg_slave,
 241         .unreg_slave = i2c_dw_unreg_slave,
 242 };
 243 
 244 int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
 245 {
 246         struct i2c_adapter *adap = &dev->adapter;
 247         int ret;
 248 
 249         init_completion(&dev->cmd_complete);
 250 
 251         dev->init = i2c_dw_init_slave;
 252         dev->disable = i2c_dw_disable;
 253         dev->disable_int = i2c_dw_disable_int;
 254 
 255         ret = i2c_dw_set_reg_access(dev);
 256         if (ret)
 257                 return ret;
 258 
 259         ret = i2c_dw_set_sda_hold(dev);
 260         if (ret)
 261                 return ret;
 262 
 263         ret = dev->init(dev);
 264         if (ret)
 265                 return ret;
 266 
 267         snprintf(adap->name, sizeof(adap->name),
 268                  "Synopsys DesignWare I2C Slave adapter");
 269         adap->retries = 3;
 270         adap->algo = &i2c_dw_algo;
 271         adap->dev.parent = dev->dev;
 272         i2c_set_adapdata(adap, dev);
 273 
 274         ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave,
 275                                IRQF_SHARED, dev_name(dev->dev), dev);
 276         if (ret) {
 277                 dev_err(dev->dev, "failure requesting irq %i: %d\n",
 278                         dev->irq, ret);
 279                 return ret;
 280         }
 281 
 282         ret = i2c_add_numbered_adapter(adap);
 283         if (ret)
 284                 dev_err(dev->dev, "failure adding adapter: %d\n", ret);
 285 
 286         return ret;
 287 }
 288 EXPORT_SYMBOL_GPL(i2c_dw_probe_slave);
 289 
 290 MODULE_AUTHOR("Luis Oliveira <lolivei@synopsys.com>");
 291 MODULE_DESCRIPTION("Synopsys DesignWare I2C bus slave adapter");
 292 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */