Tuesday, December 26, 2006

Configuration in uClinux


Everything starts from uClinux-dist/Makefile. Let's make a trip from
typing "make menuconfig"

0. make menuconfig:

1. ".PHONY: menuconfig
menuconfig: config.in "

/------------------------------
A phony target is one that is not really the name of a file. It is just
a name for some commands to be executed when you make an explicit
request. There are two reasons to use a phony target: to avoid a
conflict with a file of the same name, and to improve performance.
-------------------------------/

2. ".PHONY: config.tk config.in
config.in:
config/mkconfig > config.in
"
/------------------------------------
config/mkconfig is a script to dynamicly create menuconfig items
according to vender/AnalogDevices/<dirs>
It create configuration for the first two level menu
------------------------------------/

3. menuconfig: config.in
$(MAKE) -C $(SCRIPTSDIR)/lxdialog all
@HELP_FILE=config/Configure.help $(CONFIG_SHELL) $(SCRIPTSDIR)/Menuconfig
config.in
/-------------------------------------------------------------------------
Displays the first two level of menu - then the user choose save
and .config is created.
---------------------------------------------------------------------------/

@if [ ! -f .config ]; then echo; \ echo "You have not saved your
config, please re-run make config"; \
echo; \ exit 1; fi
@config/setconfig defaults
/-------------------------------------------------------------------------------------
Use the default configuation for the applications, uClibc and Linux
kernel.
That is, configuration filese in vendors/AnalogDevices/<boards> are
copied as configuration files.
--------------------------------------------------------------------------------------/

@if egrep "^CONFIG_DEFAULTS_KERNEL=y" .config > /dev/null; then
\
$(MAKE) linux_menuconfig; fi
@if egrep "^CONFIG_DEFAULTS_MODULES=y" .config > /dev/null; then
$(MAKE) modules_menuconfig; fi
@if egrep "^CONFIG_DEFAULTS_VENDOR=y" .config > /dev/null; then
$(MAKE) config_menuconfig; fi
/-----------------------------------------------------------------------------------------
User has choosed to change above settings - so invoke the next level of
config menu
------------------------------------------------------------------------------------------/

@config/setconfig final
/-----------------------------------------------------------------------------------------
Check whether user has choose to save the updated configuration as
default
------------------------------------------------------------------------------------------/

4. For above, if to use configure the applications:

" @if egrep "^CONFIG_DEFAULTS_VENDOR=y" .config > /dev/null; then
$(MAKE) config_menuconfig; fi
"
config_menuconfig:
$(MAKEARCH) -C config menuconfig

config/Makefile:

menuconfig:
@$(CONFIG_SHELL) -n config.in
$(MAKE) -C $(SCRIPTSDIR)/lxdialog all
@HELP_FILE=Configure.help AUTOCONF_FILE=autoconf.h $(CONFIG_SHELL) $(SCRIPTSDIR)/Menuconfig config.in

So as a result, we see the bellow facts:

1. config/* contains config scrips, like mkconfig, setconfig. It also
contains Makefiles and config files for
applications.

2. vendos/AnalogDevices/<boards>/* contains the default configuration
files.

Friday, December 22, 2006

Configuration in uClinux - 1

vendors/config/bfin/config.arch
-------------------------------

vendors/AnalogDevices/BF537-STAMP/config.arch
---------------------------------------------
include $(ROOTDIR)/vendors/config/bfin/config.arch

cp vendors/$(@:_default=)/config.device .config
cp vendors/$(@:_default=)/config.uClibc uClibc/.config
cp vendors/$(@:_default=)/config.vendor-2.6.x config/.config
cp vendors/$(@:_default=)/config.linux-2.6.x linux-2.6.x/.config
ln -sf vendors/$(@:_default=)/config.arch .

Tuesday, December 19, 2006

Friday, December 15, 2006

linker script

GNU ld version 2.17
Supported emulations:
elf32bfin
elf32bfinfd
using internal linker script:
==================================================
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf32-bfin", "elf32-bfin",
"elf32-bfin")
OUTPUT_ARCH(bfin)

=====================================================
There are several ways to set the entry point. The linker will set the
entry point by trying each of the following methods in order, and
stopping when one of them succeeds:

* the -e entry command-line option;
* the ENTRY(symbol) command in a linker script;
* the value of the symbol start, if defined;
* the address of the first byte of the .text section, if present;
* The address 0.

=====================================================

ENTRY(__start)
SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib");
SEARCH_DIR("=/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */

=========================================================================================
The PROVIDE keyword may be used to define a symbol, such as `etext',
only if it is referenced but not defined. The syntax is PROVIDE(symbol =
expression).
=========================================================================================
PROVIDE (__executable_start = 0x0);

=========================================================================================
The Location Counter

The special linker variable dot `.' always contains the current output
location counter. Since the . always refers to a location in an output
section, it must always appear in an expression within a SECTIONS
command. The . symbol may appear anywhere that an ordinary symbol is
allowed in an expression, but its assignments have a side effect.
Assigning a value to the . symbol will cause the location counter to be
moved. This may be used to create holes in the output section. The
location counter may never be moved backwards.

SECTIONS
{
output :
{
file1(.text)
. = . + 1000;
file2(.text)
. += 1000;
file3(.text)
} = 0x1234;
}

In the previous example, file1 is located at the beginning of the output
section, then there is a 1000 byte gap. Then file2 appears, also with a
1000 byte gap following before file3 is loaded. The notation `= 0x1234'
specifies what data to write in the gaps
=========================================================================================

. = 0x0;

.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.dyn :
{
*(.rel.init)
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
*(.rel.fini)
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
*(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
*(.rel.ctors)
*(.rel.dtors)
*(.rel.got)
*(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
*(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
*(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
*(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
}
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
*(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
*(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
*(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
}
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }

============================================================================
When link-time garbage collection is in use (-gc-sections), it is often
useful to mark sections that should not be eliminated. This is
accomplished by surrounding an input section's wildcard entry with
KEEP(), as in KEEP(*(.init)) or KEEP(SORT(*)(.ctors))
============================================================================

.init :
{
KEEP (*(.init))
} =0
.plt : { *(.plt) }
.text :
{
*(.text .stub .text.* .gnu.linkonce.t.*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} =0
.fini :
{
KEEP (*(.fini))
} =0

==============================================
he symbol _etext will be defined as the address following the last .text
input section.
================================================

PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 :
{
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
}
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RO
{ *(.gcc_except_table .gcc_except_table.*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN(0x1000) + (. & (0x1000 - 1));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW
{ *(.gcc_except_table .gcc_except_table.*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (___preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (___preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (___init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN (___init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (___fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (___fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin*.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin*.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
*(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
KEEP (*(.gnu.linkonce.d.*personality*))
==================================================
When linking object file formats which do not support arbitrary
sections, such as ECOFF and XCOFF, the linker will automatically
recognize C++ global constructors and destructors by name. For these
object file formats, the CONSTRUCTORS command tells the linker to place
constructor information in the output section where the CONSTRUCTORS
command appears. The CONSTRUCTORS command is ignored for other object
file formats.

If you are using the gnu C++ support for initialization priority, which
provides some control over the order in which global constructors are
run, you must sort the constructors at link time to ensure that they are
executed in the correct order. When using the CONSTRUCTORS command, use
SORT(CONSTRUCTORS) instead. When using the .ctors and .dtors sections,
use *(SORT(.ctors)) and *(SORT(.dtors)) instead of just *(.ctors) and
*(.dtors).
===================================================

SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.got : { *(.got.plt) *(.got) }
/* We want the small data sections together, so single-instruction
offsets
can access them all, and initialized data all before uninitialized,
so
we can shorten the on-disk segment size. */
.sdata :
{
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
__edata = .; PROVIDE (_edata = .);
__bss_start = .;
.sbss :
{
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = ALIGN(32 / 8);
__end = .; PROVIDE (_end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the
beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/DISCARD/ : { *(.note.GNU-stack) }
}

==================================================

Wednesday, December 13, 2006

bad log

50 + 60 + 100 + 150 + 200 + 180 + 90 + 200 + 350 + 120 + 30

300 + 100 + 100 + 100 + 100

500 + 500 + 250 + 250 + 200 + 200 + 100 + 70 + 60

50 + 110 + 50

70 + 70

40 + 50 + 50 + 50

30

50 + 50 + 200 + 300

50 + 50 + 50

90 + 70

60 + 60 + 180

300 + 600

120 + 100 + 100

400

100 + 100

70 + 100 + 100 + 120

total:59

Sunday, December 10, 2006

usb gadget

GadgetFS ... since not every developer wants to program in the kernel,
or rely specifically on the Linux kernel APIs, a user mode API is
available. An example user mode driver is usb.c. (It also needs
usbstring.c and usbstring.h.) Notice how the device is initialized by
writing its configuration and device descriptors to a file (such
as /dev/gadget/$CHIP), and how the endpoints are initialized in similar
ways (writing descriptors to /dev/gadget/$ENDPOINT). After initializing
them, just read or write to the files to transfer data; or to handle
events including control requests to retrieve string descriptors,
configure alternate settings, and implement class or vendor requests. On
Linux 2.6 AIO (Async I/O) support is available, helping user mode
drivers avoid i/o latencies and letting them stream data as quickly as
in-kernel drivers can stream it. Note that user mode gadget drivers do
not necesarily need to be licensed according to the GPL.

1. Build kernel with GadgetFS support
2. Build kernel with USB client chip, e.g net2272
3. root:/> mount -t gadgetfs gadgetfs /dev/gadget

Will create user space device node: /dev/gadget/net2272.

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

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