Friday, December 01, 2006

Re: SPI on Blackfin - 2

Data Structures
==================

arch/blackfin/mach-bf537/boards/stamp.c
---------------------------------------

/* SPI ADC chip */
static struct bfin5xx_spi_chip spi_adc_chip_info = {
.ctl_reg = 0x1000,
.enable_dma = 1, /* use dma transfer with this chip*/
.bits_per_word = 16,
};

include/asm-blackfin/bfin5xx_spi.h:
-----------------------------------
/* spi_board_info.controller_data for SPI slave devices,
* copied to spi_device.platform_data ... mostly for dma tuning
*/
struct bfin5xx_spi_chip {
u16 ctl_reg;
u8 enable_dma;
u8 bits_per_word;
u8 cs_change_per_word;
u8 cs_chg_udelay;
};

+++++++++++++++++++++++++++++++++++++++++++++++++++++

arch/blackfin/mach-bf537/boards/stamp.c
----------------------------------------
static struct spi_board_info bfin_spi_board_info[] = {

{
.modalias = "bfin_spi_adc", /* Name of spi_driver for
this device */
.max_speed_hz = 8, /* actual baudrate is
SCLK/(2xspeed_hz) */
.bus_num = 1, /* Framework bus number */
.chip_select = 1, /* Framework chip select. */
.platform_data = NULL, /* No spi_driver specific config
*/
.controller_data = &spi_adc_chip_info,
},
}

include/linux/spi/spi.h
---------------------------

/* board-specific information about each SPI device */
struct spi_board_info {
/* the device name and module name are coupled, like
platform_bus;
* "modalias" is normally the driver name.
*
* platform_data goes to spi_device.dev.platform_data,
* controller_data goes to spi_device.controller_data,
* irq is copied too
*/
char modalias[KOBJ_NAME_LEN];
const void *platform_data;
void *controller_data;
int irq;

/* slower signaling on noisy or low voltage boards */
u32 max_speed_hz;

/* bus_num is board specific and matches the bus_num of some
* spi_master that will probably be registered later.
*
* chip_select reflects how this chip is wired to that master;
* it's less than num_chipselect.
*/
u16 bus_num;
u16 chip_select;

/* mode becomes spi_device.mode, and is essential for chips
* where the default of SPI_CS_HIGH = 0 is wrong.
*/
u8 mode;

/* ... may need additional spi_device chip config data here.
* avoid stuff protocol drivers can set; but include stuff
* needed to behave without being bound to a driver:
* - quirks like clock rate mattering when not selected
*/
};

+++++++++++++++++++++++++++++++++++++++++++++++++++++++

drivers/char/bfin_spi_adc.c:
----------------------------
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),
};

include/linux/spi/spi.h:
------------------------

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;
};

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

drivers/char/bfin_spi_adc.c:
----------------------------
struct bfin_spi_adc {
int opened;
int timeout;
unsigned char sense;
unsigned char edge;
unsigned int triggerpos;
unsigned int actcount;
unsigned short *buffer;
unsigned short level;
unsigned char mode;
unsigned char cont;
unsigned short skfs;
int baud;

struct spi_device *spidev;
};

struct bfin_spi_adc spi_adc;

static int __devinit bfin_spi_adc_probe(struct spi_device *spi)
{
spi_adc.spidev = spi;

return 0;
}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

drivers/spi/spi_bfin5xx.c

struct chip_data {
u16 ctl_reg;
u16 baud;
u16 flag;

u8 chip_select_num;
u8 n_bytes;
u32 width; /* 0 or 1 */
u8 enable_dma;
u8 bits_per_word; /* 8 or 16 */
u8 cs_change_per_word;
u8 cs_chg_udelay;
void (*write) (struct driver_data *);
void (*read) (struct driver_data *);
void (*duplex) (struct driver_data *);
};

static inline void setup()
{
<snip>
spi_set_ctldata(spi, chip);
<snip>
}

include/linux/spi/spi.h:
------------------------

static inline void spi_set_ctldata(struct spi_device *spi, void *state)
{
spi->controller_state = state;
}
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
*/
u8 bits_per_word;
int irq;
void *controller_state;
void *controller_data;
const char *modalias;
}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

drivers/spi/spi.c
------------------
spi_register_master() -> scan_boardinfo() -> spi_new_device()

struct spi_device *__init_or_module
spi_new_device(struct spi_master *master, struct spi_board_info *chip)
{
struct spi_device *__init_or_module
spi_new_device(struct spi_master *master, struct spi_board_info *chip)
{
struct spi_device *proxy;
struct device *dev = master->cdev.dev;
int status;

/* NOTE: caller did any chip->bus_num checks necessary */

if (!spi_master_get(master))
return NULL;

proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
if (!proxy) {
dev_err(dev, "can't alloc dev for cs%d\n",
chip->chip_select);
goto fail;
}
proxy->master = master;

<snip>
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
<snip>
/* drivers may modify this default i/o setup */
status = master->setup(proxy);
status = device_register(&proxy->dev);

<snip>

}

Blog Archive