[linux-yocto] [PATCH 40/70] PowerPC: ACP34xx: Add SPI at25 eeprom support

Paul Butler butler.paul at gmail.com
Mon Jun 10 18:46:03 PDT 2013


From: Jiang Lu <lu.jiang at 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.jiang at 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




More information about the linux-yocto mailing list