Re: SPI read problem

From: Murali K. Vemuri
Date: Thu Apr 21 2011 - 07:30:57 EST


2011/4/21 Murali K. Vemuri <vemuri.muralikrishna@xxxxxxxxx>:
> 2011/4/21 Pei Lin <telent997@xxxxxxxxx>:
>> 2011/4/21 Murali K. Vemuri <vemuri.muralikrishna@xxxxxxxxx>:
>>> On Wed, Apr 20, 2011 at 10:48 PM, Jonathan Cameron <jic23@xxxxxxxxx> wrote:
>>>> On 04/20/11 05:40, Murali K. Vemuri wrote:
>>>>> On Wed, Apr 20, 2011 at 12:19 PM, 徐建辉 <xujianhui168@xxxxxxxxx> wrote:
>>>>>> you can use tasklet.
>>>>>>
>>>>>> 2011/4/19 Murali K. Vemuri <vemuri.muralikrishna@xxxxxxxxx>
>>>>>>>
>>>>>>> Hello there,
>>>>>>> I have a device which is Written_to/Read_from using SPI Bus.
>>>>>>>
>>>>>>> I initialize the device like this:
>>>>>>>
>>>>>>> static int __init myDEV_init(void)
>>>>>>> {
>>>>>>> return spi_register_driver(&myDEV_driver);
>>>>>>> }
>>>>>>> module_init(myDEV_init);
>>>>>>>
>>>>>>> My myDEV_probe() function looks like this:
>>>>>>>
>>>>>>> static int __devinit myDEV_probe(struct spi_device *spi)
>>>>>>> {
>>>>>>> .....
>>>>>>> .....
>>>>>>> /*when my CPU receives a particular IRQ, I have to do a spi_read() and
>>>>>>> do couple of spi_write(), I am using like this:*/
>>>>>>> err = request_threaded_irq (MY_DEV_IRQ, NULL, myDEV_irq_thread,
>>>>>>> IRQF_TRIGGER_RISING, "MYDEV", NULL);
>>>> This should be fine. The thread can sleep just fine. We do this
>>>> all over the place. Could be something to do with the irq
>>>> handling on the device.
>>>>>>>
>>>>>>> return 0;
>>>>>>> }
>>>>>>>
>>>>>>> When the Interrupt is received by the CPU, myDEV_irq_thread is being
>>>>>>> called.
>>>>>>> However, in the ISR I have to do spi_read(). This is always returning
>>>>>>> "Timed out".
>>>> That's very suspicious. What spi controller are we dealing with here?
>>>>>>>
>>>>>>> To verify if the device is not at all working, along with registering
>>>>>>> for the IRQ, I also created a char device through I did a IOCTL.
>>>>>>> The IOCTL command in turn does spi_read(). In this case spi_read() is
>>>>>>> successful.
>>>>>>>
>>>>>>> Since it is necessary to do spi_read() in my ISR, I searched around
>>>>>>> and found some information that
>>>>>>> spi_read() is callable only from contexts that can sleep.
>>>>>>>
>>>>>>> How can I make my ISR sleep? or is there any other way of doing this?
>>>>>>>
>>>>>>> Any help is highly appreciated.
>>>>>>> Thanks & regards
>>>>>>> Murali
>>>>>>> --
>>>>>>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>>>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>>>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>>>>>> Please read the FAQ at http://www.tux.org/lkml/
>>>>>>
>>>>>>
>>>>>
>>>>> Hi there,
>>>>>
>>>>> I tried using "tasklet", "workqueue" and semaphore ... all my attempts failed.
>>>>> if there is any other method I should try, please let me know.
>>>> Something nastier is happening here. It's not a problem with what you've
>>>> presented in this email. Perhaps a minimum example of the full code surrounding
>>>> the problem may help us diagnose it.
>>>>
>>>
>>> Thanks a lot for the inputs. this is the read function I have:
>>> (What I am trying to do is read register E6 of my device, the
>>> register width is 16 bits.).
>>>
>>> static struct spi_device * my_SPI_DEV; (this is populated in the probe function)
>>>
>>> static int myDEV_read(u8 * buf, u16 len)
>>> {
>>> int err;
>>> err = spi_read(my_SPI_DEV, buf, len);
>>> return err;
>>> }
>>> static int read_e6()
>>> {
>>> u8 buf[3];
>>> int err;
>>> buf[0] = 0xe6;
>>> buf[1] = 0x00;
>>> buf[2] = 0x00;
>>> err = myDEV_read(buf, 3);
>>> printk(KERN_ERR "myDEV read returned: %d\n",err);
>>> return err;
>>> }
>>>
>>> Now, this function read_e6() is called from the ISR I mentioned above.
>>>
>>
>>
>> spi_read will call spi_sync and this call may only be used from a
>> context that may sleep. The sleep
>> is non-interruptible, and has no timeout. should use in
>> non-interruptable context.
>> you should put the spi_read on context which can sleep, as bottom half
>> "work queue"
>> Or use spi_async interface.
>>
> I added "workqueue", and got the same result. Also, I used "tasklet"
> and got the same result.
> spi_async does not seem to be working for me, returning EINVAL (-22).
> spi_sync() seem to be returning 0 (supposed to be success) but no data
> coming out ... still investigating why ZEROS are returned instead of
> valid data.
>
> if you have any suggestions, please let me know.
>
> Murali
>>
>>> 90% of time, the read returns "-5" (I/O Error) and about 10% time it
>>> gets "0". However I added a little hexdump to check the content in
>>> case the return value is "0". The register content is always "0".
>>>
>>> Please let me know if I am doing any mistake.
>>> Thanks & regards
>>> Murali
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>> Please read the FAQ at http://www.tux.org/lkml/
>>>
>>
>>
>>
>> --
>> Best Regards
>> Lin
>>
>
Okay, finally dug about and found that My chip was expecting the read
command in different style and I am sending in different style.
my spi_read() has to send only one byte (the register address ) on the
SIMO line and expect 2 bytes on the SOMI line.
I used a load of debug prints to find that my code (as below) is
providing the two bytes of space on SIMO line itself. So, what changes
are needed in this code to read correctly?

static struct spi_device * my_SPI_DEV; (this is populated in the probe function)

static int myDEV_read(u8 * buf, u16 len)
{
int err;
err = spi_read(my_SPI_DEV, buf, len);
return err;
}
static int read_e6()
{
u8 buf[3];
int err;
buf[0] = 0xe6;
buf[1] = 0x00;
buf[2] = 0x00;
err = myDEV_read(buf, 3);
printk(KERN_ERR "myDEV read returned: %d\n",err);
return err;
}


Thanks in advance
Murali
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/