Thread (1 message) 1 message, 1 author, 2013-02-11

Re: [PATCH V3] i2c: add bcm2835 driver

From: Wolfram Sang <hidden>
Date: 2013-02-11 22:52:08
Also in: linux-arm-kernel, linux-i2c

Hi Stephen,

On Fri, Feb 08, 2013 at 08:52:58PM -0700, Stephen Warren wrote:
This implements a very basic I2C host driver for the BCM2835 SoC. Missing
features so far are:

* 10-bit addressing.
* DMA.

Reviewed-by: Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org>
Signed-off-by: Stephen Warren <redacted>
---
...
+struct bcm2835_i2c_dev {
+	struct device *dev;
+	void __iomem *regs;
+	struct clk *clk;
+	struct i2c_adapter adapter;
+	struct completion completion;
+	u32 msg_err;
+	u8 *msg_buf;
+	size_t msg_buf_remaining;
+};
+
+static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev,
+				      u32 reg, u32 val)
+{
+	writel(val, i2c_dev->regs + reg);
+}
+
+static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
+{
+	return readl(i2c_dev->regs + reg);
+}
Hmm, not sure if those functions add readability, but no need to change.
+
+static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev)
+{
+	u32 val;
+
+	for (;;) {
+		if (!i2c_dev->msg_buf_remaining)
+			return;
+		val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+		if (!(val & BCM2835_I2C_S_TXD))
+			break;
+		bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_FIFO,
+				   *i2c_dev->msg_buf);
+		i2c_dev->msg_buf++;
+		i2c_dev->msg_buf_remaining--;
+	}
while (i2c_dev->msg_buf_remaining) ...

?
+}
+
+static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev)
+{
+	u32 val;
+
+	for (;;) {
+		if (!i2c_dev->msg_buf_remaining)
+			return;
+		val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+		if (!(val & BCM2835_I2C_S_RXD))
+			break;
+		*i2c_dev->msg_buf = bcm2835_i2c_readl(i2c_dev,
+						      BCM2835_I2C_FIFO);
+		i2c_dev->msg_buf++;
+		i2c_dev->msg_buf_remaining--;
+	}
ditto?

...
+	ret = wait_for_completion_timeout(&i2c_dev->completion,
+					  BCM2835_I2C_TIMEOUT);
+	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
+	if (WARN_ON(ret == 0)) {
+		dev_err(i2c_dev->dev, "i2c transfer timed out\n");
+		return -ETIMEDOUT;
+	}
I'd suggest to skip the WARN_ON. Timeout is the expected case when you
want to read from an EEPROM which is just in the process of
erasing/writing data from the previous command.

...
+	adap = &i2c_dev->adapter;
+	i2c_set_adapdata(adap, i2c_dev);
+	adap->owner = THIS_MODULE;
+	adap->class = I2C_CLASS_HWMON;
Do you really need the class?
+	strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name));
+	adap->algo = &bcm2835_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->nr = -1;
If you are using '-1' anyhow, you could skip setting it and simply call
i2c_add_adapter(). Or you can init it here to pdev->id. Whatever you
prefer.
+
+	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0);
+
+	return i2c_add_numbered_adapter(adap);
+}
+
+static int bcm2835_i2c_remove(struct platform_device *pdev)
+{
+	struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&i2c_dev->adapter);
Is it guaranteed that interrupts cannot occur anymore? Otherwise OOPS
might happen, since the adapter is cleared here already but devm will
remove the interrupt only a little later.

Thanks,

   Wolfram
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help