[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