public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* Using SPI in a kernel module
@ 2010-06-27 18:25 Alfredo Quesada Sánchez
  2010-06-27 20:09 ` Mykhail Lodygin
  0 siblings, 1 reply; 6+ messages in thread
From: Alfredo Quesada Sánchez @ 2010-06-27 18:25 UTC (permalink / raw)
  To: linux-arm-kernel

After reading many things about SPI in linux (including the kernel Documentation, that is, spi_summary.txt) and having read many source files in the kernel itself I'm not sure which is the right way to deal with SPI from a kernel module if you don't want to use the spidev (neither the spi-gpio) implementation.

My goal is to create an spidev-like module, which generates a /dev entry (that is the easy part) and hides the details of the device, such as an EEPROM. The way to communicate with userspace using /dev files is simple, but the access to spi.h features isn't that much.

According to some board specific code there is one spi device registered in the system (it's wired to a serial dataflash in my development board), but I don't know how I can get a reference to the spi_device that should give me access to it.

By looking to other existing drivers I should register my own spi_driver, mostly providing probe and remove functions. And the questions are:
- When should I receive a probe call?
- What if I have more than 1 spi device on my system (let's say.. 3)? Will I receive 3 calls to probe?
- Is this the only way to get valid references to spi_device's? Is there any other way to access to the "list" of available spi_device's?

I did a small test with a fake module, which registers a spi_driver, but I did not receive any probe call, that's why this might not be the right way to access to the spi_device.
Besides in other low level code I can see calls to 

Regards



      

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Using SPI in a kernel module
  2010-06-27 18:25 Using SPI in a kernel module Alfredo Quesada Sánchez
@ 2010-06-27 20:09 ` Mykhail Lodygin
  2010-06-27 20:55   ` Alfredo Quesada Sánchez
  0 siblings, 1 reply; 6+ messages in thread
From: Mykhail Lodygin @ 2010-06-27 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hello
How about specifying correct data (for your particular board) in the 
machine-specific code?(arch/your_arch/mach-your_machine/your_machine.c)
Basically it is enough for the system to invoke proper probes.
Mikhail
On 06/27/2010 09:25 PM, Alfredo Quesada S?nchez wrote:
> After reading many things about SPI in linux (including the kernel Documentation, that is, spi_summary.txt) and having read many source files in the kernel itself I'm not sure which is the right way to deal with SPI from a kernel module if you don't want to use the spidev (neither the spi-gpio) implementation.
>
> My goal is to create an spidev-like module, which generates a /dev entry (that is the easy part) and hides the details of the device, such as an EEPROM. The way to communicate with userspace using /dev files is simple, but the access to spi.h features isn't that much.
>
> According to some board specific code there is one spi device registered in the system (it's wired to a serial dataflash in my development board), but I don't know how I can get a reference to the spi_device that should give me access to it.
>
> By looking to other existing drivers I should register my own spi_driver, mostly providing probe and remove functions. And the questions are:
> - When should I receive a probe call?
> - What if I have more than 1 spi device on my system (let's say.. 3)? Will I receive 3 calls to probe?
> - Is this the only way to get valid references to spi_device's? Is there any other way to access to the "list" of available spi_device's?
>
> I did a small test with a fake module, which registers a spi_driver, but I did not receive any probe call, that's why this might not be the right way to access to the spi_device.
> Besides in other low level code I can see calls to
>
> Regards
>
>
>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>    

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Using SPI in a kernel module
  2010-06-27 20:09 ` Mykhail Lodygin
@ 2010-06-27 20:55   ` Alfredo Quesada Sánchez
  2010-06-27 21:26     ` Mykhail Lodygin
  0 siblings, 1 reply; 6+ messages in thread
From: Alfredo Quesada Sánchez @ 2010-06-27 20:55 UTC (permalink / raw)
  To: linux-arm-kernel

There are a few compiled files in that directory (more preciselly is arch/arm/mach-at91), including:

- board-XXX.c (well, the name of the board)

MACHINE_START(AT91SAM9G45EKES, "Atmel AT91SAM9G45-EKES")
	/* Maintainer: Atmel */
	.phys_io	= AT91_BASE_SYS,
	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
	.boot_params	= AT91_SDRAM_BASE + 0x100,
	.timer		= &at91sam926x_timer,
	.map_io		= ek_map_io,
	.init_irq	= ek_init_irq,
	.init_machine	= ek_board_init,
MACHINE_END

In this file there is:

/*
 * SPI devices.
 */
static struct spi_board_info ek_spi_devices[] = {
	{	/* DataFlash chip */
		.modalias	= "mtd_dataflash",
		.chip_select	= 0,
		.max_speed_hz	= 15 * 1000 * 1000,
		.bus_num	= 0,
	},
};

And in ek_board_init I can see a call to:

/* SPI */
at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));


This function is in at91sam9g45_devices.c (also compiled), also having:

static struct resource spi0_resources[] = {
	[0] = {
		.start	= AT91SAM9G45_BASE_SPI0,
		.end	= AT91SAM9G45_BASE_SPI0 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9G45_ID_SPI0,
		.end	= AT91SAM9G45_ID_SPI0,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91sam9g45_spi0_device = {
	.name		= "atmel_spi",
	.id		= 0,
	.dev		= {
				.dma_mask		= &spi_dmamask,
				.coherent_dma_mask	= DMA_BIT_MASK(32),
	},
	.resource	= spi0_resources,
	.num_resources	= ARRAY_SIZE(spi0_resources),
};

static const unsigned spi0_standard_cs[4] = { AT91_PIN_PB3, AT91_PIN_PB18, AT91_PIN_PB19, AT91_PIN_PD27 };

static struct resource spi1_resources[] = {
	[0] = {
		.start	= AT91SAM9G45_BASE_SPI1,
		.end	= AT91SAM9G45_BASE_SPI1 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9G45_ID_SPI1,
		.end	= AT91SAM9G45_ID_SPI1,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91sam9g45_spi1_device = {
	.name		= "atmel_spi",
	.id		= 1,
	.dev		= {
				.dma_mask		= &spi_dmamask,
				.coherent_dma_mask	= DMA_BIT_MASK(32),
	},
	.resource	= spi1_resources,
	.num_resources	= ARRAY_SIZE(spi1_resources),
};

static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB17, AT91_PIN_PD28, AT91_PIN_PD18, AT91_PIN_PD19 };

void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
{
	int i;
	unsigned long cs_pin;
	short enable_spi0 = 0;
	short enable_spi1 = 0;

	/* Choose SPI chip-selects */
	for (i = 0; i < nr_devices; i++) {
		if (devices[i].controller_data)
			cs_pin = (unsigned long) devices[i].controller_data;
		else if (devices[i].bus_num == 0)
			cs_pin = spi0_standard_cs[devices[i].chip_select];
		else
			cs_pin = spi1_standard_cs[devices[i].chip_select];

		if (devices[i].bus_num == 0)
			enable_spi0 = 1;
		else
			enable_spi1 = 1;

		/* enable chip-select pin */
		at91_set_gpio_output(cs_pin, 1);

		/* pass chip-select pin to driver */
		devices[i].controller_data = (void *) cs_pin;
	}

	spi_register_board_info(devices, nr_devices);

	/* Configure SPI bus(es) */
	if (enable_spi0) {
		at91_set_A_periph(AT91_PIN_PB0, 0);	/* SPI0_MISO */
		at91_set_A_periph(AT91_PIN_PB1, 0);	/* SPI0_MOSI */
		at91_set_A_periph(AT91_PIN_PB2, 0);	/* SPI0_SPCK */

		at91_clock_associate("spi0_clk", &at91sam9g45_spi0_device.dev, "spi_clk");
		platform_device_register(&at91sam9g45_spi0_device);
	}
	if (enable_spi1) {
		at91_set_A_periph(AT91_PIN_PB14, 0);	/* SPI1_MISO */
		at91_set_A_periph(AT91_PIN_PB15, 0);	/* SPI1_MOSI */
		at91_set_A_periph(AT91_PIN_PB16, 0);	/* SPI1_SPCK */

		at91_clock_associate("spi1_clk", &at91sam9g45_spi1_device.dev, "spi_clk");
		platform_device_register(&at91sam9g45_spi1_device);
	}
}

To summarize, in the end platform_device_register should be called for SPI 0 (as you can see the board has 2 SPI channels).


So.. assuming this is working as expected, when should i see a call to my driver's probe function? and.. which spi_device will be passed as parameter? (there is only 1 registered, but for this question let's assume that i have more spi devices registered).

Regards

> Hello
> How about specifying correct data (for your particular
> board) in the 
> machine-specific
> code?(arch/your_arch/mach-your_machine/your_machine.c)
> Basically it is enough for the system to invoke proper
> probes.
> Mikhail



      

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Using SPI in a kernel module
  2010-06-27 20:55   ` Alfredo Quesada Sánchez
@ 2010-06-27 21:26     ` Mykhail Lodygin
  2010-06-27 21:47       ` Alfredo Quesada Sánchez
  0 siblings, 1 reply; 6+ messages in thread
From: Mykhail Lodygin @ 2010-06-27 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

Invocation sequence is the same as described  in  ek_spi_devices. So since there is no YOUR driver in ek_spi_devices - i can't say when it would be called - for now - never.
which device? - you define it by setting .chip_select, i believe.

You could see all calls -  just set verbosity to debug function in the 
configuration.
On 06/27/2010 11:55 PM, Alfredo Quesada S?nchez wrote:
> There are a few compiled files in that directory (more preciselly is arch/arm/mach-at91), including:
>
> - board-XXX.c (well, the name of the board)
>
> MACHINE_START(AT91SAM9G45EKES, "Atmel AT91SAM9G45-EKES")
> 	/* Maintainer: Atmel */
> 	.phys_io	= AT91_BASE_SYS,
> 	.io_pg_offst	= (AT91_VA_BASE_SYS>>  18)&  0xfffc,
> 	.boot_params	= AT91_SDRAM_BASE + 0x100,
> 	.timer		=&at91sam926x_timer,
> 	.map_io		= ek_map_io,
> 	.init_irq	= ek_init_irq,
> 	.init_machine	= ek_board_init,
> MACHINE_END
>
> In this file there is:
>
> /*
>   * SPI devices.
>   */
> static struct spi_board_info ek_spi_devices[] = {
> 	{	/* DataFlash chip */
> 		.modalias	= "mtd_dataflash",
> 		.chip_select	= 0,
> 		.max_speed_hz	= 15 * 1000 * 1000,
> 		.bus_num	= 0,
> 	},
> };
>
> And in ek_board_init I can see a call to:
>
> /* SPI */
> at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
>
>
> This function is in at91sam9g45_devices.c (also compiled), also having:
>
> static struct resource spi0_resources[] = {
> 	[0] = {
> 		.start	= AT91SAM9G45_BASE_SPI0,
> 		.end	= AT91SAM9G45_BASE_SPI0 + SZ_16K - 1,
> 		.flags	= IORESOURCE_MEM,
> 	},
> 	[1] = {
> 		.start	= AT91SAM9G45_ID_SPI0,
> 		.end	= AT91SAM9G45_ID_SPI0,
> 		.flags	= IORESOURCE_IRQ,
> 	},
> };
>
> static struct platform_device at91sam9g45_spi0_device = {
> 	.name		= "atmel_spi",
> 	.id		= 0,
> 	.dev		= {
> 				.dma_mask		=&spi_dmamask,
> 				.coherent_dma_mask	= DMA_BIT_MASK(32),
> 	},
> 	.resource	= spi0_resources,
> 	.num_resources	= ARRAY_SIZE(spi0_resources),
> };
>
> static const unsigned spi0_standard_cs[4] = { AT91_PIN_PB3, AT91_PIN_PB18, AT91_PIN_PB19, AT91_PIN_PD27 };
>
> static struct resource spi1_resources[] = {
> 	[0] = {
> 		.start	= AT91SAM9G45_BASE_SPI1,
> 		.end	= AT91SAM9G45_BASE_SPI1 + SZ_16K - 1,
> 		.flags	= IORESOURCE_MEM,
> 	},
> 	[1] = {
> 		.start	= AT91SAM9G45_ID_SPI1,
> 		.end	= AT91SAM9G45_ID_SPI1,
> 		.flags	= IORESOURCE_IRQ,
> 	},
> };
>
> static struct platform_device at91sam9g45_spi1_device = {
> 	.name		= "atmel_spi",
> 	.id		= 1,
> 	.dev		= {
> 				.dma_mask		=&spi_dmamask,
> 				.coherent_dma_mask	= DMA_BIT_MASK(32),
> 	},
> 	.resource	= spi1_resources,
> 	.num_resources	= ARRAY_SIZE(spi1_resources),
> };
>
> static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB17, AT91_PIN_PD28, AT91_PIN_PD18, AT91_PIN_PD19 };
>
> void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
> {
> 	int i;
> 	unsigned long cs_pin;
> 	short enable_spi0 = 0;
> 	short enable_spi1 = 0;
>
> 	/* Choose SPI chip-selects */
> 	for (i = 0; i<  nr_devices; i++) {
> 		if (devices[i].controller_data)
> 			cs_pin = (unsigned long) devices[i].controller_data;
> 		else if (devices[i].bus_num == 0)
> 			cs_pin = spi0_standard_cs[devices[i].chip_select];
> 		else
> 			cs_pin = spi1_standard_cs[devices[i].chip_select];
>
> 		if (devices[i].bus_num == 0)
> 			enable_spi0 = 1;
> 		else
> 			enable_spi1 = 1;
>
> 		/* enable chip-select pin */
> 		at91_set_gpio_output(cs_pin, 1);
>
> 		/* pass chip-select pin to driver */
> 		devices[i].controller_data = (void *) cs_pin;
> 	}
>
> 	spi_register_board_info(devices, nr_devices);
>
> 	/* Configure SPI bus(es) */
> 	if (enable_spi0) {
> 		at91_set_A_periph(AT91_PIN_PB0, 0);	/* SPI0_MISO */
> 		at91_set_A_periph(AT91_PIN_PB1, 0);	/* SPI0_MOSI */
> 		at91_set_A_periph(AT91_PIN_PB2, 0);	/* SPI0_SPCK */
>
> 		at91_clock_associate("spi0_clk",&at91sam9g45_spi0_device.dev, "spi_clk");
> 		platform_device_register(&at91sam9g45_spi0_device);
> 	}
> 	if (enable_spi1) {
> 		at91_set_A_periph(AT91_PIN_PB14, 0);	/* SPI1_MISO */
> 		at91_set_A_periph(AT91_PIN_PB15, 0);	/* SPI1_MOSI */
> 		at91_set_A_periph(AT91_PIN_PB16, 0);	/* SPI1_SPCK */
>
> 		at91_clock_associate("spi1_clk",&at91sam9g45_spi1_device.dev, "spi_clk");
> 		platform_device_register(&at91sam9g45_spi1_device);
> 	}
> }
>
> To summarize, in the end platform_device_register should be called for SPI 0 (as you can see the board has 2 SPI channels).
>
>
> So.. assuming this is working as expected, when should i see a call to my driver's probe function? and.. which spi_device will be passed as parameter? (there is only 1 registered, but for this question let's assume that i have more spi devices registered).
>
> Regards
>
>    
>> Hello
>> How about specifying correct data (for your particular
>> board) in the
>> machine-specific
>> code?(arch/your_arch/mach-your_machine/your_machine.c)
>> Basically it is enough for the system to invoke proper
>> probes.
>> Mikhail
>>      
>
>
>
>    

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100628/edc6638e/attachment-0001.html>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Using SPI in a kernel module
  2010-06-27 21:26     ` Mykhail Lodygin
@ 2010-06-27 21:47       ` Alfredo Quesada Sánchez
  2010-06-27 22:30         ` Mykhail Lodygin
  0 siblings, 1 reply; 6+ messages in thread
From: Alfredo Quesada Sánchez @ 2010-06-27 21:47 UTC (permalink / raw)
  To: linux-arm-kernel

I expected to receive a call to probe as soon as i register an spi_driver, which doesn't
seem to happen. If my driver must be already registered before the machine init then it
can't be a module, it must be inside the kernel, which looks really strange.

What I don't understand is where the spi_device instance is created, and where. Looks like
it's appearing from nowhere. But even more strange is the fact that spidev only registers
its own spi_driver and according to other people it works, so the only explanation for me
is that it can only be done as long as it's part of the kernel. But even being part of the
kernel spi_driver's register should be done before the machine init, which makes no sense
imho.

Regards


--- El dom, 27/6/10, Mykhail Lodygin <mishal@softerra.com> escribi?:

De: Mykhail Lodygin <mishal@softerra.com>
Asunto: Re: Using SPI in a kernel module
Para: "Alfredo Quesada S?nchez" <freddy2_es@yahoo.com>
CC: linux-arm-kernel at lists.infradead.org
Fecha: domingo, 27 de junio, 2010 23:26





  
Invocation sequence is the same as described in ek_spi_devices. So since there is no YOUR driver in ek_spi_devices - i can't say when it would be called - for now - never.
which device? - you define it by setting .chip_select, i believe. 

You could see all calls -? just set verbosity to debug function in the
configuration.



 



      
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100627/e7979067/attachment-0001.html>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Using SPI in a kernel module
  2010-06-27 21:47       ` Alfredo Quesada Sánchez
@ 2010-06-27 22:30         ` Mykhail Lodygin
  0 siblings, 0 replies; 6+ messages in thread
From: Mykhail Lodygin @ 2010-06-27 22:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/28/2010 12:47 AM, Alfredo Quesada S?nchez wrote:
> I expected to receive a call to probe as soon as i register an 
> spi_driver, which doesn't
> seem to happen.
>
of course , you havn't fullfill the appropriate structure fields.
> If my driver must be already registered before the machine init then it
> can't be a module, it must be inside the kernel,
>
Why do you think so? spi works for many years - your driver is not the 
first and definitely not the last, please exame other drivers - you will 
see how to register.
>

> What I don't understand is where the spi_device instance is created, 
> and where. Looks like
> it's appearing from nowhere.
>
come on! drivers/spi/spi.c spi_alloc_device 
<http://lxr.linux.no/linux+*/+code=spi_alloc_device>
> But even more strange is the fact that spidev only registers
> its own spi_driver and according to other people it works, so the only 
> explanation for me
> is that it can only be done as long as it's part of the kernel. But 
> even being part of the
> kernel spi_driver's register should be done before the machine init, 
> which makes no sense
> imho.
>
Sorry but again - why do you think so? please look at several drivers 
which utilize spi_driver structure carefully - and you'll see how to do 
it yourself.
> Regards
>
>
> --- El *dom, 27/6/10, Mykhail Lodygin /<mishal@softerra.com>/* escribi?:
>
>
>     De: Mykhail Lodygin <mishal@softerra.com>
>     Asunto: Re: Using SPI in a kernel module
>     Para: "Alfredo Quesada S?nchez" <freddy2_es@yahoo.com>
>     CC: linux-arm-kernel at lists.infradead.org
>     Fecha: domingo, 27 de junio, 2010 23:26
>
>           Invocation sequence is the same as described   in   ek_spi_devices. So since there is no YOUR driver in ek_spi_devices - i can't say when it would be called - for now - never.
>     which device? - you define it by setting .chip_select, i believe.
>         
>
>     You could see all calls -  just set verbosity to debug function in
>     the configuration.
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100628/da8f9102/attachment-0001.html>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-06-27 22:30 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-27 18:25 Using SPI in a kernel module Alfredo Quesada Sánchez
2010-06-27 20:09 ` Mykhail Lodygin
2010-06-27 20:55   ` Alfredo Quesada Sánchez
2010-06-27 21:26     ` Mykhail Lodygin
2010-06-27 21:47       ` Alfredo Quesada Sánchez
2010-06-27 22:30         ` Mykhail Lodygin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox