[i2c] [PATCH 8/12] drivers: PMC MSP71xx TWI driver

Jean Delvare khali at linux-fr.org
Fri Jun 29 20:46:26 CEST 2007


Hi Marc,

On Thu, 28 Jun 2007 18:01:11 -0600, Marc St-Jean wrote:
> [PATCH 8/12] drivers: PMC MSP71xx TWI driver
> 
> Patch to add TWI driver for the PMC-Sierra MSP71xx devices.
> 
> Thanks,
> Marc
> 
> Signed-off-by: Marc St-Jean <Marc_St-Jean at pmc-sierra.com>
> ---
> Changes since last post:
> - Changed config item to no longer depend on I2C and updated help text.
> - Converted to platform device driver and rewrote probe/remove functions.
> - Changed xfer_command to fix up be64 handling in .
> - Changed master_xfer function to eliminate support for multiple commands
> other that simple write-read. Fixed probing workaround to not perform a read.
> - Updated IRQ flags.
> - Returned more meaningful error codes.
> - Removed unnecessary headers and definitions.
> - Removed get_clock_config function as not currently used.
> - Removed algo_data function pointers and made direct calls.
> - Removed extra casts and backets.
> - Removed redundant debugging output.
> - Other cleanups as requested by feedback.
> 
>  Kconfig      |    6 
>  Makefile     |    1 
>  i2c-pmcmsp.c |  674 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 681 insertions(+)

It's getting in shape... Some more comments:

> diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
> new file mode 100644
> index 0000000..68018df
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-pmcmsp.c
> (...)
> +/* IO Operation macros */
> +#define pmcmsptwi_readl		__raw_readl
> +#define pmcmsptwi_writel	__raw_writel

Where are these defined?

> +
> +/* TWI command type */
> +enum pmcmsptwi_cmd_type {
> +	MSP_TWI_CMD_WRITE	= 0,	/* Write only */
> +	MSP_TWI_CMD_READ	= 1,	/* Read only */
> +	MSP_TWI_CMD_WRITE_READ	= 2	/* Write then Read */
> +};

Add a comma after the last item (makes it easier if you ever need to
add values.)

> +/*
> + * Probe for and register the device and return 0 if there is one.
> + */
> +static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
> +{
> +	struct resource *res;
> +	int rc = -ENODEV;
> +
> +	/* get the static platform resources */
> +	res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		printk(KERN_ERR "IOMEM resource not found\n");

Please use dev_err(). Same below.

> +		goto ret_err;
> +	}
> +
> +	/* reserve the memory region */
> +	if (!request_mem_region(res->start, res->end - res->start + 1,
> +				pldev->name)) {
> +		printk(KERN_ERR "Unable to get memory/io address "
> +			"region 0x%08x\n", res->start);
> +		rc = -EBUSY;
> +		goto ret_err;
> +	}
> +
> +	/* remap the memory */
> +	pmcmsptwi_data.iobase = ioremap_nocache(res->start,
> +						res->end - res->start + 1);
> +	if (!pmcmsptwi_data.iobase) {
> +		printk(KERN_WARNING "Unable to ioremap address 0x%08x\n",
> +			res->start);
> +		rc = -EIO;
> +		goto ret_unreserve;
> +	}
> +
> +	/* request the irq */
> +	pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
> +	if (pmcmsptwi_data.irq) {
> +		rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
> +			IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
> +			pldev->name, &pmcmsptwi_data);
> +		if (rc == 0) {
> +			/*
> +			 * Enable 'DONE' interrupt only.
> +			 *
> +			 * If you enable all interrupts, you will get one on
> +			 * error and another when the operation completes.
> +			 * This way you only have to handle one interrupt,
> +			 * but you can still check all result flags.
> +			 */
> +			pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
> +					pmcmsptwi_data.iobase +
> +					MSP_TWI_INT_MSK_REG_OFFSET);
> +		} else {
> +			printk(KERN_WARNING
> +				"Could not assign TWI IRQ handler "
> +				"to irq %d (continuing with poll)\n",
> +				pmcmsptwi_data.irq);
> +			pmcmsptwi_data.irq = 0;
> +		}
> +	}
> +
> +	init_completion(&pmcmsptwi_data.wait);
> +	mutex_init(&pmcmsptwi_data.lock);
> +
> +	pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
> +	pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
> +
> +	printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
> +
> +	pmcmsptwi_adapter.dev.parent = &pldev->dev;
> +	platform_set_drvdata(pldev, &pmcmsptwi_adapter);

This assumes that you have a single I2C bus, but your driver doesn't
actually check this. Ideally this memory should be dynamically
allocated.

> +
> +	rc = i2c_add_adapter(&pmcmsptwi_adapter);
> +	if (rc) {
> +		printk(KERN_ERR "Unable to register I2C adapter\n");
> +		goto ret_unmap;
> +	}
> +
> +	return 0;
> +
> +ret_unmap:
> +	platform_set_drvdata(pldev, NULL);
> +	if (pmcmsptwi_data.irq) {
> +		pmcmsptwi_writel(0,
> +			pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
> +		free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
> +	}
> +
> +	iounmap(pmcmsptwi_data.iobase);
> +
> +ret_unreserve:
> +	release_mem_region(res->start, res->end - res->start + 1);
> +
> +ret_err:
> +	return rc;
> +}

> +/*
> + * Polls the 'busy' register until the command is complete.
> + * NOTE: Assumes data->lock is held.
> + */
> +static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
> +{
> +	int i;
> +	u32 val = 0;

Initialization isn't needed.

> +
> +	for (i = 0; i < MSP_MAX_POLL; i++) {
> +		val = pmcmsptwi_readl(data->iobase + MSP_TWI_BUSY_REG_OFFSET);
> +		if (val == 0) {
> +			u32 reason = pmcmsptwi_readl(data->iobase +
> +						MSP_TWI_INT_STS_REG_OFFSET);
> +			pmcmsptwi_writel(reason, data->iobase +
> +						MSP_TWI_INT_STS_REG_OFFSET);
> +			data->last_result = pmcmsptwi_get_result(reason);
> +			return;
> +		}
> +		udelay(MSP_POLL_DELAY);
> +	}
> +
> +	dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
> +	data->last_result = MSP_TWI_XFER_TIMEOUT;
> +}

> +/*
> + * Sends an i2c command out on the adapter
> + */
> +static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
> +				struct i2c_msg *msg, int num)
> +{
> +	struct pmcmsptwi_data *data = adap->algo_data;
> +	struct pmcmsptwi_cmd cmd;
> +	struct pmcmsptwi_cfg oldcfg, newcfg;
> +	bool probe = false;
> +	u8 probe_buf[] = { 0 };
> +	int ret;
> +
> +	if (num > 2) {
> +		dev_dbg(&adap->dev, "%d messages unsupported\n", num);
> +		return -EINVAL;
> +	} else if (num == 2) {
> +		/* Check for a dual write-then-read command */
> +		struct i2c_msg *nextmsg = msg + 1;
> +		if (!(msg->flags & I2C_M_RD) &&
> +		    (nextmsg->flags & I2C_M_RD) &&
> +		    msg->addr == nextmsg->addr) {
> +			cmd.type = MSP_TWI_CMD_WRITE_READ;
> +			cmd.write_len = msg->len;
> +			cmd.write_data = msg->buf;
> +			cmd.read_len = nextmsg->len;
> +			cmd.read_data = nextmsg->buf;
> +		} else {
> +			dev_dbg(&adap->dev,
> +				"Non write-read dual messages unsupported\n");
> +			return -EINVAL;
> +		}
> +	} else if (msg->flags & I2C_M_RD) {
> +		cmd.type = MSP_TWI_CMD_READ;
> +		cmd.read_len = msg->len;
> +		cmd.read_data = msg->buf;
> +		cmd.write_len = 0;
> +		cmd.write_data = NULL;
> +	} else {
> +		cmd.type = MSP_TWI_CMD_WRITE;
> +		cmd.read_len = 0;
> +		cmd.read_data = NULL;
> +		cmd.write_len = msg->len;
> +		cmd.write_data = msg->buf;
> +	}

Good, exactly what I had in mind.

> +
> +	if (msg->len == 0) {
> +		if (msg->flags & I2C_M_RD) {
> +			dev_dbg(&adap->dev,
> +				"Read of 0 bytes unsupported\n");
> +			return -EINVAL;
> +		} else {
> +			dev_dbg(&adap->dev, "Probing for slave at 0x%02x\n",
> +				msg->addr & 0xff);
> +			probe = true;
> +
> +			/* Probe is a special write of 1 byte */
> +			cmd.write_len = 1;
> +			cmd.write_data = probe_buf;
> +		}
> +	}

This should go away. As explained in my other post, new-style i2c
drivers don't need probing (and if you really want probing, it no
longer requires zero-byte messages.)

> +
> +	cmd.addr = msg->addr;
> +
> +	if (probe || (msg->flags & I2C_M_TEN)) {
> +		pmcmsptwi_get_twi_config(&newcfg, data);
> +		memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
> +
> +		/* For probes, we don't want any retries */
> +		if (probe)
> +			newcfg.nak = 0;
> +
> +		/* Set the special 10-bit address flag, if required */
> +		if (msg->flags & I2C_M_TEN)
> +			newcfg.add10 = 1;
> +
> +		pmcmsptwi_set_twi_config(&newcfg, data);
> +	}
> +
> +	/* Execute the command */
> +	ret = pmcmsptwi_xfer_cmd(&cmd, data);
> +
> +	if (probe || (msg->flags & I2C_M_TEN))
> +		pmcmsptwi_set_twi_config(&oldcfg, data);
> +
> +	dev_dbg(&adap->dev, "I2C %s of %d bytes ",
> +		(msg->flags & I2C_M_RD) ? "read" : "write", msg->len);
> +	if (ret != MSP_TWI_XFER_OK) {
> +		/*
> +		 * TODO: We could potentially loop and retry in the case
> +		 * of MSP_TWI_XFER_TIMEOUT.
> +		 */
> +		dev_dbg(&adap->dev, "failed\n");
> +		return -1;
> +	}
> +
> +	dev_dbg(&adap->dev, "succeeded\n");
> +	return 0;
> +}
> +
> +static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
> +{
> +	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
> +}

You'll have to change this. I2C_FUNC_SMBUS_EMUL includes
I2C_FUNC_SMBUS_QUICK and it's important that you don't pretend to
support that when you don't.

> +static struct platform_driver pmcmsptwi_driver = {
> +	.probe  = pmcmsptwi_probe,
> +	.remove	= __devexit_p(pmcmsptwi_remove),
> +	.driver {
> +		.name = DRV_NAME,

Use a tab before "=" for alignment.

> +		.owner	= THIS_MODULE,
> +	},
> +};
> +
> +static int __init pmcmsptwi_init(void)
> +{
> +	printk(KERN_INFO "PMC MSP TWI Driver\n");

You already have a printk when the adapter is registered, maybe it's
enough?

> +
> +	if (platform_driver_register(&pmcmsptwi_driver)) {
> +		printk(KERN_ERR "Driver registration failed\n");

This error message isn't particularly useful. The user will notice that
it failed, as the driver won't be loaded. And you don't even print the
driver name...

> +		return -ENOMEM;

You should return the error value that was returned to you by
platform_driver_register(), rather than an arbitrary value.

> +	}
> +
> +	return 0;
> +}

It starts looking really good, well done.

-- 
Jean Delvare



More information about the i2c mailing list