From: Jiang Lu <lu.ji...@windriver.com> LSI ACP34xx board implements 2 eeprom on pl022 spi bus for 2nd stage bootloader. The patch adds dts parser code to extract eeprom information from device-tree and register the devices on spi bus.
Signed-off-by: Jiang Lu <lu.ji...@windriver.com> --- drivers/spi/spi-pl022.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 16c58a6..b4617dc 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -37,6 +37,7 @@ #else #include <linux/of_platform.h> #include <linux/of.h> +#include <linux/spi/eeprom.h> #endif #include <linux/amba/pl022.h> #include <linux/io.h> @@ -89,6 +90,7 @@ #define SSP_MIS(r) (r + 0x01C) #define SSP_ICR(r) (r + 0x020) #define SSP_DMACR(r) (r + 0x024) +#define SSP_CSR(r) (r + 0x030) #define SSP_ITCR(r) (r + 0x080) #define SSP_ITIP(r) (r + 0x084) #define SSP_ITOP(r) (r + 0x088) @@ -2355,6 +2357,162 @@ static struct amba_driver pl022_driver = { .remove = __devexit_p(pl022_amba_remove), }; #else +static void __iomem *pl022_virtbase; +static void __acp_spi_cs_control(u32 control, int cs) +{ + if (control == SSP_CHIP_SELECT) + writel( + readl(SSP_CSR(pl022_virtbase)) & + ~(1 << cs), + SSP_CSR(pl022_virtbase)); + else if (control == SSP_CHIP_DESELECT) + writel( + readl(SSP_CSR(pl022_virtbase)) | + (1 << cs), + SSP_CSR(pl022_virtbase)); +} + +#define DECLARE_PL022_CS_FUN(x) \ +static void __acp_spi_cs_control_##x(u32 control) \ +{ \ + __acp_spi_cs_control(control, x); \ +} + +DECLARE_PL022_CS_FUN(0); +DECLARE_PL022_CS_FUN(1); +DECLARE_PL022_CS_FUN(2); +DECLARE_PL022_CS_FUN(3); +DECLARE_PL022_CS_FUN(4); +DECLARE_PL022_CS_FUN(5); +DECLARE_PL022_CS_FUN(6); +DECLARE_PL022_CS_FUN(7); + +static void (*acp_cs_control[])(u32) = { + __acp_spi_cs_control_0, + __acp_spi_cs_control_1, + __acp_spi_cs_control_2, + __acp_spi_cs_control_3, + __acp_spi_cs_control_4, + __acp_spi_cs_control_5, + __acp_spi_cs_control_6, + __acp_spi_cs_control_7, +}; + +struct pl022_config_chip eeprom_chip_info = { + .iface = SSP_INTERFACE_MOTOROLA_SPI, + .hierarchy = SSP_MASTER, + .clk_freq = { + .cpsdvsr = 0x2, + .scr = 0x31, + }, + .com_mode = INTERRUPT_TRANSFER, + .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, + .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, + .ctrl_len = SSP_BITS_8, + .wait_state = SSP_MWIRE_WAIT_ZERO, + .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, +}; + +struct spi_eeprom eeprom_chip = { + .flags = EE_ADDR3 | EE_READONLY, + .byte_len = 128*1024, +}; + +static void register_spi_device(struct pl022 *pl022) +{ + struct spi_device *spi; + struct device_node *nc; + const __be32 *prop; + int rc; + int len; + struct spi_master *master = pl022->master; + + int is_at25; + + /* Save pl022 io base for cs functions */ + pl022_virtbase = pl022->virtbase; + for_each_child_of_node(pl022->dev->dev.of_node, nc) { + /* Alloc an spi_device */ + spi = spi_alloc_device(pl022->master); + if (!spi) { + dev_err(&master->dev, "spi_device alloc error for %s\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + /* Select device driver */ + is_at25 = 0; + if (of_device_is_compatible(nc, "at25")) { + sprintf(spi->modalias, "at25"); + is_at25 = 1; + } else if (of_modalias_node(nc, spi->modalias, + sizeof(spi->modalias)) < 0) { + dev_err(&master->dev, "cannot find modalias for %s\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + + /* Device address */ + prop = of_get_property(nc, "reg", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(&master->dev, "%s has no 'reg' property\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + spi->chip_select = be32_to_cpup(prop); + if (spi->chip_select >= master->num_chipselect) { + dev_err(&master->dev, "%s got a wrong cs %d\n", + nc->full_name, spi->chip_select); + spi_dev_put(spi); + continue; + } + + /* Mode (clock phase/polarity/etc.) */ + if (of_find_property(nc, "spi-cpha", NULL)) + spi->mode |= SPI_CPHA; + if (of_find_property(nc, "spi-cpol", NULL)) + spi->mode |= SPI_CPOL; + if (of_find_property(nc, "spi-cs-high", NULL)) + spi->mode |= SPI_CS_HIGH; + + /* Device speed */ + prop = of_get_property(nc, "spi-max-frequency", &len); + if (!prop || len < sizeof(*prop)) { + dev_err(&master->dev, "%s has no 'spi-max-frequency'" \ + " property\n", + nc->full_name); + spi_dev_put(spi); + continue; + } + spi->max_speed_hz = be32_to_cpup(prop); + + /* IRQ */ + spi->irq = irq_of_parse_and_map(nc, 0); + + /* Store a pointer to the node in the device structure */ + of_node_get(nc); + spi->dev.of_node = nc; + + if (is_at25) { + eeprom_chip_info.cs_control = + acp_cs_control[spi->chip_select], + spi->controller_data = &eeprom_chip_info; + spi->dev.platform_data = &eeprom_chip; + } + + /* Register the new device */ + request_module(spi->modalias); + rc = spi_add_device(spi); + if (rc) { + dev_err(&master->dev, "spi_device register error %s\n", + nc->full_name); + spi_dev_put(spi); + } + } +} + static struct of_device_id pl022_match[]; static int __devinit @@ -2415,6 +2573,7 @@ pl022_of_probe(struct platform_device *ofdev) goto err_data; pl022->dev = ofdev; + register_spi_device(pl022); return 0; err_data: kfree(platform_info); -- 1.8.3 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto