static int xlp9xx_i2c_probe(struct platform_device *pdev) { struct xlp9xx_i2c_dev *priv; struct resource *res; int err = 0; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); priv->irq = platform_get_irq(pdev, 0); if (priv->irq <= 0) { dev_err(&pdev->dev, "invalid irq!\n"); return priv->irq; } xlp9xx_i2c_get_frequency(pdev, priv); xlp9xx_i2c_init(priv); err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, pdev->name, priv); if (err) { dev_err(&pdev->dev, "IRQ request failed!\n"); return err; } init_completion(&priv->msg_complete); priv->adapter.dev.parent = &pdev->dev; priv->adapter.algo = &xlp9xx_i2c_algo; priv->adapter.dev.of_node = pdev->dev.of_node; priv->dev = &pdev->dev; snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c"); i2c_set_adapdata(&priv->adapter, priv); err = i2c_add_adapter(&priv->adapter); if (err) { dev_err(&pdev->dev, "failed to add I2C adapter!\n"); return err; } platform_set_drvdata(pdev, priv); dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); return 0; }
static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg, int last_msg) { unsigned long timeleft; u32 intr_mask, cmd, val; priv->msg_buf = msg->buf; priv->msg_buf_remaining = priv->msg_len = msg->len; priv->msg_err = 0; priv->msg_read = (msg->flags & I2C_M_RD); reinit_completion(&priv->msg_complete); /* Reset FIFO */ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL, XLP9XX_I2C_MFIFOCTRL_RST); /* set FIFO threshold if reading */ if (priv->msg_read) xlp9xx_i2c_update_rx_fifo_thres(priv); /* set slave addr */ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR, (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) | (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0)); /* Build control word for transfer */ val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); if (!priv->msg_read) val &= ~XLP9XX_I2C_CTRL_FIFORD; else val |= XLP9XX_I2C_CTRL_FIFORD; /* read */ if (msg->flags & I2C_M_TEN) val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/ else val &= ~XLP9XX_I2C_CTRL_ADDMODE; /* set data length to be transferred */ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) | (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val); /* fill fifo during tx */ if (!priv->msg_read) xlp9xx_i2c_fill_tx_fifo(priv); /* set interrupt mask */ intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR | XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE); if (priv->msg_read) { intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI; if (msg->len == 0) intr_mask |= XLP9XX_I2C_INTEN_SADDR; } else { if (msg->len == 0) intr_mask |= XLP9XX_I2C_INTEN_SADDR; else intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY; } xlp9xx_i2c_unmask_irq(priv, intr_mask); /* set cmd reg */ cmd = XLP9XX_I2C_CMD_START; cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE); if (last_msg) cmd |= XLP9XX_I2C_CMD_STOP; xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd); timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS); timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft); if (priv->msg_err) { dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err); if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR) xlp9xx_i2c_init(priv); return -EIO; } if (timeleft == 0) { dev_dbg(priv->dev, "i2c transfer timed out!\n"); xlp9xx_i2c_init(priv); return -ETIMEDOUT; } return 0; }