Patchwork [U-Boot,5/5] e1000: Add a small SPI driver wrapper around the EEPROM code

login
register
mail settings
Submitter Kyle Moffett
Date Sept. 13, 2010, 3:52 p.m.
Message ID <1284393146-22142-5-git-send-email-Kyle.D.Moffett@boeing.com>
Download mbox | patch
Permalink /patch/71848/
State Superseded
Headers show

Comments

Kyle Moffett - Sept. 13, 2010, 3:52 p.m.
To make it possible to use the "sspi" command with the e1000 firmware
EEPROM we add a small "generic SPI" driver wrapper around the existing
e1000 SPI backend.

Signed-off-by: Kyle Moffett <Kyle.D.Moffett@boeing.com>
---
 drivers/net/e1000.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/e1000.h |    7 ++++
 2 files changed, 98 insertions(+), 1 deletions(-)

Patch

diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c
index 4ff845a..70457f1 100644
--- a/drivers/net/e1000.c
+++ b/drivers/net/e1000.c
@@ -5259,7 +5259,7 @@  e1000_initialize(bd_t * bis)
 	return i;
 }
 
-#ifdef CONFIG_CMD_E1000
+#if defined(CONFIG_E1000_SPI) || defined(CONFIG_CMD_E1000)
 static struct e1000_hw *e1000_find_card(unsigned int cardnum)
 {
 	struct e1000_hw *hw;
@@ -5338,6 +5338,96 @@  static int e1000_spi_xfer(struct e1000_hw *hw, unsigned int bitlen,
 
 	return 0;
 }
+#endif /* defined(CONFIG_E1000_SPI) || defined(CONFIG_CMD_E1000) */
+
+#ifdef CONFIG_E1000_SPI
+static inline struct e1000_hw *e1000_hw_from_spi(struct spi_slave *spi)
+{
+	return container_of(spi, struct e1000_hw, spi);
+}
+
+/* Not sure why all of these are necessary */
+void spi_init_r(void) { /* Nothing to do */ }
+void spi_init_f(void) { /* Nothing to do */ }
+void spi_init(void)   { /* Nothing to do */ }
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+		unsigned int max_hz, unsigned int mode)
+{
+	/* Find the right PCI device */
+	struct e1000_hw *hw = e1000_find_card(bus);
+	if (!hw) {
+		printf("ERROR: No such e1000 device: e1000#%u\n", bus);
+		return NULL;
+	}
+
+	/* Make sure it has an SPI chip */
+	if (hw->eeprom.type != e1000_eeprom_spi) {
+		printf("%s: No attached SPI EEPROM found!\n", hw->nic->name);
+		return NULL;
+	}
+
+	/* Argument sanity checks */
+	if (cs != 0) {
+		printf("%s: No such SPI chip: %u\n", hw->nic->name, cs);
+		return NULL;
+	}
+	if (mode != SPI_MODE_0) {
+		printf("%s: Cannot support SPI modes other than MODE-0\n",
+				hw->nic->name);
+		return NULL;
+	}
+
+	/* TODO: Use max_hz somehow */
+	printf("%s: EEPROM SPI access requested\n", hw->nic->name);
+	return &hw->spi;
+}
+
+void spi_free_slave(struct spi_slave *spi)
+{
+	struct e1000_hw *hw = e1000_hw_from_spi(spi);
+	printf("%s: EEPROM SPI access released\n", hw->nic->name);
+}
+
+int spi_claim_bus(struct spi_slave *spi)
+{
+	struct e1000_hw *hw = e1000_hw_from_spi(spi);
+
+	if (e1000_acquire_eeprom(hw)) {
+		printf("%s: EEPROM SPI cannot be acquired!", hw->nic->name);
+		return -1;
+	}
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *spi)
+{
+	struct e1000_hw *hw = e1000_hw_from_spi(spi);
+	e1000_release_eeprom(hw);
+}
+
+/* Skinny wrapper around e1000_spi_xfer */
+int spi_xfer(struct spi_slave *spi, unsigned int bitlen,
+		const void *dout_mem, void *din_mem, unsigned long flags)
+{
+	struct e1000_hw *hw = e1000_hw_from_spi(spi);
+	int ret;
+
+	if (flags & SPI_XFER_BEGIN)
+		e1000_standby_eeprom(hw);
+
+	ret = e1000_spi_xfer(hw, bitlen, dout_mem, din_mem, TRUE);
+
+	if (flags & SPI_XFER_END)
+		e1000_standby_eeprom(hw);
+
+	return ret;
+}
+
+#endif /* CONFIG_E1000_SPI */
+
+#ifdef CONFIG_CMD_E1000
 
 /* The EEPROM opcodes */
 #define SPI_EEPROM_ENABLE_WR	0x06
diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h
index 68a3409..f504c90 100644
--- a/drivers/net/e1000.h
+++ b/drivers/net/e1000.h
@@ -41,6 +41,10 @@ 
 #include <asm/io.h>
 #include <pci.h>
 
+#ifdef CONFIG_E1000_SPI
+#include <spi.h>
+#endif
+
 #define E1000_ERR(args...) printf("e1000: " args)
 
 #ifdef E1000_DEBUG
@@ -1046,6 +1050,9 @@  typedef enum {
 struct e1000_hw {
 	struct list_head list_node;
 	struct eth_device *nic;
+#ifdef CONFIG_E1000_SPI
+	struct spi_slave spi;
+#endif
 	unsigned int cardnum;
 
 	pci_dev_t pdev;