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

Reply via email to