/********************** ADAM **************************************/
The SPI master is registered as a platform devices, while SPI slave devices are registered
as devices in the SPI bus.
SPI Bus
~~~~~~~
spi.c: spi_init()
status = bus_register(&spi_bus_type);
status = class_register(&spi_master_class);
root:/sys/bus/spi> ls -lR
.:
drwxr-xr-x 2 root root 0 Jan 1 01:47 devices
drwxr-xr-x 3 root root 0 Jan 1 2007 drivers
-rw-r--r-- 1 root root 4096 Jan 1 01:47 drivers_autoprobe
--w------- 1 root root 4096 Jan 1 01:47 drivers_probe
./devices:
lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../devices/platform/bfin-spi.0/spi0.1
./drivers:
drwxr-xr-x 2 root root 0 Jan 1 01:47 spidev
./drivers/spidev:
--w------- 1 root root 4096 Jan 1 01:47 bind
lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../../devices/platform/bfin-spi.0/spi0.1
--w------- 1 root root 4096 Jan 1 01:47 unbind
Setup the master (SPI controller)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The SPI master device is registered as a platform device:
// stamp.c:
struct platform_device {
const char *name;
u32 id;
struct device dev;
u32 num_resources;
struct resource *resource;
};
//---------------------------------------------------------------
stamp.c:
static struct resource bfin_spi0_resource[] = {
[0] = {
.start = SPI0_REGBASE,
.end = SPI0_REGBASE + 0xFF,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = CH_SPI,
.end = CH_SPI,
.flags = IORESOURCE_IRQ,
}
};
/* SPI controller data */
static struct bfin5xx_spi_master bfin_spi0_info = {
.num_chipselect = 8,
.enable_dma = 1, /* master has the ability to do dma transfer */
.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
};
static struct platform_device bfin_spi0_device = {
.name = "bfin-spi",
.id = 0, /* Bus number */
.num_resources = ARRAY_SIZE(bfin_spi0_resource),
.resource = bfin_spi0_resource,
.dev = {
.platform_data = &bfin_spi0_info, /* Passed to driver */
},
};
static int __init stamp_init(void) {
platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
}
//-------------------------------------------------------------------------
The driver for SPI master:
static struct platform_driver bfin5xx_spi_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
.suspend = bfin5xx_spi_suspend,
.resume = bfin5xx_spi_resume,
.remove = __devexit_p(bfin5xx_spi_remove),
}
/**
* platform_driver_probe - register driver for non-hotpluggable device
* @drv: platform driver structure
* @probe: the driver probe routine, probably from an __init section
*
* Use this instead of platform_driver_register() when you know the device
* is not hotpluggable and has already been registered, and you want to
* remove its run-once probe() infrastructure from memory after the driver
* has bound to the device.
*
* One typical use for this would be with drivers for controllers integrated
* into system-on-chip processors, where the controller devices have been
* configured as part of board setup.
*
* Returns zero if the driver registered and bound to a device, else returns
* a negative error code and with the driver not registered.
*/
static int __init bfin5xx_spi_init(void)
{
return platform_driver_probe(&bfin5xx_spi_driver, bfin5xx_spi_probe);
}
------------------------------------------------------------------------------------------
Bind spi slave devices and spi driver.
platform_probe()
--> bfin_spi_probe() // spi_bf5xx.c
--> spi_register_master() // spi.c
--> scan_board_info() // for all the devices in the table defined in board.c (stamp.c)
--> spi_new_device()
--> master->setup() // set up the new device HW
--> device_register()
-----------------------------------------------------------------
This driver defines bellow routine for spi master device
master->cleanup = cleanup;
master->setup = setup;
master->transfer = transfer;
------------------------------------------------------------------
Set up queues for transfer:
// spi_bf5xx.c
bfin_spi_probe()
---> init_queue()
---> tasklet_init(&drv_data->pump_transfers,
pump_transfers, (unsigned long)drv_data);
---> INIT_WORK(&drv_data->pump_messages, pump_messages);
root:/sys/devices/platform/bfin-spi.0> ls -lR
.:
lrwxrwxrwx 1 root root 0 Jan 1 01:48 bus -> ../../../bus/platform
lrwxrwxrwx 1 root root 0 Jan 1 01:48 driver -> ../../../bus/platform/drivers/bfin-spi
-r--r--r-- 1 root root 4096 Jan 1 01:48 modalias
drwxr-xr-x 2 root root 0 Jan 1 2007 power
drwxr-xr-x 3 root root 0 Jan 1 2007 spi0.1
lrwxrwxrwx 1 root root 0 Jan 1 01:48 spi_master:spi0 -> ../../../class/spi_master/spi0
lrwxrwxrwx 1 root root 0 Jan 1 01:48 subsystem -> ../../../bus/platform
-rw-r--r-- 1 root root 4096 Jan 1 01:48 uevent
./power:
-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup
./spi0.1:
lrwxrwxrwx 1 root root 0 Jan 1 01:49 bus -> ../../../../bus/spi
lrwxrwxrwx 1 root root 0 Jan 1 01:49 driver -> ../../../../bus/spi/drivers/spidev
-r--r--r-- 1 root root 4096 Jan 1 01:49 modalias
drwxr-xr-x 2 root root 0 Jan 1 2007 power
lrwxrwxrwx 1 root root 0 Jan 1 01:49 spidev:spidev0.1 -> ../../../../class/spidev/spidev0.1
lrwxrwxrwx 1 root root 0 Jan 1 01:49 subsystem -> ../../../../bus/spi
-rw-r--r-- 1 root root 4096 Jan 1 01:49 uevent
./spi0.1/power:
-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup
For a SPI slave driver:
~~~~~~~~~~~~~~~~~
* This represents the kind of device driver that uses SPI messages to
* interact with the hardware at the other end of a SPI link. It's called
* a "protocol" driver because it works through messages rather than talking
* directly to SPI hardware (which is what the underlying SPI controller
* driver does to pass those messages). These protocols are defined in the
* specification for the device(s) supported by the driver.
*
* As a rule, those device protocols represent the lowest level interface
* supported by a driver, and it will support upper level interfaces too.
* Examples of such upper levels include frameworks like MTD, networking,
* MMC, RTC, filesystem character device nodes, and hardware monitoring.
struct spi_driver {
int (*probe)(struct spi_device *spi);
int (*remove)(struct spi_device *spi);
void (*shutdown)(struct spi_device *spi);
int (*suspend)(struct spi_device *spi, pm_message_t mesg);
int (*resume)(struct spi_device *spi);
struct device_driver driver;
};
static struct spi_driver bfin_spi_adc_driver = {
.driver = {
.name = "bfin_spi_adc",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = bfin_spi_adc_probe,
.remove = __devexit_p(bfin_spi_adc_remove),
};
spi_register_driver(&bfin_spi_adc_driver);
struct bfin_spi_adc {
int opened;
unsigned short *buffer;
int hz;
int cont;
struct spi_device *spidev;
dma_addr_t dma_handle;
};
struct bfin_spi_adc spi_adc;
struct spi_device {
struct device dev;
struct spi_master *master;
u32 max_speed_hz;
u8 chip_select;
u8 mode;
#define SPI_CPHA 0x01 /* clock phase */
#define SPI_CPOL 0x02 /* clock polarity */
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04 /* chipselect active high? */
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
#define SPI_LOOP 0x20 /* loopback mode */
u8 bits_per_word;
int irq;
void *controller_state;
void *controller_data;
const char *modalias;
};
root:/sys/bus/spi/drivers/spidev> ls -lR
.:
--w------- 1 root root 4096 Jan 1 01:47 bind
lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../../devices/platform/bfin-spi.0/spi0.1
--w------- 1 root root 4096 Jan 1 01:47 unbind
root:/sys/devices/platform/bfin-spi.0> ls -lR
.:
lrwxrwxrwx 1 root root 0 Jan 1 01:48 bus -> ../../../bus/platform
lrwxrwxrwx 1 root root 0 Jan 1 01:48 driver -> ../../../bus/platform/drivers/bfin-spi
-r--r--r-- 1 root root 4096 Jan 1 01:48 modalias
drwxr-xr-x 2 root root 0 Jan 1 01:49 power
drwxr-xr-x 3 root root 0 Jan 1 01:49 spi0.1
lrwxrwxrwx 1 root root 0 Jan 1 01:48 spi_master:spi0 -> ../../../class/spi_master/spi0
lrwxrwxrwx 1 root root 0 Jan 1 01:48 subsystem -> ../../../bus/platform
-rw-r--r-- 1 root root 4096 Jan 1 01:48 uevent
./power:
-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup
./spi0.1:
lrwxrwxrwx 1 root root 0 Jan 1 01:49 bus -> ../../../../bus/spi
lrwxrwxrwx 1 root root 0 Jan 1 01:49 driver -> ../../../../bus/spi/drivers/spidev
-r--r--r-- 1 root root 4096 Jan 1 01:49 modalias
drwxr-xr-x 2 root root 0 Jan 1 01:49 power
lrwxrwxrwx 1 root root 0 Jan 1 01:49 spidev:spidev0.1 -> ../../../../class/spidev/spidev0.1
lrwxrwxrwx 1 root root 0 Jan 1 01:49 subsystem -> ../../../../bus/spi
-rw-r--r-- 1 root root 4096 Jan 1 01:49 uevent
./spi0.1/power:
-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup
-------------------------------------------------
Bind the SPI protocol driver to SPI device:
1. In driver init: calls spi_register_driver() --> driver_register()
2. when device_register() is called, the "Driver Core" will search the list of drivers,
and check whether the device "match" with a driver.
3. when driver_register() get called, the "Driver Core" will also scan existing devices
To send a message:
~~~~~~~~~~~~~~~~~
spi_sync() // spi.c
--> spi_async();
--> master->transfer(); // spi_bf5xx.c
--> queue_work(drv_data->workqueue, &drv_data->pump_messages);
--> pump_messages()
--> tasklet_schedule(&drv_data->pump_transfers) //activate the tasklet
--> pump_taskfer()
--> wait_for_completion(&done)
miscellaneous device
~~~~~~~~~~~~~~~~~~~~~
Misc (or miscellaneous) drivers are simple char drivers that share certain common characteristics. The kernel
abstracts these commonalities into an API (implemented in drivers/char/misc.c), and this simplifies the way
these drivers are initialized. All misc devices are assigned a major number of 10, but each can choose a single
minor number. So, if a char driver needs to drive multiple devices as in the CMOS example discussed earlier, it's
probably not a candidate for being a misc driver.
Platform devices
~~~~~~~~~~~~~~~~
Platform devices are devices that typically appear as autonomous
entities in the system. This includes legacy port-based devices and
host bridges to peripheral buses, and most controllers integrated
into system-on-chip platforms. What they usually have in common
is direct addressing from a CPU bus. Rarely, a platform_device will
be connected through a segment of some other kind of bus; but its
registers will still be directly addressable.
Platform devices are given a name, used in driver binding, and a
list of resources such as addresses and IRQs.
Monday, July 28, 2008
blackfin spi device driver
Subscribe to:
Posts (Atom)