Thursday, December 07, 2006

SPI on Blackfin - 3

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

------------------------------------------------
spi_device.control_datqa = spi_adc_chip_info;
spi_device.control_state = chip_data;
------------------------------------------------

include/linux/spi/spi.h:
------------------------
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;
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

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/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 *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>

}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

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>
/* Only alloc (or use chip_info) on first setup */
chip = spi_get_ctldata(spi);
if (chip == NULL) {
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip)
return -ENOMEM;

chip->enable_dma = 0;
chip_info = spi->controller_data;
}

/* chip_info isn't always needed */
if (chip_info) {
chip->enable_dma = chip_info->enable_dma != 0
&&
drv_data->master_info->enable_dma;
chip->ctl_reg = chip_info->ctl_reg;
chip->bits_per_word = chip_info->bits_per_word;
chip->cs_change_per_word =
chip_info->cs_change_per_word;
chip->cs_chg_udelay = chip_info->cs_chg_udelay;
}
<snip>

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

Blog Archive