Loading drivers/i2c/busses/i2c-emev2.c +111 −1 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ struct em_i2c_device { struct i2c_adapter adap; struct completion msg_done; struct clk *sclk; struct i2c_client *slave; }; static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg) Loading Loading @@ -226,22 +227,131 @@ static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, return num; } static bool em_i2c_slave_irq(struct em_i2c_device *priv) { u8 status, value; enum i2c_slave_event event; int ret; if (!priv->slave) return false; status = readb(priv->base + I2C_OFS_IICSE0); /* Extension code, do not participate */ if (status & I2C_BIT_EXC0) { em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0); return true; } /* Stop detected, we don't know if it's for slave or master */ if (status & I2C_BIT_SPD0) { /* Notify slave device */ i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value); /* Pretend we did not handle the interrupt */ return false; } /* Only handle interrupts addressed to us */ if (!(status & I2C_BIT_COI0)) return false; /* Enable stop interrupts */ em_clear_set_bit(priv, 0, I2C_BIT_SPIE0, I2C_OFS_IICC0); /* Transmission or Reception */ if (status & I2C_BIT_TRC0) { if (status & I2C_BIT_ACKD0) { /* 9 bit interrupt mode */ em_clear_set_bit(priv, 0, I2C_BIT_WTIM0, I2C_OFS_IICC0); /* Send data */ event = status & I2C_BIT_STD0 ? I2C_SLAVE_READ_REQUESTED : I2C_SLAVE_READ_PROCESSED; i2c_slave_event(priv->slave, event, &value); writeb(value, priv->base + I2C_OFS_IIC0); } else { /* NACK, stop transmitting */ em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0); } } else { /* 8 bit interrupt mode */ em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0, I2C_OFS_IICC0); em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0, I2C_OFS_IICC0); if (status & I2C_BIT_STD0) { i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value); } else { /* Recv data */ value = readb(priv->base + I2C_OFS_IIC0); ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value); if (ret < 0) em_clear_set_bit(priv, I2C_BIT_ACKE0, 0, I2C_OFS_IICC0); } } return true; } static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id) { struct em_i2c_device *priv = dev_id; if (em_i2c_slave_irq(priv)) return IRQ_HANDLED; complete(&priv->msg_done); return IRQ_HANDLED; } static u32 em_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE; } static int em_i2c_reg_slave(struct i2c_client *slave) { struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter); if (priv->slave) return -EBUSY; if (slave->flags & I2C_CLIENT_TEN) return -EAFNOSUPPORT; priv->slave = slave; /* Set slave address */ writeb(slave->addr << 1, priv->base + I2C_OFS_SVA0); return 0; } static int em_i2c_unreg_slave(struct i2c_client *slave) { struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter); WARN_ON(!priv->slave); writeb(0, priv->base + I2C_OFS_SVA0); priv->slave = NULL; return 0; } static struct i2c_algorithm em_i2c_algo = { .master_xfer = em_i2c_xfer, .functionality = em_i2c_func, .reg_slave = em_i2c_reg_slave, .unreg_slave = em_i2c_unreg_slave, }; static int em_i2c_probe(struct platform_device *pdev) Loading Loading
drivers/i2c/busses/i2c-emev2.c +111 −1 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ struct em_i2c_device { struct i2c_adapter adap; struct completion msg_done; struct clk *sclk; struct i2c_client *slave; }; static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg) Loading Loading @@ -226,22 +227,131 @@ static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, return num; } static bool em_i2c_slave_irq(struct em_i2c_device *priv) { u8 status, value; enum i2c_slave_event event; int ret; if (!priv->slave) return false; status = readb(priv->base + I2C_OFS_IICSE0); /* Extension code, do not participate */ if (status & I2C_BIT_EXC0) { em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0); return true; } /* Stop detected, we don't know if it's for slave or master */ if (status & I2C_BIT_SPD0) { /* Notify slave device */ i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value); /* Pretend we did not handle the interrupt */ return false; } /* Only handle interrupts addressed to us */ if (!(status & I2C_BIT_COI0)) return false; /* Enable stop interrupts */ em_clear_set_bit(priv, 0, I2C_BIT_SPIE0, I2C_OFS_IICC0); /* Transmission or Reception */ if (status & I2C_BIT_TRC0) { if (status & I2C_BIT_ACKD0) { /* 9 bit interrupt mode */ em_clear_set_bit(priv, 0, I2C_BIT_WTIM0, I2C_OFS_IICC0); /* Send data */ event = status & I2C_BIT_STD0 ? I2C_SLAVE_READ_REQUESTED : I2C_SLAVE_READ_PROCESSED; i2c_slave_event(priv->slave, event, &value); writeb(value, priv->base + I2C_OFS_IIC0); } else { /* NACK, stop transmitting */ em_clear_set_bit(priv, 0, I2C_BIT_LREL0, I2C_OFS_IICC0); } } else { /* 8 bit interrupt mode */ em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0, I2C_OFS_IICC0); em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0, I2C_OFS_IICC0); if (status & I2C_BIT_STD0) { i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value); } else { /* Recv data */ value = readb(priv->base + I2C_OFS_IIC0); ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value); if (ret < 0) em_clear_set_bit(priv, I2C_BIT_ACKE0, 0, I2C_OFS_IICC0); } } return true; } static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id) { struct em_i2c_device *priv = dev_id; if (em_i2c_slave_irq(priv)) return IRQ_HANDLED; complete(&priv->msg_done); return IRQ_HANDLED; } static u32 em_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE; } static int em_i2c_reg_slave(struct i2c_client *slave) { struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter); if (priv->slave) return -EBUSY; if (slave->flags & I2C_CLIENT_TEN) return -EAFNOSUPPORT; priv->slave = slave; /* Set slave address */ writeb(slave->addr << 1, priv->base + I2C_OFS_SVA0); return 0; } static int em_i2c_unreg_slave(struct i2c_client *slave) { struct em_i2c_device *priv = i2c_get_adapdata(slave->adapter); WARN_ON(!priv->slave); writeb(0, priv->base + I2C_OFS_SVA0); priv->slave = NULL; return 0; } static struct i2c_algorithm em_i2c_algo = { .master_xfer = em_i2c_xfer, .functionality = em_i2c_func, .reg_slave = em_i2c_reg_slave, .unreg_slave = em_i2c_unreg_slave, }; static int em_i2c_probe(struct platform_device *pdev) Loading