From: Darius <augulis.darius-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW@public.gmane.org
Subject: Re: [PATCH][resend] iMX/MXC support for I2C
Date: Thu, 04 Dec 2008 11:59:56 +0200 [thread overview]
Message-ID: <4937AA1C.8050004@gmail.com> (raw)
In-Reply-To: <20081203234317.GA4256-elnMNo+KYs3pIgCt6eIbzw@public.gmane.org>
>>> +static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
>>> +{
>>> + unsigned long orig_jiffies = jiffies;
>>> +
>>> + /* Wait for ack */
>>> + while (readb(i2c_imx->base + IMX_I2C_I2SR) & I2SR_RXAK) {
>>> + if (signal_pending(current)) {
>>> + dev_dbg(&i2c_imx->adapter.dev,
>>> + "<%s> I2C Interrupted\n", __func__);
>>> + return -EINTR;
>>> + }
>>> + if (time_after(jiffies, orig_jiffies + HZ)) {
>>> + dev_dbg(&i2c_imx->adapter.dev,
>>> + "<%s> No ACK\n", __func__);
>>> + return -EIO;
>>> + }
>>> + schedule();
>>> + }
>> 1s is way too long here! i2cdetect takes ages to complete. The mxc driver
>> doesn't wait here at all - as soon as a tx is complete, it checks the ack
>> status. Could you verify if this would work on your MX1 too?
>
> That does seem a problem, if we can detect a NAK immediately then all
> the better.
I tested on MX1. There delay is not needed at all.
>
>>> +
>>> + dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__);
>>> + return 0; /* No ACK */
>>> +}
>>> +
>>> +static void i2c_imx_start(struct imx_i2c_struct *i2c_imx)
>>> +{
>>> + unsigned int temp = 0;
>>> +
>>> + dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>>> +
>>> + /* Enable I2C controller */
>>> + writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
>>> + /* Start I2C transaction */
>>> + temp = readb(i2c_imx->base + IMX_I2C_I2CR);
>>> + temp |= I2CR_MSTA;
>>> + writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
>>> + temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
>>> + writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
>>> +}
>>> +
>>> +static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
>>> +{
>>> + unsigned int temp = 0;
>>> +
>>> + /* Stop I2C transaction */
>>> + dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
>>> + temp = readb(i2c_imx->base + IMX_I2C_I2CR);
>>> + temp &= ~I2CR_MSTA;
>>> + writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
>>> + /* setup chip registers to defaults */
>>> + writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
>>> + writeb(0, i2c_imx->base + IMX_I2C_I2SR);
>>> + /*
>>> + * This delay caused by an i.MXL hardware bug.
>>> + * If no (or too short) delay, no "STOP" bit will be generated.
>>> + */
>>> + udelay(disable_delay);
>>> + /* Disable I2C controller */
>>> + writeb(0, i2c_imx->base + IMX_I2C_I2CR);
>>> +}
>>> +
>>> +static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
>>> + unsigned int rate)
>>> +{
>>> + unsigned int i2c_clk_rate;
>>> + unsigned int div;
>>> + int i;
>>> +
>>> + /* Divider value calculation */
>>> + i2c_clk_rate = clk_get_rate(i2c_imx->clk);
>>> + div = (i2c_clk_rate + rate - 1) / rate;
>>> + if (div < i2c_clk_div[0][0])
>>> + i = 0;
>>> + else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
>>> + i = ARRAY_SIZE(i2c_clk_div) - 1;
>>> + else
>>> + for (i = 0; i2c_clk_div[i][0] < div; i++);
>>> +
>>> + /* Write divider value to register */
>>> + writeb(i2c_clk_div[i][1], i2c_imx->base + IMX_I2C_IFDR);
>>> +
>>> + /*
>>> + * There dummy delay is calculated.
>>> + * It should be about one I2C clock period long.
>>> + * This delay is used in I2C bus disable function
>>> + * to fix chip hardware bug.
>>> + */
>>> + disable_delay = (500000U * i2c_clk_div[i][0]
>>> + + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
>>> +
>>> + /* dev_dbg() can't be used, because adapter is not yet registered */
>>> +#ifdef CONFIG_I2C_DEBUG_BUS
>>> + printk(KERN_DEBUG "I2C: <%s> I2C_CLK=%d, REQ DIV=%d\n",
>>> + __func__, i2c_clk_rate, div);
>>> + printk(KERN_DEBUG "I2C: <%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
>>> + __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
>>> +#endif
>
> not using dev_xxx() here?
because adapter is not yet registered.
>
>>> +}
>>> +
>>> +static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
>>> +{
>>> + struct imx_i2c_struct *i2c_imx = dev_id;
>>> + unsigned int temp;
>>> +
>>> + temp = readb(i2c_imx->base + IMX_I2C_I2SR);
>>> + if (temp & I2SR_IIF) {
>>> + /* save status register */
>>> + i2c_imx->i2csr = temp;
>>> + temp &= ~I2SR_IIF;
>>> + writeb(temp, i2c_imx->base + IMX_I2C_I2SR);
>>> + wake_up_interruptible(&i2c_imx->queue);
>>> + }
>>> +
>>> + return IRQ_HANDLED;
>>> +}
>
> it would be nice if we returned IRQ_NONE if we didn't have anything
> to handle.
I will add this.
>>> + if (!request_mem_region(res->start, res_size, res->name)) {
>>> + dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
>>> + res_size, res->start);
>>> + return -ENOMEM;
>>> + }
>> I was once told, one doesn't need request_mem_region() on regions from
>> platform data resources - this is already done implicitly.
>
> I belive that request_mem_region() is the correct thing to do, IIRC,
> the platform_device_register() calls insert_resource() on all the
> resource regions of the device so that it is guarnateed to appear in
> the /proc/ioport or /proc/iomem map. However I belive this does not
> actually make a reservation of that resource.
>
confused... Guennadi, can you please explain more your mention?
>>> +
>>> + if (pdata->init) {
>>> + ret = pdata->init(&pdev->dev);
>>> + if (ret)
>>> + goto fail0;
>>> + }
>>> +
>>> + base = ioremap(res->start, res_size);
>>> + if (!base) {
>>> + dev_err(&pdev->dev, "ioremap failed\n");
>>> + ret = -EIO;
>>> + goto fail1;
>>> + }
>>> +
>>> + i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);
>>> + if (!i2c_imx) {
>>> + dev_err(&pdev->dev, "can't allocate interface\n");
>>> + ret = -ENOMEM;
>>> + goto fail2;
>>> + }
>>> +
>>> + /* Setup i2c_imx driver structure */
>>> + strcpy(i2c_imx->adapter.name, pdev->name);
>>> + i2c_imx->adapter.owner = THIS_MODULE;
>>> + i2c_imx->adapter.algo = &i2c_imx_algo;
>>> + i2c_imx->adapter.dev.parent = &pdev->dev;
>>> + i2c_imx->adapter.nr = pdev->id;
>>> + i2c_imx->irq = irq;
>>> + i2c_imx->base = base;
>>> + i2c_imx->res = res;
>>> +
>>> + /* Get I2C clock */
>>> + i2c_imx->clk = clk_get(NULL, "i2c_clk");
>> There can be several i2c busses on the system, so you want:
>>
>> + i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
>
> tbh, the bus clock should be defined as NULL, any extra clocks for
> a device get names. However this may need fixing in the platform
> as well. I belive RMK is already making these changes for AMBA and
> I will probably follow suit with the s3c architectures as soon as
> the rest of the development work is out of the way.
>
>>> + if (IS_ERR(i2c_imx->clk)) {
>>> + ret = PTR_ERR(i2c_imx->clk);
>>> + dev_err(&pdev->dev, "can't get I2C clock\n");
>>> + goto fail3;
>>> + }
>>> + clk_enable(i2c_imx->clk);
>>> +
>>> + /* Request IRQ */
>>> + ret = request_irq(i2c_imx->irq, i2c_imx_isr,
>>> + IRQF_DISABLED, pdev->name, i2c_imx);
>
> do you really need to run your i2c isr with interrupts disabled?
no, interrupts can be enabled. will fix.
>
> kernel doc comments would be nice for this to actually say what is
> expected of the implementation and what these calls are there for.
>
>>> +struct imxi2c_platform_data {
>>> + int (*init)(struct device *dev);
>>> + int (*exit)(struct device *dev);
>> What are you going to use .exit() for? Is it really needed? Even if it is,
>> it can easily return void I guess?
>>
Where to put commnets? Right here in driver code or is better in /Documentation?
next prev parent reply other threads:[~2008-12-04 9:59 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-12-02 14:00 [PATCH][resend] iMX/MXC support for I2C Darius
2008-12-02 14:04 ` Darius
2008-12-03 8:28 ` Jean Delvare
2008-12-03 11:17 ` Guennadi Liakhovetski
[not found] ` <Pine.LNX.4.64.0812030917440.4717-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
2008-12-03 12:52 ` Darius
2008-12-03 15:19 ` Mark Brown
2008-12-03 21:19 ` Guennadi Liakhovetski
[not found] ` <Pine.LNX.4.64.0812032158150.7961-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
2008-12-03 23:45 ` Ben Dooks
2008-12-04 7:47 ` Darius
[not found] ` <49378B1A.7030909-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2008-12-04 13:30 ` Mark Brown
2008-12-03 23:43 ` Ben Dooks
[not found] ` <20081203234317.GA4256-elnMNo+KYs3pIgCt6eIbzw@public.gmane.org>
2008-12-04 9:59 ` Darius [this message]
[not found] ` <4937AA1C.8050004-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2008-12-04 10:20 ` Guennadi Liakhovetski
2008-12-05 15:17 ` Guennadi Liakhovetski
[not found] ` <Pine.LNX.4.64.0812051612500.5840-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
2008-12-08 9:18 ` Darius
2008-12-03 12:56 ` Guennadi Liakhovetski
[not found] ` <Pine.LNX.4.64.0812031355120.4717-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
2008-12-03 13:07 ` Darius
2008-12-03 13:27 ` Wolfram Sang
2008-12-03 20:58 ` Guennadi Liakhovetski
[not found] ` <Pine.LNX.4.64.0812032155350.7961-0199iw4Nj15frtckUFj5Ag@public.gmane.org>
2008-12-03 23:48 ` Ben Dooks
[not found] ` <20081203234833.GC4256-elnMNo+KYs3pIgCt6eIbzw@public.gmane.org>
2008-12-04 0:21 ` Guennadi Liakhovetski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4937AA1C.8050004@gmail.com \
--to=augulis.darius-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
--cc=linux-arm-kernel-xIg/pKzrS19vn6HldHNs0ANdhmdF6hFW@public.gmane.org \
--cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.