All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
@ 2014-09-29 19:34 Simon Glass
  2014-09-29 19:34 ` [U-Boot] [PATCH v3 01/29] sandbox: dts: Add a SPI device and cros_ec device Simon Glass
                   ` (30 more replies)
  0 siblings, 31 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:34 UTC (permalink / raw)
  To: u-boot

Up until now driver model has not been used for any type of bus. Buses
have some unique properties and needs, so we cannot claim that driver
model can cover all the common cases unless we have converted a bus over
to driver model.

SPI is a reasonable choice for this next step. It has a fairly simple
API and not too many dependencies. The main one is SPI flash so we may
as well convert that also. Since the boards I test with have cros_ec I
have also included that, for SPI only.

The technique used is make use of driver model's supported data structures
to hold information currently kept by each subsystem in a private data
structure. Since 'struct spi_slave' relates to the slave device on the bus
it is stored in the 'parent' data with each child device of the bus.
Since 'struct spi_flash' is a standard interface used for each SPI flash
driver, it is stored in the SPI FLash uclass's private data for each
device.

New defines are created to enable driver model for each subsystem. These
are:

   CONFIG_DM_SPI
   CONFIG_DM_SPI_FLASH
   CONFIG_DM_CROS_EC

This allows us to move some boards and drivers to driver model, while
leaving others behind. A 'big bang' conversion of everything to driver
model, even at a subsystem level, is never going to work.

There is some cost in changing the uclass interface after it is created,
so if you have limited time, please spend it reviewing the uclass
interfaces in spi.h and spi_flash.h. These need to be supported by each
driver, so changing them later may involve changing multiple drivers.

To assist with the conversion of other SPI drivers, a README file is
added to walk through the process.

So far, sandbox, exynos and tegra drivers are converted over.

As always, driver model patches are available at u-boot-dm.git branch
'working'. There is a branch for just this series called 'spi-working'.

Changes in v3:
- Add a cs_info() method to the driver model SPI API
- Add a debug() in the probe method
- Add a few more debug() statements
- Add a function comment for sandbox_spi_get_emul()
- Add a missing tab character
- Add a uclass for a generic SPI device (for use with the 'sspi' command)
- Add implementation/comment for the cs_info() method
- Add missing comments to spi.h
- Add new functions to iterate through device children
- Add new patch to add a clarifying comment on struct udevice's seq member
- Add new patch to add aliases for spi on tegra30 boards
- Add new patch to allow parents to pass data to children during probe
- Add new patch to convert Tegra SPI to driver model
- Add spi.h header to 3 sh boards
- Correct typo where 'slave' should say 'bus'
- Expand SPI tests to cover compatibility functions
- Fix two comment typos
- Make sure the old device is both removed and unbound in 'sf probe'
- Minor renames for clarity
- Put the cs member back into spi_slave
- Rebase to master
- Remove the child_pre_probe() method which is no longer needed
- Update for the new cs_info() method
- Use a generic SPI device for the 'sspi command'
- Use an explicit chip select value instead of reusing device sequence number
- Word-wrap the first paragraph of the binding

Changes in v2:
- Add additional debug() statements
- Add missing comments for struct spi_slave
- Add spi.h header to dfu_sf.c
- Adjust binding to avoid Linux-specific mentions
- Adjust xfer() method for new API
- Correct sandbox's xfer() method signature
- Create a 'spi.bin' file for the SPI tests
- Fix a typo in the commit message
- Fix code nits from Daniel Schwierzeck
- Fix comment on 'slave' parameter to match the parameter name
- Fix typos reported by Jagannadha Sutradharudu Teki
- Update for changes to exynos driver
- Use 'bus' instead of 'dev' to distinguish bus from slave
- Use 'bus' instead of 'dev' to make the API clearer

Simon Glass (29):
  sandbox: dts: Add a SPI device and cros_ec device
  dm: core: Add functions for iterating through device children
  dm: core: Allow parents to pass data to children during probe
  dm: core: Add a clarifying comment on struct udevice's seq member
  dm: spi: Add a uclass for SPI
  dm: sandbox: Add a SPI emulation uclass
  dm: Remove spi_init() from board_r.c when using driver model
  dm: Add spi.h header to a few files
  dm: spi: Adjust cmd_spi to work with driver model
  dm: sandbox: spi: Move to driver model
  dm: spi: Rename soft_spi.c to soft_spi_legacy.c
  dm: spi: Remove SPI_INIT feature
  dm: spi: Add soft_spi implementation
  dm: exynos: Convert SPI to driver model
  dm: spi: Add documentation on how to convert over SPI drivers
  exynos: universal_c210: Move to driver model soft_spi
  sf: Tidy up public and private header files
  spi: Use error return value in sf_ops
  dm: sf: Add a uclass for SPI flash
  dm: Convert spi_flash_probe() and 'sf probe' to use driver model
  dm: sf: sandbox: Convert SPI flash driver to driver model
  dm: exynos: config: Use driver model for SPI flash
  dm: spi: Add tests
  dm: sf: Add tests for SPI flash
  dm: tegra: dts: Add aliases for spi on tegra30 boards
  dm: tegra: spi: Convert to driver model
  dm: cros_ec: Add support for driver model
  dm: sandbox: cros_ec: Move sandbox cros_ec to driver module
  dm: exynos: cros_ec: Move cros_ec_spi to driver model

 arch/arm/dts/exynos4210-universal_c210.dts         |  13 +
 arch/arm/dts/exynos5250-snow.dts                   |   8 +
 arch/arm/dts/exynos5420-peach-pit.dts              |   1 +
 arch/arm/dts/tegra20-trimslice.dts                 |   1 +
 arch/arm/dts/tegra30-beaver.dts                    |   1 +
 arch/arm/dts/tegra30-cardhu.dts                    |   1 +
 arch/arm/dts/tegra30-colibri.dts                   |   1 +
 arch/arm/include/asm/arch-tegra114/tegra114_spi.h  |  41 --
 arch/arm/include/asm/arch-tegra20/tegra20_sflash.h |  41 --
 arch/arm/include/asm/arch-tegra20/tegra20_slink.h  |  41 --
 arch/sandbox/dts/sandbox.dts                       |  26 +
 arch/sandbox/include/asm/spi.h                     |  13 -
 arch/sandbox/include/asm/state.h                   |   2 +-
 board/buffalo/lsxl/lsxl.c                          |   3 +-
 board/compulab/common/eeprom.c                     |   2 +-
 board/nvidia/common/board.c                        |   3 +-
 board/renesas/sh7752evb/sh7752evb.c                |   1 +
 board/renesas/sh7753evb/sh7753evb.c                |   1 +
 board/renesas/sh7757lcr/sh7757lcr.c                |   1 +
 board/samsung/common/board.c                       |   3 -
 board/samsung/universal_c210/universal.c           |  52 --
 common/board_r.c                                   |   2 +-
 common/cmd_sf.c                                    |  26 +
 common/cmd_spi.c                                   |  39 +-
 common/cros_ec.c                                   |  30 ++
 common/env_sf.c                                    |   1 +
 common/exports.c                                   |   4 +-
 doc/device-tree-bindings/mtd/spi/spi-flash.txt     |  25 +
 doc/device-tree-bindings/spi/soft-spi.txt          |  34 ++
 doc/driver-model/README.txt                        |   7 +-
 doc/driver-model/spi-howto.txt                     | 594 +++++++++++++++++++++
 drivers/core/device.c                              |  36 +-
 drivers/dfu/dfu_sf.c                               |   1 +
 drivers/misc/cros_ec.c                             | 122 ++++-
 drivers/misc/cros_ec_sandbox.c                     |  99 +++-
 drivers/misc/cros_ec_spi.c                         |  68 ++-
 drivers/mtd/spi/Makefile                           |   7 +-
 drivers/mtd/spi/ramtron.c                          |   1 +
 drivers/mtd/spi/sandbox.c                          | 338 ++++++++++--
 drivers/mtd/spi/sf-uclass.c                        |  63 +++
 drivers/mtd/spi/sf_internal.h                      |  67 ++-
 drivers/mtd/spi/sf_params.c                        |   1 +
 drivers/mtd/spi/sf_probe.c                         | 154 ++++--
 drivers/mtd/spi/spi_spl_load.c                     |   1 +
 drivers/spi/Makefile                               |   9 +-
 drivers/spi/exynos_spi.c                           | 513 +++++++-----------
 drivers/spi/fdt_spi.c                              | 186 -------
 drivers/spi/sandbox_spi.c                          | 200 +++----
 drivers/spi/soft_spi.c                             | 227 +++++---
 drivers/spi/soft_spi_legacy.c                      | 176 ++++++
 drivers/spi/spi-emul-uclass.c                      |  15 +
 drivers/spi/spi-uclass.c                           | 390 ++++++++++++++
 drivers/spi/tegra114_spi.c                         | 254 ++++-----
 drivers/spi/tegra20_sflash.c                       | 238 +++++----
 drivers/spi/tegra20_slink.c                        | 235 ++++----
 drivers/spi/tegra_spi.h                            |  12 +
 include/configs/exynos-common.h                    |   2 +
 include/configs/peach-pit.h                        |   1 +
 include/configs/s5pc210_universal.h                |  12 +-
 include/configs/sacsng.h                           |   1 -
 include/configs/sandbox.h                          |   5 +-
 include/configs/tegra-common-post.h                |   2 +-
 include/configs/tegra-common.h                     |   2 +
 include/configs/zipitz2.h                          |   1 -
 include/cros_ec.h                                  |  27 +-
 include/dm/device-internal.h                       |  13 +
 include/dm/device.h                                |  25 +-
 include/dm/uclass-id.h                             |   5 +
 include/spi.h                                      | 299 ++++++++++-
 include/spi_flash.h                                | 127 +++--
 test/dm/Makefile                                   |   2 +
 test/dm/bus.c                                      |  31 ++
 test/dm/sf.c                                       |  43 ++
 test/dm/spi.c                                      | 127 +++++
 test/dm/test-dm.sh                                 |   2 +
 test/dm/test.dts                                   |  17 +-
 76 files changed, 3703 insertions(+), 1472 deletions(-)
 delete mode 100644 arch/arm/include/asm/arch-tegra114/tegra114_spi.h
 delete mode 100644 arch/arm/include/asm/arch-tegra20/tegra20_sflash.h
 delete mode 100644 arch/arm/include/asm/arch-tegra20/tegra20_slink.h
 create mode 100644 doc/device-tree-bindings/mtd/spi/spi-flash.txt
 create mode 100644 doc/device-tree-bindings/spi/soft-spi.txt
 create mode 100644 doc/driver-model/spi-howto.txt
 create mode 100644 drivers/mtd/spi/sf-uclass.c
 delete mode 100644 drivers/spi/fdt_spi.c
 create mode 100644 drivers/spi/soft_spi_legacy.c
 create mode 100644 drivers/spi/spi-emul-uclass.c
 create mode 100644 drivers/spi/spi-uclass.c
 create mode 100644 drivers/spi/tegra_spi.h
 create mode 100644 test/dm/sf.c
 create mode 100644 test/dm/spi.c

-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 01/29] sandbox: dts: Add a SPI device and cros_ec device
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
@ 2014-09-29 19:34 ` Simon Glass
  2014-09-29 19:34 ` [U-Boot] [PATCH v3 02/29] dm: core: Add functions for iterating through device children Simon Glass
                   ` (29 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:34 UTC (permalink / raw)
  To: u-boot

Add a SPI device which can be used for testing SPI flash features in
sandbox.

Also add a cros_ec device since with driver model the Chrome OS EC
emulation will not otherwise be available.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2:
- Adjust binding to avoid Linux-specific mentions

 arch/sandbox/dts/sandbox.dts                   | 26 ++++++++++++++++++++++++++
 doc/device-tree-bindings/mtd/spi/spi-flash.txt | 25 +++++++++++++++++++++++++
 2 files changed, 51 insertions(+)
 create mode 100644 doc/device-tree-bindings/mtd/spi/spi-flash.txt

diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 797478a..7614715 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -1,6 +1,9 @@
 /dts-v1/;
 
 / {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
 	chosen {
 		stdout-path = "/serial";
 	};
@@ -131,4 +134,27 @@
 		num-gpios = <20>;
 	};
 
+	spi at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+		compatible = "sandbox,spi";
+		cs-gpios = <0>, <&gpio_a 0>;
+		flash at 0 {
+			reg = <0>;
+			compatible = "spansion,m25p16", "sandbox,spi-flash";
+			spi-max-frequency = <40000000>;
+			sandbox,filename = "spi.bin";
+		};
+	};
+
+	cros-ec at 0 {
+		compatible = "google,cros-ec";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		firmware_storage_spi: flash at 0 {
+			reg = <0 0x400000>;
+		};
+	};
+
 };
diff --git a/doc/device-tree-bindings/mtd/spi/spi-flash.txt b/doc/device-tree-bindings/mtd/spi/spi-flash.txt
new file mode 100644
index 0000000..85522d8
--- /dev/null
+++ b/doc/device-tree-bindings/mtd/spi/spi-flash.txt
@@ -0,0 +1,25 @@
+* MTD SPI driver for serial flash chips
+
+Required properties:
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+- compatible : Should be the manufacturer and the name of the chip. Bear in
+               mind that the DT binding is not U-Boot-only, but in case of
+               U-Boot, see spi_flash_params_table table in
+               drivers/mtd/spi/sf_params.c for the list of supported chips.
+- reg : Chip-Select number
+- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
+
+Optional properties:
+ - memory-map : Address and size of the flash, if memory mapped. This may
+                apply to Intel chipsets, which tend to memory-map flash.
+
+Example:
+
+	flash: m25p80 at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spansion,m25p80";
+		reg = <0>;
+		spi-max-frequency = <40000000>;
+	};
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 02/29] dm: core: Add functions for iterating through device children
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
  2014-09-29 19:34 ` [U-Boot] [PATCH v3 01/29] sandbox: dts: Add a SPI device and cros_ec device Simon Glass
@ 2014-09-29 19:34 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 03/29] dm: core: Allow parents to pass data to children during probe Simon Glass
                   ` (28 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:34 UTC (permalink / raw)
  To: u-boot

Buses need to iterate through their children in some situations. Add a few
functions to make this easy.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add new functions to iterate through device children

Changes in v2: None

 doc/driver-model/README.txt |  3 ++-
 drivers/core/device.c       | 27 +++++++++++++++++++++++++++
 include/dm/device.h         | 18 ++++++++++++++++++
 test/dm/bus.c               | 31 +++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index f9b68be..c435cdc 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -95,7 +95,7 @@ are provided in test/dm. To run them, try:
 You should see something like this:
 
     <...U-Boot banner...>
-    Running 21 driver model tests
+    Running 22 driver model tests
     Test: dm_test_autobind
     Test: dm_test_autoprobe
     Test: dm_test_bus_children
@@ -103,6 +103,7 @@ You should see something like this:
     Device 'c-test at 0': seq 0 is in use by 'a-test'
     Device 'c-test at 1': seq 1 is in use by 'd-test'
     Test: dm_test_bus_children_funcs
+    Test: dm_test_bus_children_iterators
     Test: dm_test_bus_parent_data
     Test: dm_test_bus_parent_ops
     Test: dm_test_children
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 32e80e8..9538874 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -514,3 +514,30 @@ int device_get_child_by_of_offset(struct udevice *parent, int seq,
 	ret = device_find_child_by_of_offset(parent, seq, &dev);
 	return device_get_device_tail(dev, ret, devp);
 }
+
+int device_find_first_child(struct udevice *parent, struct udevice **devp)
+{
+	if (list_empty(&parent->child_head)) {
+		*devp = NULL;
+	} else {
+		*devp = list_first_entry(&parent->child_head, struct udevice,
+					 sibling_node);
+	}
+
+	return 0;
+}
+
+int device_find_next_child(struct udevice **devp)
+{
+	struct udevice *dev = *devp;
+	struct udevice *parent = dev->parent;
+
+	if (list_is_last(&dev->sibling_node, &parent->child_head)) {
+		*devp = NULL;
+	} else {
+		*devp = list_entry(dev->sibling_node.next, struct udevice,
+				   sibling_node);
+	}
+
+	return 0;
+}
diff --git a/include/dm/device.h b/include/dm/device.h
index c8a4072..4d277db 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -274,4 +274,22 @@ int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
 int device_get_child_by_of_offset(struct udevice *parent, int seq,
 				  struct udevice **devp);
 
+/**
+ * device_find_first_child() - Find the first child of a device
+ *
+ * @parent: Parent device to search
+ * @devp: Returns first child device, or NULL if none
+ * @return 0
+ */
+int device_find_first_child(struct udevice *parent, struct udevice **devp);
+
+/**
+ * device_find_first_child() - Find the first child of a device
+ *
+ * @devp: Pointer to previous child device on entry. Returns pointer to next
+ *		child device, or NULL if none
+ * @return 0
+ */
+int device_find_next_child(struct udevice **devp);
+
 #endif
diff --git a/test/dm/bus.c b/test/dm/bus.c
index 873d64e..abbaccf 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -140,6 +140,37 @@ static int dm_test_bus_children_funcs(struct dm_test_state *dms)
 }
 DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
+/* Test that we can iterate through children */
+static int dm_test_bus_children_iterators(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev, *child;
+
+	/* Walk through the children one by one */
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+	ut_assertok(device_find_first_child(bus, &dev));
+	ut_asserteq_str("c-test at 5", dev->name);
+	ut_assertok(device_find_next_child(&dev));
+	ut_asserteq_str("c-test at 0", dev->name);
+	ut_assertok(device_find_next_child(&dev));
+	ut_asserteq_str("c-test at 1", dev->name);
+	ut_assertok(device_find_next_child(&dev));
+	ut_asserteq_ptr(dev, NULL);
+
+	/* Move to the next child without using device_find_first_child() */
+	ut_assertok(device_find_child_by_seq(bus, 5, true, &dev));
+	ut_asserteq_str("c-test at 5", dev->name);
+	ut_assertok(device_find_next_child(&dev));
+	ut_asserteq_str("c-test at 0", dev->name);
+
+	/* Try a device with no children */
+	ut_assertok(device_find_first_child(dev, &child));
+	ut_asserteq_ptr(child, NULL);
+
+	return 0;
+}
+DM_TEST(dm_test_bus_children_iterators,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
 /* Test that the bus can store data about each child */
 static int dm_test_bus_parent_data(struct dm_test_state *dms)
 {
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 03/29] dm: core: Allow parents to pass data to children during probe
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
  2014-09-29 19:34 ` [U-Boot] [PATCH v3 01/29] sandbox: dts: Add a SPI device and cros_ec device Simon Glass
  2014-09-29 19:34 ` [U-Boot] [PATCH v3 02/29] dm: core: Add functions for iterating through device children Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 04/29] dm: core: Add a clarifying comment on struct udevice's seq member Simon Glass
                   ` (27 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Buses sometimes want to pass data to their children when they are probed.
For example, a SPI bus may want to tell the slave device about the chip
select it is connected to.

Add a new function to permit the parent data to be supplied to the child.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add new patch to allow parents to pass data to children during probe

Changes in v2: None

 drivers/core/device.c        |  9 ++++++++-
 include/dm/device-internal.h | 13 +++++++++++++
 include/dm/device.h          |  4 ++++
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/core/device.c b/drivers/core/device.c
index 9538874..49faa29 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -232,7 +232,7 @@ static void device_free(struct udevice *dev)
 	}
 }
 
-int device_probe(struct udevice *dev)
+int device_probe_child(struct udevice *dev, void *parent_priv)
 {
 	struct driver *drv;
 	int size = 0;
@@ -282,6 +282,8 @@ int device_probe(struct udevice *dev)
 				ret = -ENOMEM;
 				goto fail;
 			}
+			if (parent_priv)
+				memcpy(dev->parent_priv, parent_priv, size);
 		}
 
 		ret = device_probe(dev->parent);
@@ -335,6 +337,11 @@ fail:
 	return ret;
 }
 
+int device_probe(struct udevice *dev)
+{
+	return device_probe_child(dev, NULL);
+}
+
 int device_remove(struct udevice *dev)
 {
 	struct driver *drv;
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 7005d03..44cb7ef 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -66,6 +66,19 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
 int device_probe(struct udevice *dev);
 
 /**
+ * device_probe() - Probe a child device, activating it
+ *
+ * Activate a device so that it is ready for use. All its parents are probed
+ * first. The child is provided with parent data if parent_priv is not NULL.
+ *
+ * @dev: Pointer to device to probe
+ * @parent_priv: Pointer to parent data. If non-NULL then this is provided to
+ * the child.
+ * @return 0 if OK, -ve on error
+ */
+int device_probe_child(struct udevice *dev, void *parent_priv);
+
+/**
  * device_remove() - Remove a device, de-activating it
  *
  * De-activate a device so that it is no longer ready for use. All its
diff --git a/include/dm/device.h b/include/dm/device.h
index 4d277db..c24707e 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -133,6 +133,10 @@ struct udevice_id {
  * @per_child_auto_alloc_size: Each device can hold private data owned by
  * its parent. If required this will be automatically allocated if this
  * value is non-zero.
+ * TODO(sjg at chromium.org): I'm considering dropping this, and just having
+ * device_probe_child() pass it in. So far the use case for allocating it
+ * is SPI, but I found that unsatisfactory. Since it is here I will leave it
+ * until things are clearer.
  * @ops: Driver-specific operations. This is typically a list of function
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 04/29] dm: core: Add a clarifying comment on struct udevice's seq member
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (2 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 03/29] dm: core: Allow parents to pass data to children during probe Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI Simon Glass
                   ` (26 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

The sequence number is unique within the uclass, so state this clearly.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add new patch to add a clarifying comment on struct udevice's seq member

Changes in v2: None

 doc/driver-model/README.txt | 4 +++-
 include/dm/device.h         | 3 ++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index c435cdc..8dfcf75 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -359,7 +359,9 @@ Device Sequence Numbers
 U-Boot numbers devices from 0 in many situations, such as in the command
 line for I2C and SPI buses, and the device names for serial ports (serial0,
 serial1, ...). Driver model supports this numbering and permits devices
-to be locating by their 'sequence'.
+to be locating by their 'sequence'. This numbering unique identifies a
+device in its uclass, so no two devices within a particular uclass can have
+the same sequence number.
 
 Sequence numbers start from 0 but gaps are permitted. For example, a board
 may have I2C buses 0, 1, 4, 5 but no 2 or 3. The choice of how devices are
diff --git a/include/dm/device.h b/include/dm/device.h
index c24707e..b8d4e7a 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -57,7 +57,8 @@ struct driver_info;
  * @sibling_node: Next device in list of all devices
  * @flags: Flags for this device DM_FLAG_...
  * @req_seq: Requested sequence number for this device (-1 = any)
- * @seq: Allocated sequence number for this device (-1 = none)
+ * @seq: Allocated sequence number for this device (-1 = none). This is set up
+ * when the device is probed and will be unique within the device's uclass.
  */
 struct udevice {
 	struct driver *driver;
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (3 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 04/29] dm: core: Add a clarifying comment on struct udevice's seq member Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-10-10 17:31   ` Jagan Teki
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 06/29] dm: sandbox: Add a SPI emulation uclass Simon Glass
                   ` (25 subsequent siblings)
  30 siblings, 1 reply; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Add a uclass which provides access to SPI buses and includes operations
required by SPI.

For a time driver model will need to co-exist with the legacy SPI interface
so some parts of the header file are changed depending on which is in use.
The exports are adjusted also since some functions are not available with
driver model.

Boards must define CONFIG_DM_SPI to use driver model for SPI.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add a cs_info() method to the driver model SPI API
- Add a uclass for a generic SPI device (for use with the 'sspi' command)
- Add missing comments to spi.h
- Correct typo where 'slave' should say 'bus'
- Fix two comment typos
- Put the cs member back into spi_slave
- Use an explicit chip select value instead of reusing device sequence number

Changes in v2:
- Add missing comments for struct spi_slave
- Fix code nits from Daniel Schwierzeck
- Use 'bus' instead of 'dev' to make the API clearer

 common/exports.c         |   4 +-
 drivers/spi/Makefile     |   4 +
 drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h   |   2 +
 include/spi.h            | 254 +++++++++++++++++++++++++++++-
 5 files changed, 650 insertions(+), 4 deletions(-)
 create mode 100644 drivers/spi/spi-uclass.c

diff --git a/common/exports.c b/common/exports.c
index b97ca48..88fcfc8 100644
--- a/common/exports.c
+++ b/common/exports.c
@@ -27,10 +27,12 @@ unsigned long get_version(void)
 # define i2c_write         dummy
 # define i2c_read          dummy
 #endif
-#ifndef CONFIG_CMD_SPI
+#if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI)
 # define spi_init          dummy
 # define spi_setup_slave   dummy
 # define spi_free_slave    dummy
+#endif
+#ifndef CONFIG_CMD_SPI
 # define spi_claim_bus     dummy
 # define spi_release_bus   dummy
 # define spi_xfer          dummy
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index f02c35a..d1f1dd0 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -6,7 +6,11 @@
 #
 
 # There are many options which enable SPI, so make this library available
+ifdef CONFIG_DM_SPI
+obj-y += spi-uclass.o
+else
 obj-y += spi.o
+endif
 
 obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o
 obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
new file mode 100644
index 0000000..13c6b77
--- /dev/null
+++ b/drivers/spi/spi-uclass.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <dm/root.h>
+#include <dm/lists.h>
+#include <dm/util.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int spi_set_speed_mode(struct udevice *bus, int speed, int mode)
+{
+	struct dm_spi_ops *ops;
+	int ret;
+
+	ops = spi_get_ops(bus);
+	if (ops->set_speed)
+		ret = ops->set_speed(bus, speed);
+	else
+		ret = -EINVAL;
+	if (ret) {
+		printf("Cannot set speed (err=%d)\n", ret);
+		return ret;
+	}
+
+	if (ops->set_mode)
+		ret = ops->set_mode(bus, mode);
+	else
+		ret = -EINVAL;
+	if (ret) {
+		printf("Cannot set mode (err=%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct udevice *dev = slave->dev;
+	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+	struct dm_spi_bus *spi = bus->uclass_priv;
+	int speed;
+	int ret;
+
+	speed = slave->max_hz;
+	if (spi->max_hz) {
+		if (speed)
+			speed = min(speed, spi->max_hz);
+		else
+			speed = spi->max_hz;
+	}
+	if (!speed)
+		speed = 100000;
+	ret = spi_set_speed_mode(bus, speed, slave->mode);
+	if (ret)
+		return ret;
+
+	return ops->claim_bus ? ops->claim_bus(bus) : 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct udevice *dev = slave->dev;
+	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+
+	if (ops->release_bus)
+		ops->release_bus(bus);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+	     const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *dev = slave->dev;
+	struct udevice *bus = dev->parent;
+
+	if (bus->uclass->uc_drv->id != UCLASS_SPI)
+		return -EOPNOTSUPP;
+
+	return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
+}
+
+int spi_post_bind(struct udevice *dev)
+{
+	/* Scan the bus for devices */
+	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+}
+
+int spi_post_probe(struct udevice *dev)
+{
+	struct dm_spi_bus *spi = dev->uclass_priv;
+
+	spi->max_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+				     "spi-max-frequency", 0);
+
+	return 0;
+}
+
+int spi_chip_select(struct udevice *dev)
+{
+	struct spi_slave *slave = dev_get_parentdata(dev);
+
+	return slave ? slave->cs : -ENOENT;
+}
+
+/**
+ * spi_find_chip_select() - Find the slave attached to chip select
+ *
+ * @bus:	SPI bus to search
+ * @cs:		Chip select to look for
+ * @devp:	Returns the slave device if found
+ * @return 0 if found, -ENODEV on error
+ */
+static int spi_find_chip_select(struct udevice *bus, int cs,
+				struct udevice **devp)
+{
+	struct udevice *dev;
+
+	for (device_find_first_child(bus, &dev); dev;
+	     device_find_next_child(&dev)) {
+		struct spi_slave store;
+		struct spi_slave *slave = dev_get_parentdata(dev);
+
+		if (!slave)  {
+			slave = &store;
+			spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+					       slave);
+		}
+		debug("%s: slave=%p, cs=%d\n", __func__, slave,
+		      slave ? slave->cs : -1);
+		if (slave && slave->cs == cs) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
+int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
+{
+	struct spi_cs_info info;
+	struct udevice *bus;
+	int ret;
+
+	ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus);
+	if (ret) {
+		debug("%s: No bus %d\n", __func__, busnum);
+		return ret;
+	}
+
+	return spi_cs_info(bus, cs, &info);
+}
+
+int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info)
+{
+	struct spi_cs_info local_info;
+	struct dm_spi_ops *ops;
+	int ret;
+
+	if (!info)
+		info = &local_info;
+
+	/* If there is a device attached, return it */
+	info->dev = NULL;
+	ret = spi_find_chip_select(bus, cs, &info->dev);
+	if (!ret)
+		return 0;
+
+	/*
+	 * Otherwise ask the driver. For the moment we don't have CS info.
+	 * When we do we could provide the driver with a helper function
+	 * to figure out what chip selects are valid, or just handle the
+	 * request.
+	 */
+	ops = spi_get_ops(bus);
+	if (ops->cs_info)
+		return ops->cs_info(bus, cs, info);
+
+	/*
+	 * We could assume there is at least one valid chip select, but best
+	 * to be sure and return an error in this case. The driver didn't
+	 * care enough to tell us.
+	 */
+	return -ENODEV;
+}
+
+int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
+		    const char *dev_name, struct udevice **devp)
+{
+	struct driver *drv;
+	int ret;
+
+	drv = lists_driver_lookup_name(drv_name);
+	if (!drv) {
+		printf("Cannot find driver '%s'\n", drv_name);
+		return -ENOENT;
+	}
+	ret = device_bind(bus, drv, dev_name, NULL, -1, devp);
+	if (ret) {
+		printf("Cannot create device named '%s' (err=%d)\n",
+		       dev_name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
+			struct udevice **devp)
+{
+	struct udevice *bus, *dev;
+	int ret;
+
+	ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus);
+	if (ret) {
+		debug("%s: No bus %d\n", __func__, busnum);
+		return ret;
+	}
+	ret = spi_find_chip_select(bus, cs, &dev);
+	if (ret) {
+		debug("%s: No cs %d\n", __func__, cs);
+		return ret;
+	}
+	*busp = bus;
+	*devp = dev;
+
+	return ret;
+}
+
+int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
+		       const char *drv_name, const char *dev_name,
+		       struct udevice **busp, struct spi_slave **devp)
+{
+	struct udevice *bus, *dev;
+	struct spi_slave *slave;
+	bool created = false;
+	int ret;
+
+	ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
+	if (ret) {
+		printf("Invalid bus %d (err=%d)\n", busnum, ret);
+		return ret;
+	}
+	ret = spi_find_chip_select(bus, cs, &dev);
+
+	/*
+	 * If there is no such device, create one automatically. This means
+	 * that we don't need a device tree node or platform data for the
+	 * SPI flash chip - we will bind to the correct driver.
+	 */
+	if (ret == -ENODEV && drv_name) {
+		debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
+		      __func__, dev_name, busnum, cs, drv_name);
+		ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev);
+		if (ret)
+			return ret;
+		created = true;
+	} else if (ret) {
+		printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs,
+		       ret);
+		return ret;
+	}
+
+	if (!device_active(dev)) {
+		slave = (struct spi_slave *)calloc(1,
+						   sizeof(struct spi_slave));
+		if (!slave) {
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
+					     slave);
+		if (ret)
+			goto err;
+		slave->cs = cs;
+		slave->dev = dev;
+		ret = device_probe_child(dev, slave);
+		free(slave);
+		if (ret)
+			goto err;
+	}
+
+	ret = spi_set_speed_mode(bus, speed, mode);
+	if (ret)
+		goto err;
+
+	*busp = bus;
+	*devp = dev_get_parentdata(dev);
+	debug("%s: bus=%p, slave=%p\n", __func__, bus, *devp);
+
+	return 0;
+
+err:
+	if (created) {
+		device_remove(dev);
+		device_unbind(dev);
+	}
+
+	return ret;
+}
+
+/* Compatibility function - to be removed */
+struct spi_slave *spi_setup_slave_fdt(const void *blob, int node,
+				      int bus_node)
+{
+	struct udevice *bus, *dev;
+	int ret;
+
+	ret = uclass_get_device_by_of_offset(UCLASS_SPI, bus_node, &bus);
+	if (ret)
+		return NULL;
+	ret = device_get_child_by_of_offset(bus, node, &dev);
+	if (ret)
+		return NULL;
+	return dev_get_parentdata(dev);
+}
+
+/* Compatibility function - to be removed */
+struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
+				  unsigned int speed, unsigned int mode)
+{
+	struct spi_slave *slave;
+	struct udevice *dev;
+	int ret;
+
+	ret = spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, 0, &dev,
+				  &slave);
+	if (ret)
+		return NULL;
+
+	return slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	device_remove(slave->dev);
+	slave->dev = NULL;
+}
+
+int spi_ofdata_to_platdata(const void *blob, int node,
+			   struct spi_slave *spi)
+{
+	int mode = 0;
+
+	spi->cs = fdtdec_get_int(blob, node, "reg", -1);
+	spi->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
+	if (fdtdec_get_bool(blob, node, "spi-cpol"))
+		mode |= SPI_CPOL;
+	if (fdtdec_get_bool(blob, node, "spi-cpha"))
+		mode |= SPI_CPHA;
+	if (fdtdec_get_bool(blob, node, "spi-cs-high"))
+		mode |= SPI_CS_HIGH;
+	if (fdtdec_get_bool(blob, node, "spi-half-duplex"))
+		mode |= SPI_PREAMBLE;
+	spi->mode = mode;
+
+	return 0;
+}
+
+UCLASS_DRIVER(spi) = {
+	.id		= UCLASS_SPI,
+	.name		= "spi",
+	.post_bind	= spi_post_bind,
+	.post_probe	= spi_post_probe,
+	.per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
+};
+
+UCLASS_DRIVER(spi_generic) = {
+	.id		= UCLASS_SPI_GENERIC,
+	.name		= "spi_generic",
+};
+
+U_BOOT_DRIVER(spi_generic_drv) = {
+	.name		= "spi_generic_drv",
+	.id		= UCLASS_SPI_GENERIC,
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 7f0e37b..0afdc75 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -22,6 +22,8 @@ enum uclass_id {
 	/* U-Boot uclasses start here */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
 	UCLASS_SERIAL,		/* Serial UART */
+	UCLASS_SPI,		/* SPI bus */
+	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/spi.h b/include/spi.h
index b673be2..89949b1 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -54,12 +54,31 @@
 
 #define SPI_DEFAULT_WORDLEN 8
 
+#ifdef CONFIG_DM_SPI
+struct dm_spi_bus {
+	uint max_hz;
+};
+
+#endif /* CONFIG_DM_SPI */
+
 /**
  * struct spi_slave - Representation of a SPI slave
  *
- * Drivers are expected to extend this with controller-specific data.
+ * For driver model this is the per-child data used by the SPI bus. It can
+ * be accessed using dev_get_parentdata() on the slave device. Each SPI
+ * driver should define this child data in its U_BOOT_DRIVER() definition:
+ *
+ *	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
  *
- * @bus:		ID of the bus that the slave is attached to.
+ * If not using driver model, drivers are expected to extend this with
+ * controller-specific data.
+ *
+ * @dev:		SPI slave device
+ * @max_hz:		Maximum speed for this slave
+ * @mode:		SPI mode to use for this slave (see SPI mode flags)
+ * @bus:		ID of the bus that the slave is attached to. For
+ *			driver model this is the sequence number of the SPI
+ *			bus (bus->seq) so does not need to be stored
  * @cs:			ID of the chip select connected to the slave.
  * @op_mode_rx:		SPI RX operation mode.
  * @op_mode_tx:		SPI TX operation mode.
@@ -71,7 +90,13 @@
  * @flags:		Indication of SPI flags.
  */
 struct spi_slave {
+#ifdef CONFIG_DM_SPI
+	struct udevice *dev;	/* struct spi_slave is dev->parentdata */
+	uint max_hz;
+	uint mode;
+#else
 	unsigned int bus;
+#endif
 	unsigned int cs;
 	u8 op_mode_rx;
 	u8 op_mode_tx;
@@ -228,8 +253,9 @@ int  spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
  * Returns: 1 if bus:cs identifies a valid chip on this board, 0
  * otherwise.
  */
-int  spi_cs_is_valid(unsigned int bus, unsigned int cs);
+int spi_cs_is_valid(unsigned int bus, unsigned int cs);
 
+#ifndef CONFIG_DM_SPI
 /**
  * Activate a SPI chipselect.
  * This function is provided by the board code when using a driver
@@ -255,6 +281,7 @@ void spi_cs_deactivate(struct spi_slave *slave);
  * @hz:		The transfer speed
  */
 void spi_set_speed(struct spi_slave *slave, uint hz);
+#endif
 
 /**
  * Write 8 bits, then read 8 bits.
@@ -305,4 +332,225 @@ struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
 struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum,
 					   int node);
 
+#ifdef CONFIG_DM_SPI
+
+/**
+ * struct spi_cs_info - Information about a bus chip select
+ *
+ * @dev:	Connected device, or NULL if none
+ */
+struct spi_cs_info {
+	struct udevice *dev;
+};
+
+/**
+ * struct struct dm_spi_ops - Driver model SPI operations
+ *
+ * The uclass interface is implemented by all SPI devices which use
+ * driver model.
+ */
+struct dm_spi_ops {
+	/**
+	 * Claim the bus and prepare it for communication.
+	 *
+	 * The device provided is the slave device. It's parent controller
+	 * will be used to provide the communication.
+	 *
+	 * This must be called before doing any transfers with a SPI slave. It
+	 * will enable and initialize any SPI hardware as necessary, and make
+	 * sure that the SCK line is in the correct idle state. It is not
+	 * allowed to claim the same bus for several slaves without releasing
+	 * the bus in between.
+	 *
+	 * @bus:	The SPI slave
+	 *
+	 * Returns: 0 if the bus was claimed successfully, or a negative value
+	 * if it wasn't.
+	 */
+	int (*claim_bus)(struct udevice *bus);
+
+	/**
+	 * Release the SPI bus
+	 *
+	 * This must be called once for every call to spi_claim_bus() after
+	 * all transfers have finished. It may disable any SPI hardware as
+	 * appropriate.
+	 *
+	 * @bus:	The SPI slave
+	 */
+	int (*release_bus)(struct udevice *bus);
+
+	/**
+	 * Set the word length for SPI transactions
+	 *
+	 * Set the word length (number of bits per word) for SPI transactions.
+	 *
+	 * @bus:	The SPI slave
+	 * @wordlen:	The number of bits in a word
+	 *
+	 * Returns: 0 on success, -ve on failure.
+	 */
+	int (*set_wordlen)(struct udevice *bus, unsigned int wordlen);
+
+	/**
+	 * SPI transfer
+	 *
+	 * This writes "bitlen" bits out the SPI MOSI port and simultaneously
+	 * clocks "bitlen" bits in the SPI MISO port.  That's just the way SPI
+	 * works.
+	 *
+	 * The source of the outgoing bits is the "dout" parameter and the
+	 * destination of the input bits is the "din" parameter.  Note that
+	 * "dout" and "din" can point to the same memory location, in which
+	 * case the input data overwrites the output data (since both are
+	 * buffered by temporary variables, this is OK).
+	 *
+	 * spi_xfer() interface:
+	 * @dev:	The slave device to communicate with
+	 * @bitlen:	How many bits to write and read.
+	 * @dout:	Pointer to a string of bits to send out.  The bits are
+	 *		held in a byte array and are sent MSB first.
+	 * @din:	Pointer to a string of bits that will be filled in.
+	 * @flags:	A bitwise combination of SPI_XFER_* flags.
+	 *
+	 * Returns: 0 on success, not -1 on failure
+	 */
+	int (*xfer)(struct udevice *dev, unsigned int bitlen, const void *dout,
+		    void *din, unsigned long flags);
+
+	/**
+	 * Set transfer speed.
+	 * This sets a new speed to be applied for next spi_xfer().
+	 * @bus:	The SPI bus
+	 * @hz:		The transfer speed
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*set_speed)(struct udevice *bus, uint hz);
+
+	/**
+	 * Set the SPI mode/flags
+	 *
+	 * It is unclear if we want to set speed and mode together instead
+	 * of separately.
+	 *
+	 * @bus:	The SPI bus
+	 * @mode:	Requested SPI mode (SPI_... flags)
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*set_mode)(struct udevice *bus, uint mode);
+
+	/**
+	 * Get information on a chip select
+	 *
+	 * This is only called when the SPI uclass does not know about a
+	 * chip select, i.e. it has no attached device. It gives the driver
+	 * a chance to allow activity on that chip select even so.
+	 *
+	 * @bus:	The SPI bus
+	 * @cs:		The chip select (0..n-1)
+	 * @info:	Returns information about the chip select, if valid.
+	 *		On entry info->dev is NULL
+	 * @return 0 if OK (and @info is set up), -ENODEV if the chip select
+	 *	   is invalid, other -ve value on error
+	 */
+	int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
+};
+
+/**
+ * spi_find_bus_and_cs() - Find bus and slave devices by number
+ *
+ * Given a bus number and chip select, this finds the corresponding bus
+ * device and slave device. Neither device is activated by this function,
+ * although they may have been activated previously.
+ *
+ * @busnum:	SPI bus number
+ * @cs:		Chip select to look for
+ * @busp:	Returns bus device
+ * @devp:	Return slave device
+ * @return 0 if found, -ENODEV on error
+ */
+int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
+			struct udevice **devp);
+
+/**
+ * spi_get_bus_and_cs() - Find and activate bus and slave devices by number
+ *
+ * Given a bus number and chip select, this finds the corresponding bus
+ * device and slave device.
+ *
+ * If no such slave exists, and drv_name is not NULL, then a new slave device
+ * is automatically bound on this chip select.
+ *
+ * Ths new slave device is probed ready for use with the given speed and mode.
+ *
+ * @busnum:	SPI bus number
+ * @cs:		Chip select to look for
+ * @speed:	SPI speed to use for this slave
+ * @mode:	SPI mode to use for this slave
+ * @drv_name:	Name of driver to attach to this chip select
+ * @dev_name:	Name of the new device thus created
+ * @busp:	Returns bus device
+ * @devp:	Return slave device
+ * @return 0 if found, -ve on error
+ */
+int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
+			const char *drv_name, const char *dev_name,
+			struct udevice **busp, struct spi_slave **devp);
+
+/**
+ * spi_chip_select() - Get the chip select for a slave
+ *
+ * @return the chip select this slave is attached to
+ */
+int spi_chip_select(struct udevice *slave);
+
+/**
+ * spi_bind_device() - bind a device to a bus's chip select
+ *
+ * This binds a new device to an given chip select (which must be unused).
+ *
+ * @bus:	SPI bus to search
+ * @cs:		Chip select to attach to
+ * @drv_name:	Name of driver to attach to this chip select
+ * @dev_name:	Name of the new device thus created
+ * @devp:	Returns the newly bound device
+ */
+int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
+		    const char *dev_name, struct udevice **devp);
+
+/**
+ * spi_ofdata_to_platdata() - decode standard SPI platform data
+ *
+ * This decodes the speed and mode from a device tree node and puts it into
+ * the spi_slave structure.
+ *
+ * @blob:	Device tree blob
+ * @node:	Node offset to read from
+ * @spi:	Place to put the decoded information
+ */
+int spi_ofdata_to_platdata(const void *blob, int node, struct spi_slave *spi);
+
+/**
+ * spi_cs_info() - Check information on a chip select
+ *
+ * This checks a particular chip select on a bus to see if it has a device
+ * attached, or is even valid.
+ *
+ * @bus:	The SPI bus
+ * @cs:		The chip select (0..n-1)
+ * @info:	Returns information about the chip select, if valid
+ * @return 0 if OK (and @info is set up), -ENODEV if the chip select
+ *	   is invalid, other -ve value on error
+ */
+int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info);
+
+struct sandbox_state;
+int sandbox_spi_get_emul(struct sandbox_state *state,
+			 struct udevice *bus, struct udevice *slave,
+			 struct udevice **emulp);
+
+/* Access the serial operations for a device */
+#define spi_get_ops(dev)	((struct dm_spi_ops *)(dev)->driver->ops)
+#endif /* CONFIG_DM_SPI */
+
 #endif	/* _SPI_H_ */
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 06/29] dm: sandbox: Add a SPI emulation uclass
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (4 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 07/29] dm: Remove spi_init() from board_r.c when using driver model Simon Glass
                   ` (24 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

U-Boot includes a SPI emulation driver already but it is not explicit, and
is hidden in the SPI flash code.

Conceptually with sandbox's SPI implementation we have a layer which
creates SPI bus transitions and a layer which interprets them, currently
only for SPI flash. The latter is actually an emulation, and it should be
possible to add more than one emulation - not just SPI flash.

Add a SPI emulation uclass so that other emulations can be plugged in to
support different types of emulated devices on difference buses/chip
selects.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add a function comment for sandbox_spi_get_emul()

Changes in v2:
- Fix comment on 'slave' parameter to match the parameter name

 drivers/spi/Makefile          |  1 +
 drivers/spi/spi-emul-uclass.c | 15 +++++++++++++++
 include/dm/uclass-id.h        |  1 +
 include/spi.h                 | 45 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 62 insertions(+)
 create mode 100644 drivers/spi/spi-emul-uclass.c

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d1f1dd0..a1de028 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -8,6 +8,7 @@
 # There are many options which enable SPI, so make this library available
 ifdef CONFIG_DM_SPI
 obj-y += spi-uclass.o
+obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
 else
 obj-y += spi.o
 endif
diff --git a/drivers/spi/spi-emul-uclass.c b/drivers/spi/spi-emul-uclass.c
new file mode 100644
index 0000000..b436a0e
--- /dev/null
+++ b/drivers/spi/spi-emul-uclass.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+UCLASS_DRIVER(spi_emul) = {
+	.id		= UCLASS_SPI_EMUL,
+	.name		= "spi_emul",
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 0afdc75..6e56382 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -18,6 +18,7 @@ enum uclass_id {
 	UCLASS_TEST,
 	UCLASS_TEST_FDT,
 	UCLASS_TEST_BUS,
+	UCLASS_SPI_EMUL,	/* sandbox SPI device emulator */
 
 	/* U-Boot uclasses start here */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
diff --git a/include/spi.h b/include/spi.h
index 89949b1..aa0a48e 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -456,6 +456,35 @@ struct dm_spi_ops {
 	int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
 };
 
+struct dm_spi_emul_ops {
+	/**
+	 * SPI transfer
+	 *
+	 * This writes "bitlen" bits out the SPI MOSI port and simultaneously
+	 * clocks "bitlen" bits in the SPI MISO port.  That's just the way SPI
+	 * works. Here the device is a slave.
+	 *
+	 * The source of the outgoing bits is the "dout" parameter and the
+	 * destination of the input bits is the "din" parameter.  Note that
+	 * "dout" and "din" can point to the same memory location, in which
+	 * case the input data overwrites the output data (since both are
+	 * buffered by temporary variables, this is OK).
+	 *
+	 * spi_xfer() interface:
+	 * @slave:	The SPI slave which will be sending/receiving the data.
+	 * @bitlen:	How many bits to write and read.
+	 * @dout:	Pointer to a string of bits sent to the device. The
+	 *		bits are held in a byte array and are sent MSB first.
+	 * @din:	Pointer to a string of bits that will be sent back to
+	 *		the master.
+	 * @flags:	A bitwise combination of SPI_XFER_* flags.
+	 *
+	 * Returns: 0 on success, not -1 on failure
+	 */
+	int (*xfer)(struct udevice *slave, unsigned int bitlen,
+		    const void *dout, void *din, unsigned long flags);
+};
+
 /**
  * spi_find_bus_and_cs() - Find bus and slave devices by number
  *
@@ -545,12 +574,28 @@ int spi_ofdata_to_platdata(const void *blob, int node, struct spi_slave *spi);
 int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info);
 
 struct sandbox_state;
+
+/**
+ * sandbox_spi_get_emul() - get an emulator for a SPI slave
+ *
+ * This provides a way to attach an emulated SPI device to a particular SPI
+ * slave, so that xfer() operations on the slave will be handled by the
+ * emulator. If a emulator already exists on that chip select it is returned.
+ * Otherwise one is created.
+ *
+ * @state:	Sandbox state
+ * @bus:	SPI bus requesting the emulator
+ * @slave:	SPI slave device requesting the emulator
+ * @emuip:	Returns pointer to emulator
+ * @return 0 if OK, -ve on error
+ */
 int sandbox_spi_get_emul(struct sandbox_state *state,
 			 struct udevice *bus, struct udevice *slave,
 			 struct udevice **emulp);
 
 /* Access the serial operations for a device */
 #define spi_get_ops(dev)	((struct dm_spi_ops *)(dev)->driver->ops)
+#define spi_emul_get_ops(dev)	((struct dm_spi_emul_ops *)(dev)->driver->ops)
 #endif /* CONFIG_DM_SPI */
 
 #endif	/* _SPI_H_ */
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 07/29] dm: Remove spi_init() from board_r.c when using driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (5 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 06/29] dm: sandbox: Add a SPI emulation uclass Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 08/29] dm: Add spi.h header to a few files Simon Glass
                   ` (23 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Driver model does its own init, so we don't need this.

There is still a call in board_f.c but it is only enabled by CONFIG_HARD_SPI.
It is easy enough to disable that option when converting boards which use
it to driver model.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2:
- Fix a typo in the commit message

 common/board_r.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/board_r.c b/common/board_r.c
index 231c6d6..cd92288 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -354,7 +354,7 @@ static int initr_flash(void)
 }
 #endif
 
-#ifdef CONFIG_PPC
+#if defined(CONFIG_PPC) && !defined(CONFIG_DM_SPI)
 static int initr_spi(void)
 {
 	/* PPC does this here */
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 08/29] dm: Add spi.h header to a few files
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (6 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 07/29] dm: Remove spi_init() from board_r.c when using driver model Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 09/29] dm: spi: Adjust cmd_spi to work with driver model Simon Glass
                   ` (22 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Some files are using SPI functions but not explitly including the SPI
header file. Fix this, since driver model needs it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2:
- Add spi.h header to dfu_sf.c

 common/env_sf.c             | 1 +
 drivers/dfu/dfu_sf.c        | 1 +
 drivers/mtd/spi/sf_params.c | 1 +
 3 files changed, 3 insertions(+)

diff --git a/common/env_sf.c b/common/env_sf.c
index 37ab13a..5e3729c 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -12,6 +12,7 @@
 #include <common.h>
 #include <environment.h>
 #include <malloc.h>
+#include <spi.h>
 #include <spi_flash.h>
 #include <search.h>
 #include <errno.h>
diff --git a/drivers/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c
index 91f6df2..c3d3c3b 100644
--- a/drivers/dfu/dfu_sf.c
+++ b/drivers/dfu/dfu_sf.c
@@ -9,6 +9,7 @@
 #include <errno.h>
 #include <div64.h>
 #include <dfu.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 static long dfu_get_medium_size_sf(struct dfu_entity *dfu)
diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
index 453edf0..61545ca 100644
--- a/drivers/mtd/spi/sf_params.c
+++ b/drivers/mtd/spi/sf_params.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 #include "sf_internal.h"
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 09/29] dm: spi: Adjust cmd_spi to work with driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (7 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 08/29] dm: Add spi.h header to a few files Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 10/29] dm: sandbox: spi: Move to " Simon Glass
                   ` (21 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Driver model uses a different way to find the SPI bus and slave from the
numbered devices given on the command line. Adjust the code to suit.

We use a generic SPI device, and attach it to the SPI bus before performing
the transaction.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Use a generic SPI device for the 'sspi command'

Changes in v2: None

 common/cmd_spi.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/common/cmd_spi.c b/common/cmd_spi.c
index be5709c..64c3ffc 100644
--- a/common/cmd_spi.c
+++ b/common/cmd_spi.c
@@ -11,6 +11,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <errno.h>
 #include <spi.h>
 
@@ -42,19 +43,38 @@ static uchar 		din[MAX_SPI_BYTES];
 static int do_spi_xfer(int bus, int cs)
 {
 	struct spi_slave *slave;
-	int rcode = 0;
-
+	int ret = 0;
+
+#ifdef CONFIG_DM_SPI
+	char name[30], *str;
+	struct udevice *dev;
+
+	snprintf(name, sizeof(name), "generic_%d:%d", bus, cs);
+	str = strdup(name);
+	ret = spi_get_bus_and_cs(bus, cs, 1000000, mode, "spi_generic_drv",
+				 str, &dev, &slave);
+	if (ret)
+		return ret;
+#else
 	slave = spi_setup_slave(bus, cs, 1000000, mode);
 	if (!slave) {
 		printf("Invalid device %d:%d\n", bus, cs);
 		return -EINVAL;
 	}
+#endif
 
-	spi_claim_bus(slave);
-	if (spi_xfer(slave, bitlen, dout, din,
-		     SPI_XFER_BEGIN | SPI_XFER_END) != 0) {
-		printf("Error during SPI transaction\n");
-		rcode = -EIO;
+	ret = spi_claim_bus(slave);
+	if (ret)
+		goto done;
+	ret = spi_xfer(slave, bitlen, dout, din,
+		       SPI_XFER_BEGIN | SPI_XFER_END);
+#ifndef CONFIG_DM_SPI
+	/* We don't get an error code in this case */
+	if (ret)
+		ret = -EIO;
+#endif
+	if (ret) {
+		printf("Error %d during SPI transaction\n", ret);
 	} else {
 		int j;
 
@@ -62,10 +82,13 @@ static int do_spi_xfer(int bus, int cs)
 			printf("%02X", din[j]);
 		printf("\n");
 	}
+done:
 	spi_release_bus(slave);
+#ifndef CONFIG_DM_SPI
 	spi_free_slave(slave);
+#endif
 
-	return rcode;
+	return ret;
 }
 
 /*
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 10/29] dm: sandbox: spi: Move to driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (8 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 09/29] dm: spi: Adjust cmd_spi to work with driver model Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 11/29] dm: spi: Rename soft_spi.c to soft_spi_legacy.c Simon Glass
                   ` (20 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Adjust the sandbox SPI driver to support driver model and move sandbox over
to driver model for SPI.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add implementation/comment for the cs_info() method
- Remove the child_pre_probe() method which is no longer needed

Changes in v2:
- Correct sandbox's xfer() method signature
- Use 'bus' instead of 'dev' to make the API clearer

 arch/sandbox/include/asm/state.h |   1 +
 drivers/spi/sandbox_spi.c        | 200 +++++++++++++++------------------------
 include/configs/sandbox.h        |   3 +-
 3 files changed, 76 insertions(+), 128 deletions(-)

diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index d17a82e..4e0981a 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -43,6 +43,7 @@ enum state_terminal_raw {
 struct sandbox_spi_info {
 	const char *spec;
 	const struct sandbox_spi_emu_ops *ops;
+	struct udevice *emul;
 };
 
 /* The complete state of the test system */
diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c
index 12e9bda..e717424 100644
--- a/drivers/spi/sandbox_spi.c
+++ b/drivers/spi/sandbox_spi.c
@@ -9,26 +9,23 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <spi.h>
+#include <spi_flash.h>
 #include <os.h>
 
 #include <asm/errno.h>
 #include <asm/spi.h>
 #include <asm/state.h>
+#include <dm/device-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 #ifndef CONFIG_SPI_IDLE_VAL
 # define CONFIG_SPI_IDLE_VAL 0xFF
 #endif
 
-struct sandbox_spi_slave {
-	struct spi_slave slave;
-	const struct sandbox_spi_emu_ops *ops;
-	void *priv;
-};
-
-#define to_sandbox_spi_slave(s) container_of(s, struct sandbox_spi_slave, slave)
-
 const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus,
 				   unsigned long *cs)
 {
@@ -45,120 +42,52 @@ const char *sandbox_spi_parse_spec(const char *arg, unsigned long *bus,
 	return endp + 1;
 }
 
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-	return bus < CONFIG_SANDBOX_SPI_MAX_BUS &&
-		cs < CONFIG_SANDBOX_SPI_MAX_CS;
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
-	struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave);
-
-	debug("sandbox_spi: activating CS\n");
-	if (sss->ops->cs_activate)
-		sss->ops->cs_activate(sss->priv);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
-	struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave);
-
-	debug("sandbox_spi: deactivating CS\n");
-	if (sss->ops->cs_deactivate)
-		sss->ops->cs_deactivate(sss->priv);
-}
-
-void spi_init(void)
-{
-}
-
-void spi_set_speed(struct spi_slave *slave, uint hz)
+__weak int sandbox_spi_get_emul(struct sandbox_state *state,
+				struct udevice *bus, struct udevice *slave,
+				struct udevice **emulp)
 {
+	return -ENOENT;
 }
 
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-		unsigned int max_hz, unsigned int mode)
+static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen,
+			    const void *dout, void *din, unsigned long flags)
 {
-	struct sandbox_spi_slave *sss;
+	struct udevice *bus = slave->parent;
 	struct sandbox_state *state = state_get_current();
-	const char *spec;
-
-	if (!spi_cs_is_valid(bus, cs)) {
-		debug("sandbox_spi: Invalid SPI bus/cs\n");
-		return NULL;
-	}
-
-	sss = spi_alloc_slave(struct sandbox_spi_slave, bus, cs);
-	if (!sss) {
-		debug("sandbox_spi: Out of memory\n");
-		return NULL;
-	}
-
-	spec = state->spi[bus][cs].spec;
-	sss->ops = state->spi[bus][cs].ops;
-	if (!spec || !sss->ops || sss->ops->setup(&sss->priv, spec)) {
-		free(sss);
-		printf("sandbox_spi: unable to locate a slave client\n");
-		return NULL;
-	}
-
-	return &sss->slave;
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
-	struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave);
-
-	debug("sandbox_spi: releasing slave\n");
-
-	if (sss->ops->free)
-		sss->ops->free(sss->priv);
-
-	free(sss);
-}
-
-static int spi_bus_claim_cnt[CONFIG_SANDBOX_SPI_MAX_BUS];
-
-int spi_claim_bus(struct spi_slave *slave)
-{
-	if (spi_bus_claim_cnt[slave->bus]++) {
-		printf("sandbox_spi: error: bus already claimed: %d!\n",
-		       spi_bus_claim_cnt[slave->bus]);
-	}
-
-	return 0;
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
-	if (--spi_bus_claim_cnt[slave->bus]) {
-		printf("sandbox_spi: error: bus freed too often: %d!\n",
-		       spi_bus_claim_cnt[slave->bus]);
-	}
-}
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-		void *din, unsigned long flags)
-{
-	struct sandbox_spi_slave *sss = to_sandbox_spi_slave(slave);
+	struct dm_spi_emul_ops *ops;
+	struct udevice *emul;
 	uint bytes = bitlen / 8, i;
-	int ret = 0;
+	int ret;
 	u8 *tx = (void *)dout, *rx = din;
+	uint busnum, cs;
 
 	if (bitlen == 0)
-		goto done;
+		return 0;
 
 	/* we can only do 8 bit transfers */
 	if (bitlen % 8) {
 		printf("sandbox_spi: xfer: invalid bitlen size %u; needs to be 8bit\n",
 		       bitlen);
-		flags |= SPI_XFER_END;
-		goto done;
+		return -EINVAL;
 	}
 
-	if (flags & SPI_XFER_BEGIN)
-		spi_cs_activate(slave);
+	busnum = bus->seq;
+	cs = spi_chip_select(slave);
+	if (busnum >= CONFIG_SANDBOX_SPI_MAX_BUS ||
+	    cs >= CONFIG_SANDBOX_SPI_MAX_CS) {
+		printf("%s: busnum=%u, cs=%u: out of range\n", __func__,
+		       busnum, cs);
+		return -ENOENT;
+	}
+	ret = sandbox_spi_get_emul(state, bus, slave, &emul);
+	if (ret) {
+		printf("%s: busnum=%u, cs=%u: no emulation available (err=%d)\n",
+		       __func__, busnum, cs, ret);
+		return -ENOENT;
+	}
+	ret = device_probe(emul);
+	if (ret)
+		return ret;
 
 	/* make sure rx/tx buffers are full so clients can assume */
 	if (!tx) {
@@ -178,12 +107,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 		}
 	}
 
-	debug("sandbox_spi: xfer: bytes = %u\n tx:", bytes);
-	for (i = 0; i < bytes; ++i)
-		debug(" %u:%02x", i, tx[i]);
-	debug("\n");
-
-	ret = sss->ops->xfer(sss->priv, tx, rx, bytes);
+	ops = spi_emul_get_ops(emul);
+	ret = ops->xfer(emul, bitlen, dout, din, flags);
 
 	debug("sandbox_spi: xfer: got back %i (that's %s)\n rx:",
 	      ret, ret ? "bad" : "good");
@@ -196,22 +121,45 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 	if (rx != din)
 		free(rx);
 
- done:
-	if (flags & SPI_XFER_END)
-		spi_cs_deactivate(slave);
-
 	return ret;
 }
 
-/**
- * Set up a new SPI slave for an fdt node
- *
- * @param blob		Device tree blob
- * @param node		SPI peripheral node to use
- * @return 0 if ok, -1 on error
- */
-struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
-				      int spi_node)
+static int sandbox_spi_set_speed(struct udevice *bus, uint speed)
+{
+	return 0;
+}
+
+static int sandbox_spi_set_mode(struct udevice *bus, uint mode)
+{
+	return 0;
+}
+
+static int sandbox_cs_info(struct udevice *bus, uint cs,
+			   struct spi_cs_info *info)
 {
-	return NULL;
+	/* Always allow activity on CS 0 */
+	if (cs >= 1)
+		return -ENODEV;
+
+	return 0;
 }
+
+static const struct dm_spi_ops sandbox_spi_ops = {
+	.xfer		= sandbox_spi_xfer,
+	.set_speed	= sandbox_spi_set_speed,
+	.set_mode	= sandbox_spi_set_mode,
+	.cs_info	= sandbox_cs_info,
+};
+
+static const struct udevice_id sandbox_spi_ids[] = {
+	{ .compatible = "sandbox,spi" },
+	{ }
+};
+
+U_BOOT_DRIVER(spi_sandbox) = {
+	.name	= "spi_sandbox",
+	.id	= UCLASS_SPI,
+	.of_match = sandbox_spi_ids,
+	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
+	.ops	= &sandbox_spi_ops,
+};
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 6972643..c80e4f0 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -97,8 +97,7 @@
 #define CONFIG_CMD_SF_TEST
 #define CONFIG_CMD_SPI
 #define CONFIG_SPI_FLASH
-#define CONFIG_OF_SPI
-#define CONFIG_OF_SPI_FLASH
+#define CONFIG_DM_SPI
 #define CONFIG_SPI_FLASH_ATMEL
 #define CONFIG_SPI_FLASH_EON
 #define CONFIG_SPI_FLASH_GIGADEVICE
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 11/29] dm: spi: Rename soft_spi.c to soft_spi_legacy.c
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (9 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 10/29] dm: sandbox: spi: Move to " Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 12/29] dm: spi: Remove SPI_INIT feature Simon Glass
                   ` (19 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Reserve the 'normal' name for use by driver model, and rename the old
driver so that it is clear that it is for 'legacy' drivers only.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 drivers/spi/Makefile                          | 2 +-
 drivers/spi/{soft_spi.c => soft_spi_legacy.c} | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename drivers/spi/{soft_spi.c => soft_spi_legacy.c} (100%)

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index a1de028..5cc8655 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -11,6 +11,7 @@ obj-y += spi-uclass.o
 obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
 else
 obj-y += spi.o
+obj-$(CONFIG_SOFT_SPI) += soft_spi_legacy.o
 endif
 
 obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o
@@ -35,7 +36,6 @@ obj-$(CONFIG_MXS_SPI) += mxs_spi.o
 obj-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
 obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
 obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
-obj-$(CONFIG_SOFT_SPI) += soft_spi.o
 obj-$(CONFIG_SH_SPI) += sh_spi.o
 obj-$(CONFIG_SH_QSPI) += sh_qspi.o
 obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi_legacy.c
similarity index 100%
rename from drivers/spi/soft_spi.c
rename to drivers/spi/soft_spi_legacy.c
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 12/29] dm: spi: Remove SPI_INIT feature
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (10 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 11/29] dm: spi: Rename soft_spi.c to soft_spi_legacy.c Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 13/29] dm: spi: Add soft_spi implementation Simon Glass
                   ` (18 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

This feature provides for init of a single SPI port for the soft SPI
feature. It is not really compatible with driver model since it assumes a
single SPI port. Also, inserting SPI init into the driver by means of
a #define is not very nice.

This feature is not used by any active boards, so let's remove it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 drivers/spi/soft_spi_legacy.c       | 5 -----
 include/configs/s5pc210_universal.h | 1 -
 include/configs/sacsng.h            | 1 -
 include/configs/zipitz2.h           | 1 -
 4 files changed, 8 deletions(-)

diff --git a/drivers/spi/soft_spi_legacy.c b/drivers/spi/soft_spi_legacy.c
index c969be3..941daa7 100644
--- a/drivers/spi/soft_spi_legacy.c
+++ b/drivers/spi/soft_spi_legacy.c
@@ -42,11 +42,6 @@ static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
  */
 void spi_init (void)
 {
-#ifdef	SPI_INIT
-	volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
-
-	SPI_INIT;
-#endif
 }
 
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
diff --git a/include/configs/s5pc210_universal.h b/include/configs/s5pc210_universal.h
index 27f3d0a..4fa8d66 100644
--- a/include/configs/s5pc210_universal.h
+++ b/include/configs/s5pc210_universal.h
@@ -194,7 +194,6 @@
 #define CONFIG_SOFT_SPI_GPIO_CS EXYNOS4_GPIO_Y43
 
 #define SPI_DELAY udelay(1)
-#undef SPI_INIT
 #define SPI_SCL(bit) universal_spi_scl(bit)
 #define SPI_SDA(bit) universal_spi_sda(bit)
 #define SPI_READ universal_spi_read()
diff --git a/include/configs/sacsng.h b/include/configs/sacsng.h
index b5064ab..2dee315 100644
--- a/include/configs/sacsng.h
+++ b/include/configs/sacsng.h
@@ -259,7 +259,6 @@
 #define I2C_MOSI	0x00004000      /* PD 17: Master Out, Slave In */
 #define I2C_MISO	0x00008000      /* PD 16: Master In, Slave Out */
 
-#undef  SPI_INIT			/* no port initialization needed */
 #define SPI_READ        ((immr->im_ioport.iop_pdatd & I2C_MISO) != 0)
 #define SPI_SDA(bit)    do {						\
 			if(bit) immr->im_ioport.iop_pdatd |=  I2C_MOSI; \
diff --git a/include/configs/zipitz2.h b/include/configs/zipitz2.h
index 41a7c99..fe331bc 100644
--- a/include/configs/zipitz2.h
+++ b/include/configs/zipitz2.h
@@ -99,7 +99,6 @@
 #define	CONFIG_VIDEO_BMP_GZIP
 #define	CONFIG_VIDEO_BMP_RLE8
 #define	CONFIG_SYS_VIDEO_LOGO_MAX_SIZE	(2 << 20)
-#undef	SPI_INIT
 
 #define	SPI_DELAY	udelay(10)
 #define	SPI_SDA(val)	zipitz2_spi_sda(val)
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 13/29] dm: spi: Add soft_spi implementation
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (11 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 12/29] dm: spi: Remove SPI_INIT feature Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 14/29] dm: exynos: Convert SPI to driver model Simon Glass
                   ` (17 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Add a new implementation of soft_spi that uses device tree to specify the
GPIOs. This will replace soft_spi_legacy for boards which use driver model.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Word-wrap the first paragraph of the binding

Changes in v2: None

 doc/device-tree-bindings/spi/soft-spi.txt |  34 ++++
 drivers/spi/Makefile                      |   1 +
 drivers/spi/soft_spi.c                    | 252 ++++++++++++++++++++++++++++++
 3 files changed, 287 insertions(+)
 create mode 100644 doc/device-tree-bindings/spi/soft-spi.txt
 create mode 100644 drivers/spi/soft_spi.c

diff --git a/doc/device-tree-bindings/spi/soft-spi.txt b/doc/device-tree-bindings/spi/soft-spi.txt
new file mode 100644
index 0000000..d09c1a5
--- /dev/null
+++ b/doc/device-tree-bindings/spi/soft-spi.txt
@@ -0,0 +1,34 @@
+Soft SPI
+
+The soft SPI bus implementation allows the use of GPIO pins to simulate a
+SPI bus. No SPI host is required for this to work. The down-side is that the
+performance will typically be much lower than a real SPI bus.
+
+The soft SPI node requires the following properties:
+
+compatible: "u-boot,soft-spi"
+soft_spi_cs: GPIO number to use for SPI chip select (output)
+soft_spi_sclk: GPIO number to use for SPI clock (output)
+soft_spi_mosi: GPIO number to use for SPI MOSI line (output)
+soft_spi_miso GPIO number to use for SPI MISO line (input)
+spi-delay-us: Number of microseconds of delay between each CS transition
+
+The GPIOs should be specified as required by the GPIO controller referenced.
+The first cell holds the phandle of the controller and the second cell
+typically holds the GPIO number.
+
+
+Example:
+
+	soft-spi {
+		compatible = "u-boot,soft-spi";
+		cs-gpio = <&gpio 235 0>;	/* Y43 */
+		sclk-gpio = <&gpio 225 0>;	/* Y31 */
+		mosi-gpio = <&gpio 227 0>;	/* Y33 */
+		miso-gpio = <&gpio 224 0>;	/* Y30 */
+		spi-delay-us = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cs at 0 {
+		};
+	};
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 5cc8655..e718528 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -9,6 +9,7 @@
 ifdef CONFIG_DM_SPI
 obj-y += spi-uclass.o
 obj-$(CONFIG_SANDBOX) += spi-emul-uclass.o
+obj-$(CONFIG_SOFT_SPI) += soft_spi.o
 else
 obj-y += spi.o
 obj-$(CONFIG_SOFT_SPI) += soft_spi_legacy.o
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
new file mode 100644
index 0000000..5588036
--- /dev/null
+++ b/drivers/spi/soft_spi.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * (C) Copyright 2002
+ * Gerald Van Baren, Custom IDEAS, vanbaren at cideas.com.
+ *
+ * Influenced by code from:
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct soft_spi_platdata {
+	struct fdt_gpio_state cs;
+	struct fdt_gpio_state sclk;
+	struct fdt_gpio_state mosi;
+	struct fdt_gpio_state miso;
+	int spi_delay_us;
+};
+
+struct soft_spi_priv {
+	unsigned int mode;
+};
+
+static int soft_spi_scl(struct udevice *dev, int bit)
+{
+	struct soft_spi_platdata *plat = dev->platdata;
+	struct soft_spi_priv *priv = dev_get_priv(dev);
+
+	gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL ? bit : !bit);
+
+	return 0;
+}
+
+static int soft_spi_sda(struct udevice *dev, int bit)
+{
+	struct soft_spi_platdata *plat = dev->platdata;
+
+	gpio_set_value(plat->mosi.gpio, bit);
+
+	return 0;
+}
+
+static int soft_spi_cs_activate(struct udevice *dev)
+{
+	struct soft_spi_platdata *plat = dev->platdata;
+	struct soft_spi_priv *priv = dev_get_priv(dev);
+
+	gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
+	gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL);
+	gpio_set_value(plat->cs.gpio, priv->mode & SPI_CS_HIGH);
+
+	return 0;
+}
+
+static int soft_spi_cs_deactivate(struct udevice *dev)
+{
+	struct soft_spi_platdata *plat = dev->platdata;
+	struct soft_spi_priv *priv = dev_get_priv(dev);
+
+	gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
+
+	return 0;
+}
+
+static int soft_spi_claim_bus(struct udevice *dev)
+{
+	/*
+	 * Make sure the SPI clock is in idle state as defined for
+	 * this slave.
+	 */
+	return soft_spi_scl(dev, 0);
+}
+
+static int soft_spi_release_bus(struct udevice *dev)
+{
+	/* Nothing to do */
+	return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * SPI transfer
+ *
+ * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
+ * "bitlen" bits in the SPI MISO port.  That's just the way SPI works.
+ *
+ * The source of the outgoing bits is the "dout" parameter and the
+ * destination of the input bits is the "din" parameter.  Note that "dout"
+ * and "din" can point to the same memory location, in which case the
+ * input data overwrites the output data (since both are buffered by
+ * temporary variables, this is OK).
+ */
+static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			 const void *dout, void *din, unsigned long flags)
+{
+	struct soft_spi_priv *priv = dev_get_priv(dev);
+	struct soft_spi_platdata *plat = dev->platdata;
+	uchar		tmpdin  = 0;
+	uchar		tmpdout = 0;
+	const u8	*txd = dout;
+	u8		*rxd = din;
+	int		cpol = priv->mode & SPI_CPOL;
+	int		cpha = priv->mode & SPI_CPHA;
+	unsigned int	j;
+
+	debug("spi_xfer: slave %s:%s dout %08X din %08X bitlen %u\n",
+	      dev->parent->name, dev->name, *(uint *)txd, *(uint *)rxd,
+	      bitlen);
+
+	if (flags & SPI_XFER_BEGIN)
+		soft_spi_cs_activate(dev);
+
+	for (j = 0; j < bitlen; j++) {
+		/*
+		 * Check if it is time to work on a new byte.
+		 */
+		if ((j % 8) == 0) {
+			if (txd)
+				tmpdout = *txd++;
+			else
+				tmpdout = 0;
+			if (j != 0) {
+				if (rxd)
+					*rxd++ = tmpdin;
+			}
+			tmpdin  = 0;
+		}
+
+		if (!cpha)
+			soft_spi_scl(dev, !cpol);
+		soft_spi_sda(dev, tmpdout & 0x80);
+		udelay(plat->spi_delay_us);
+		if (cpha)
+			soft_spi_scl(dev, !cpol);
+		else
+			soft_spi_scl(dev, cpol);
+		tmpdin	<<= 1;
+		tmpdin	|= gpio_get_value(plat->miso.gpio);
+		tmpdout	<<= 1;
+		udelay(plat->spi_delay_us);
+		if (cpha)
+			soft_spi_scl(dev, cpol);
+	}
+	/*
+	 * If the number of bits isn't a multiple of 8, shift the last
+	 * bits over to left-justify them.  Then store the last byte
+	 * read in.
+	 */
+	if (rxd) {
+		if ((bitlen % 8) != 0)
+			tmpdin <<= 8 - (bitlen % 8);
+		*rxd++ = tmpdin;
+	}
+
+	if (flags & SPI_XFER_END)
+		soft_spi_cs_deactivate(dev);
+
+	return 0;
+}
+
+static int soft_spi_set_speed(struct udevice *dev, unsigned int speed)
+{
+	/* Accept any speed */
+	return 0;
+}
+
+static int soft_spi_set_mode(struct udevice *dev, unsigned int mode)
+{
+	struct soft_spi_priv *priv = dev_get_priv(dev);
+
+	priv->mode = mode;
+
+	return 0;
+}
+
+static int soft_spi_child_pre_probe(struct udevice *dev)
+{
+	struct spi_slave *slave = dev_get_parentdata(dev);
+
+	slave->dev = dev;
+	return spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
+}
+
+static const struct dm_spi_ops soft_spi_ops = {
+	.claim_bus	= soft_spi_claim_bus,
+	.release_bus	= soft_spi_release_bus,
+	.xfer		= soft_spi_xfer,
+	.set_speed	= soft_spi_set_speed,
+	.set_mode	= soft_spi_set_mode,
+};
+
+static int soft_spi_ofdata_to_platdata(struct udevice *dev)
+{
+	struct soft_spi_platdata *plat = dev->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+
+	if (fdtdec_decode_gpio(blob, node, "cs-gpio", &plat->cs) ||
+	    fdtdec_decode_gpio(blob, node, "sclk-gpio", &plat->sclk) ||
+	    fdtdec_decode_gpio(blob, node, "mosi-gpio", &plat->mosi) ||
+	    fdtdec_decode_gpio(blob, node, "miso-gpio", &plat->miso))
+		return -EINVAL;
+	plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0);
+
+	return 0;
+}
+
+static int soft_spi_probe(struct udevice *dev)
+{
+	struct spi_slave *slave = dev_get_parentdata(dev);
+	struct soft_spi_platdata *plat = dev->platdata;
+
+	gpio_request(plat->cs.gpio, "soft_spi_cs");
+	gpio_request(plat->sclk.gpio, "soft_spi_sclk");
+	gpio_request(plat->mosi.gpio, "soft_spi_mosi");
+	gpio_request(plat->miso.gpio, "soft_spi_miso");
+
+	gpio_direction_output(plat->sclk.gpio, slave->mode & SPI_CPOL);
+	gpio_direction_output(plat->mosi.gpio, 1);
+	gpio_direction_input(plat->miso.gpio);
+	gpio_direction_output(plat->cs.gpio, !(slave->mode & SPI_CS_HIGH));
+
+	return 0;
+}
+
+static const struct udevice_id soft_spi_ids[] = {
+	{ .compatible = "u-boot,soft-spi" },
+	{ }
+};
+
+U_BOOT_DRIVER(soft_spi) = {
+	.name	= "soft_spi",
+	.id	= UCLASS_SPI,
+	.of_match = soft_spi_ids,
+	.ops	= &soft_spi_ops,
+	.ofdata_to_platdata = soft_spi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct soft_spi_platdata),
+	.priv_auto_alloc_size = sizeof(struct soft_spi_priv),
+	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
+	.probe	= soft_spi_probe,
+	.child_pre_probe	= soft_spi_child_pre_probe,
+};
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 14/29] dm: exynos: Convert SPI to driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (12 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 13/29] dm: spi: Add soft_spi implementation Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 15/29] dm: spi: Add documentation on how to convert over SPI drivers Simon Glass
                   ` (16 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Move the exynos SPI driver over to driver model. This removes quite a bit
of boilerplate from the driver, although it adds some for driver model.

A few device tree additions are needed to make the SPI flash available.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add implementation/comment for the cs_info() method
- Use an explicit chip select value instead of reusing device sequence number

Changes in v2:
- Add additional debug() statements
- Adjust xfer() method for new API
- Use 'bus' instead of 'dev' to distinguish bus from slave

 arch/arm/dts/exynos5250-snow.dts      |   8 +
 arch/arm/dts/exynos5420-peach-pit.dts |   1 +
 board/samsung/common/board.c          |   3 -
 drivers/spi/exynos_spi.c              | 513 ++++++++++++----------------------
 include/configs/exynos-common.h       |   1 +
 5 files changed, 190 insertions(+), 336 deletions(-)

diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts
index 2003412..6fd9275 100644
--- a/arch/arm/dts/exynos5250-snow.dts
+++ b/arch/arm/dts/exynos5250-snow.dts
@@ -53,6 +53,14 @@
 		};
 	};
 
+	spi at 12d30000 {
+		spi-max-frequency = <50000000>;
+		firmware_storage_spi: flash at 0 {
+			compatible = "spi-flash";
+			reg = <0>;
+		};
+	};
+
 	spi at 131b0000 {
 		spi-max-frequency = <1000000>;
 		spi-deactivate-delay = <100>;
diff --git a/arch/arm/dts/exynos5420-peach-pit.dts b/arch/arm/dts/exynos5420-peach-pit.dts
index c4c4b8e..fde863d 100644
--- a/arch/arm/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/dts/exynos5420-peach-pit.dts
@@ -140,6 +140,7 @@
 	spi at 12d30000 { /* spi1 */
 		spi-max-frequency = <50000000>;
 		firmware_storage_spi: flash at 0 {
+			compatible = "spi-flash";
 			reg = <0>;
 
 			/*
diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c
index c119641..e1fc123 100644
--- a/board/samsung/common/board.c
+++ b/board/samsung/common/board.c
@@ -87,9 +87,6 @@ int board_init(void)
 	boot_temp_check();
 #endif
 
-#ifdef CONFIG_EXYNOS_SPI
-	spi_init();
-#endif
 	return exynos_init();
 }
 
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index 2969184..f078973 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -6,6 +6,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <malloc.h>
 #include <spi.h>
 #include <fdtdec.h>
@@ -19,176 +21,35 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* Information about each SPI controller */
-struct spi_bus {
+struct exynos_spi_platdata {
 	enum periph_id periph_id;
 	s32 frequency;		/* Default clock frequency, -1 for none */
 	struct exynos_spi *regs;
-	int inited;		/* 1 if this bus is ready for use */
-	int node;
 	uint deactivate_delay_us;	/* Delay to wait after deactivate */
 };
 
-/* A list of spi buses that we know about */
-static struct spi_bus spi_bus[EXYNOS5_SPI_NUM_CONTROLLERS];
-static unsigned int bus_count;
-
-struct exynos_spi_slave {
-	struct spi_slave slave;
+struct exynos_spi_priv {
 	struct exynos_spi *regs;
 	unsigned int freq;		/* Default frequency */
 	unsigned int mode;
 	enum periph_id periph_id;	/* Peripheral ID for this device */
 	unsigned int fifo_size;
 	int skip_preamble;
-	struct spi_bus *bus;		/* Pointer to our SPI bus info */
 	ulong last_transaction_us;	/* Time of last transaction end */
 };
 
-static struct spi_bus *spi_get_bus(unsigned dev_index)
-{
-	if (dev_index < bus_count)
-		return &spi_bus[dev_index];
-	debug("%s: invalid bus %d", __func__, dev_index);
-
-	return NULL;
-}
-
-static inline struct exynos_spi_slave *to_exynos_spi(struct spi_slave *slave)
-{
-	return container_of(slave, struct exynos_spi_slave, slave);
-}
-
-/**
- * Setup the driver private data
- *
- * @param bus		ID of the bus that the slave is attached to
- * @param cs		ID of the chip select connected to the slave
- * @param max_hz	Required spi frequency
- * @param mode		Required spi mode (clk polarity, clk phase and
- *			master or slave)
- * @return new device or NULL
- */
-struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
-			unsigned int max_hz, unsigned int mode)
-{
-	struct exynos_spi_slave *spi_slave;
-	struct spi_bus *bus;
-
-	if (!spi_cs_is_valid(busnum, cs)) {
-		debug("%s: Invalid bus/chip select %d, %d\n", __func__,
-		      busnum, cs);
-		return NULL;
-	}
-
-	spi_slave = spi_alloc_slave(struct exynos_spi_slave, busnum, cs);
-	if (!spi_slave) {
-		debug("%s: Could not allocate spi_slave\n", __func__);
-		return NULL;
-	}
-
-	bus = &spi_bus[busnum];
-	spi_slave->bus = bus;
-	spi_slave->regs = bus->regs;
-	spi_slave->mode = mode;
-	spi_slave->periph_id = bus->periph_id;
-	if (bus->periph_id == PERIPH_ID_SPI1 ||
-	    bus->periph_id == PERIPH_ID_SPI2)
-		spi_slave->fifo_size = 64;
-	else
-		spi_slave->fifo_size = 256;
-
-	spi_slave->skip_preamble = 0;
-	spi_slave->last_transaction_us = timer_get_us();
-
-	spi_slave->freq = bus->frequency;
-	if (max_hz)
-		spi_slave->freq = min(max_hz, spi_slave->freq);
-
-	return &spi_slave->slave;
-}
-
-/**
- * Free spi controller
- *
- * @param slave	Pointer to spi_slave to which controller has to
- *		communicate with
- */
-void spi_free_slave(struct spi_slave *slave)
-{
-	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-
-	free(spi_slave);
-}
-
 /**
  * Flush spi tx, rx fifos and reset the SPI controller
  *
- * @param slave	Pointer to spi_slave to which controller has to
- *		communicate with
+ * @param regs	Pointer to SPI registers
  */
-static void spi_flush_fifo(struct spi_slave *slave)
+static void spi_flush_fifo(struct exynos_spi *regs)
 {
-	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-	struct exynos_spi *regs = spi_slave->regs;
-
 	clrsetbits_le32(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
 	clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
 	setbits_le32(&regs->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
 }
 
-/**
- * Initialize the spi base registers, set the required clock frequency and
- * initialize the gpios
- *
- * @param slave	Pointer to spi_slave to which controller has to
- *		communicate with
- * @return zero on success else a negative value
- */
-int spi_claim_bus(struct spi_slave *slave)
-{
-	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-	struct exynos_spi *regs = spi_slave->regs;
-	u32 reg = 0;
-	int ret;
-
-	ret = set_spi_clk(spi_slave->periph_id,
-					spi_slave->freq);
-	if (ret < 0) {
-		debug("%s: Failed to setup spi clock\n", __func__);
-		return ret;
-	}
-
-	exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE);
-
-	spi_flush_fifo(slave);
-
-	reg = readl(&regs->ch_cfg);
-	reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
-
-	if (spi_slave->mode & SPI_CPHA)
-		reg |= SPI_CH_CPHA_B;
-
-	if (spi_slave->mode & SPI_CPOL)
-		reg |= SPI_CH_CPOL_L;
-
-	writel(reg, &regs->ch_cfg);
-	writel(SPI_FB_DELAY_180, &regs->fb_clk);
-
-	return 0;
-}
-
-/**
- * Reset the spi H/W and flush the tx and rx fifos
- *
- * @param slave	Pointer to spi_slave to which controller has to
- *		communicate with
- */
-void spi_release_bus(struct spi_slave *slave)
-{
-	spi_flush_fifo(slave);
-}
-
 static void spi_get_fifo_levels(struct exynos_spi *regs,
 	int *rx_lvl, int *tx_lvl)
 {
@@ -208,6 +69,8 @@ static void spi_get_fifo_levels(struct exynos_spi *regs,
  */
 static void spi_request_bytes(struct exynos_spi *regs, int count, int step)
 {
+	debug("%s: regs=%p, count=%d, step=%d\n", __func__, regs, count, step);
+
 	/* For word address we need to swap bytes */
 	if (step == 4) {
 		setbits_le32(&regs->mode_cfg,
@@ -230,10 +93,10 @@ static void spi_request_bytes(struct exynos_spi *regs, int count, int step)
 	writel(count | SPI_PACKET_CNT_EN, &regs->pkt_cnt);
 }
 
-static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
+static int spi_rx_tx(struct exynos_spi_priv *priv, int todo,
 			void **dinp, void const **doutp, unsigned long flags)
 {
-	struct exynos_spi *regs = spi_slave->regs;
+	struct exynos_spi *regs = priv->regs;
 	uchar *rxp = *dinp;
 	const uchar *txp = *doutp;
 	int rx_lvl, tx_lvl;
@@ -245,8 +108,8 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 
 	out_bytes = in_bytes = todo;
 
-	stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) &&
-					!(spi_slave->mode & SPI_SLAVE);
+	stopping = priv->skip_preamble && (flags & SPI_XFER_END) &&
+					!(priv->mode & SPI_SLAVE);
 
 	/*
 	 * Try to transfer words if we can. This helps read performance at
@@ -254,7 +117,7 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 	 */
 	step = 1;
 	if (!((todo | (uintptr_t)rxp | (uintptr_t)txp) & 3) &&
-	    !spi_slave->skip_preamble)
+	    !priv->skip_preamble)
 		step = 4;
 
 	/*
@@ -279,7 +142,7 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 		 * Don't completely fill the txfifo, since we don't want our
 		 * rxfifo to overflow, and it may already contain data.
 		 */
-		while (tx_lvl < spi_slave->fifo_size/2 && out_bytes) {
+		while (tx_lvl < priv->fifo_size/2 && out_bytes) {
 			if (!txp)
 				temp = -1;
 			else if (step == 4)
@@ -295,9 +158,9 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 		if (rx_lvl >= step) {
 			while (rx_lvl >= step) {
 				temp = readl(&regs->rx_data);
-				if (spi_slave->skip_preamble) {
+				if (priv->skip_preamble) {
 					if (temp == SPI_PREAMBLE_END_BYTE) {
-						spi_slave->skip_preamble = 0;
+						priv->skip_preamble = 0;
 						stopping = 0;
 					}
 				} else {
@@ -326,7 +189,7 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 			txp = NULL;
 			spi_request_bytes(regs, toread, step);
 		}
-		if (spi_slave->skip_preamble && get_timer(start) > 100) {
+		if (priv->skip_preamble && get_timer(start) > 100) {
 			printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
 			       in_bytes, out_bytes);
 			return -1;
@@ -340,94 +203,29 @@ static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo,
 }
 
 /**
- * Transfer and receive data
- *
- * @param slave		Pointer to spi_slave to which controller has to
- *			communicate with
- * @param bitlen	No of bits to tranfer or receive
- * @param dout		Pointer to transfer buffer
- * @param din		Pointer to receive buffer
- * @param flags		Flags for transfer begin and end
- * @return zero on success else a negative value
- */
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-	     void *din, unsigned long flags)
-{
-	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
-	int upto, todo;
-	int bytelen;
-	int ret = 0;
-
-	/* spi core configured to do 8 bit transfers */
-	if (bitlen % 8) {
-		debug("Non byte aligned SPI transfer.\n");
-		return -1;
-	}
-
-	/* Start the transaction, if necessary. */
-	if ((flags & SPI_XFER_BEGIN))
-		spi_cs_activate(slave);
-
-	/*
-	 * Exynos SPI limits each transfer to 65535 transfers. To keep
-	 * things simple, allow a maximum of 65532 bytes. We could allow
-	 * more in word mode, but the performance difference is small.
-	 */
-	bytelen =  bitlen / 8;
-	for (upto = 0; !ret && upto < bytelen; upto += todo) {
-		todo = min(bytelen - upto, (1 << 16) - 4);
-		ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags);
-		if (ret)
-			break;
-	}
-
-	/* Stop the transaction, if necessary. */
-	if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) {
-		spi_cs_deactivate(slave);
-		if (spi_slave->skip_preamble) {
-			assert(!spi_slave->skip_preamble);
-			debug("Failed to complete premable transaction\n");
-			ret = -1;
-		}
-	}
-
-	return ret;
-}
-
-/**
- * Validates the bus and chip select numbers
- *
- * @param bus	ID of the bus that the slave is attached to
- * @param cs	ID of the chip select connected to the slave
- * @return one on success else zero
- */
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-	return spi_get_bus(bus) && cs == 0;
-}
-
-/**
  * Activate the CS by driving it LOW
  *
  * @param slave	Pointer to spi_slave to which controller has to
  *		communicate with
  */
-void spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_activate(struct udevice *dev)
 {
-	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+	struct udevice *bus = dev->parent;
+	struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
 
 	/* If it's too soon to do another transaction, wait */
-	if (spi_slave->bus->deactivate_delay_us &&
-	    spi_slave->last_transaction_us) {
+	if (pdata->deactivate_delay_us &&
+	    priv->last_transaction_us) {
 		ulong delay_us;		/* The delay completed so far */
-		delay_us = timer_get_us() - spi_slave->last_transaction_us;
-		if (delay_us < spi_slave->bus->deactivate_delay_us)
-			udelay(spi_slave->bus->deactivate_delay_us - delay_us);
+		delay_us = timer_get_us() - priv->last_transaction_us;
+		if (delay_us < pdata->deactivate_delay_us)
+			udelay(pdata->deactivate_delay_us - delay_us);
 	}
 
-	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
-	debug("Activate CS, bus %d\n", spi_slave->slave.bus);
-	spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
+	clrbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+	debug("Activate CS, bus '%s'\n", bus->name);
+	priv->skip_preamble = priv->mode & SPI_PREAMBLE;
 }
 
 /**
@@ -436,148 +234,197 @@ void spi_cs_activate(struct spi_slave *slave)
  * @param slave	Pointer to spi_slave to which controller has to
  *		communicate with
  */
-void spi_cs_deactivate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+	struct udevice *bus = dev->parent;
+	struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
 
-	setbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+	setbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
 
 	/* Remember time of this transaction so we can honour the bus delay */
-	if (spi_slave->bus->deactivate_delay_us)
-		spi_slave->last_transaction_us = timer_get_us();
+	if (pdata->deactivate_delay_us)
+		priv->last_transaction_us = timer_get_us();
 
-	debug("Deactivate CS, bus %d\n", spi_slave->slave.bus);
+	debug("Deactivate CS, bus '%s'\n", bus->name);
 }
 
-static inline struct exynos_spi *get_spi_base(int dev_index)
+static int exynos_spi_ofdata_to_platdata(struct udevice *bus)
 {
-	if (dev_index < 3)
-		return (struct exynos_spi *)samsung_get_base_spi() + dev_index;
-	else
-		return (struct exynos_spi *)samsung_get_base_spi_isp() +
-					(dev_index - 3);
-}
+	struct exynos_spi_platdata *plat = bus->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = bus->of_offset;
 
-/*
- * Read the SPI config from the device tree node.
- *
- * @param blob  FDT blob to read from
- * @param node  Node offset to read from
- * @param bus   SPI bus structure to fill with information
- * @return 0 if ok, or -FDT_ERR_NOTFOUND if something was missing
- */
-#ifdef CONFIG_OF_CONTROL
-static int spi_get_config(const void *blob, int node, struct spi_bus *bus)
-{
-	bus->node = node;
-	bus->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
-	bus->periph_id = pinmux_decode_periph_id(blob, node);
+	plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
+	plat->periph_id = pinmux_decode_periph_id(blob, node);
 
-	if (bus->periph_id == PERIPH_ID_NONE) {
+	if (plat->periph_id == PERIPH_ID_NONE) {
 		debug("%s: Invalid peripheral ID %d\n", __func__,
-			bus->periph_id);
+			plat->periph_id);
 		return -FDT_ERR_NOTFOUND;
 	}
 
 	/* Use 500KHz as a suitable default */
-	bus->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
 					500000);
-	bus->deactivate_delay_us = fdtdec_get_int(blob, node,
+	plat->deactivate_delay_us = fdtdec_get_int(blob, node,
 					"spi-deactivate-delay", 0);
+	debug("%s: regs=%p, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+	      __func__, plat->regs, plat->periph_id, plat->frequency,
+	      plat->deactivate_delay_us);
 
 	return 0;
 }
 
-/*
- * Process a list of nodes, adding them to our list of SPI ports.
- *
- * @param blob          fdt blob
- * @param node_list     list of nodes to process (any <=0 are ignored)
- * @param count         number of nodes to process
- * @param is_dvc        1 if these are DVC ports, 0 if standard I2C
- * @return 0 if ok, -1 on error
- */
-static int process_nodes(const void *blob, int node_list[], int count)
+static int exynos_spi_probe(struct udevice *bus)
 {
-	int i;
+	struct exynos_spi_platdata *plat = dev_get_platdata(bus);
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
 
-	/* build the i2c_controllers[] for each controller */
-	for (i = 0; i < count; i++) {
-		int node = node_list[i];
-		struct spi_bus *bus;
+	priv->regs = plat->regs;
+	if (plat->periph_id == PERIPH_ID_SPI1 ||
+	    plat->periph_id == PERIPH_ID_SPI2)
+		priv->fifo_size = 64;
+	else
+		priv->fifo_size = 256;
 
-		if (node <= 0)
-			continue;
+	priv->skip_preamble = 0;
+	priv->last_transaction_us = timer_get_us();
+	priv->freq = plat->frequency;
+	priv->periph_id = plat->periph_id;
 
-		bus = &spi_bus[i];
-		if (spi_get_config(blob, node, bus)) {
-			printf("exynos spi_init: failed to decode bus %d\n",
-				i);
-			return -1;
-		}
+	return 0;
+}
 
-		debug("spi: controller bus %d at %p, periph_id %d\n",
-		      i, bus->regs, bus->periph_id);
-		bus->inited = 1;
-		bus_count++;
-	}
+static int exynos_spi_claim_bus(struct udevice *bus)
+{
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+	exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
+	spi_flush_fifo(priv->regs);
+
+	writel(SPI_FB_DELAY_180, &priv->regs->fb_clk);
 
 	return 0;
 }
-#endif
 
-/**
- * Set up a new SPI slave for an fdt node
- *
- * @param blob		Device tree blob
- * @param node		SPI peripheral node to use
- * @return 0 if ok, -1 on error
- */
-struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
-				      int spi_node)
+static int exynos_spi_release_bus(struct udevice *bus)
 {
-	struct spi_bus *bus;
-	unsigned int i;
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+	spi_flush_fifo(priv->regs);
+
+	return 0;
+}
+
+static int exynos_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			   const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev->parent;
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+	int upto, todo;
+	int bytelen;
+	int ret = 0;
+
+	/* spi core configured to do 8 bit transfers */
+	if (bitlen % 8) {
+		debug("Non byte aligned SPI transfer.\n");
+		return -1;
+	}
+
+	/* Start the transaction, if necessary. */
+	if ((flags & SPI_XFER_BEGIN))
+		spi_cs_activate(dev);
+
+	/*
+	 * Exynos SPI limits each transfer to 65535 transfers. To keep
+	 * things simple, allow a maximum of 65532 bytes. We could allow
+	 * more in word mode, but the performance difference is small.
+	 */
+	bytelen = bitlen / 8;
+	for (upto = 0; !ret && upto < bytelen; upto += todo) {
+		todo = min(bytelen - upto, (1 << 16) - 4);
+		ret = spi_rx_tx(priv, todo, &din, &dout, flags);
+		if (ret)
+			break;
+	}
 
-	for (i = 0, bus = spi_bus; i < bus_count; i++, bus++) {
-		if (bus->node == spi_node)
-			return spi_base_setup_slave_fdt(blob, i, slave_node);
+	/* Stop the transaction, if necessary. */
+	if ((flags & SPI_XFER_END) && !(priv->mode & SPI_SLAVE)) {
+		spi_cs_deactivate(dev);
+		if (priv->skip_preamble) {
+			assert(!priv->skip_preamble);
+			debug("Failed to complete premable transaction\n");
+			ret = -1;
+		}
 	}
 
-	debug("%s: Failed to find bus node %d\n", __func__, spi_node);
-	return NULL;
+	return ret;
 }
 
-/* Sadly there is no error return from this function */
-void spi_init(void)
+static int exynos_spi_set_speed(struct udevice *bus, uint speed)
 {
-	int count;
+	struct exynos_spi_platdata *plat = bus->platdata;
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+	int ret;
 
-#ifdef CONFIG_OF_CONTROL
-	int node_list[EXYNOS5_SPI_NUM_CONTROLLERS];
-	const void *blob = gd->fdt_blob;
+	if (speed > plat->frequency)
+		speed = plat->frequency;
+	ret = set_spi_clk(priv->periph_id, speed);
+	if (ret)
+		return ret;
+	priv->freq = speed;
+	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+	return 0;
+}
 
-	count = fdtdec_find_aliases_for_id(blob, "spi",
-			COMPAT_SAMSUNG_EXYNOS_SPI, node_list,
-			EXYNOS5_SPI_NUM_CONTROLLERS);
-	if (process_nodes(blob, node_list, count))
-		return;
+static int exynos_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+	uint32_t reg;
 
-#else
-	struct spi_bus *bus;
+	reg = readl(&priv->regs->ch_cfg);
+	reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
 
-	for (count = 0; count < EXYNOS5_SPI_NUM_CONTROLLERS; count++) {
-		bus = &spi_bus[count];
-		bus->regs = get_spi_base(count);
-		bus->periph_id = PERIPH_ID_SPI0 + count;
+	if (mode & SPI_CPHA)
+		reg |= SPI_CH_CPHA_B;
 
-		/* Although Exynos5 supports upto 50Mhz speed,
-		 * we are setting it to 10Mhz for safe side
-		 */
-		bus->frequency = 10000000;
-		bus->inited = 1;
-		bus->node = 0;
-		bus_count = EXYNOS5_SPI_NUM_CONTROLLERS;
-	}
-#endif
+	if (mode & SPI_CPOL)
+		reg |= SPI_CH_CPOL_L;
+
+	writel(reg, &priv->regs->ch_cfg);
+	priv->mode = mode;
+	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+	return 0;
 }
+
+static const struct dm_spi_ops exynos_spi_ops = {
+	.claim_bus	= exynos_spi_claim_bus,
+	.release_bus	= exynos_spi_release_bus,
+	.xfer		= exynos_spi_xfer,
+	.set_speed	= exynos_spi_set_speed,
+	.set_mode	= exynos_spi_set_mode,
+	/*
+	 * cs_info is not needed, since we require all chip selects to be
+	 * in the device tree explicitly
+	 */
+};
+
+static const struct udevice_id exynos_spi_ids[] = {
+	{ .compatible = "samsung,exynos-spi" },
+	{ }
+};
+
+U_BOOT_DRIVER(exynos_spi) = {
+	.name	= "exynos_spi",
+	.id	= UCLASS_SPI,
+	.of_match = exynos_spi_ids,
+	.ops	= &exynos_spi_ops,
+	.ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
+	.priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
+	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
+	.probe	= exynos_spi_probe,
+};
diff --git a/include/configs/exynos-common.h b/include/configs/exynos-common.h
index 34a162d..eb6745e 100644
--- a/include/configs/exynos-common.h
+++ b/include/configs/exynos-common.h
@@ -21,6 +21,7 @@
 #define CONFIG_CMD_DM
 #define CONFIG_DM_GPIO
 #define CONFIG_DM_SERIAL
+#define CONFIG_DM_SPI
 
 #define CONFIG_ARCH_CPU_INIT
 #define CONFIG_DISPLAY_CPUINFO
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 15/29] dm: spi: Add documentation on how to convert over SPI drivers
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (13 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 14/29] dm: exynos: Convert SPI to driver model Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 16/29] exynos: universal_c210: Move to driver model soft_spi Simon Glass
                   ` (15 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

This README is intended to help maintainers move their SPI drivers over to
driver model. It works through the required steps with an example.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Update for the new cs_info() method

Changes in v2:
- Fix typos reported by Jagannadha Sutradharudu Teki
- Update for changes to exynos driver

 doc/driver-model/spi-howto.txt | 594 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 594 insertions(+)
 create mode 100644 doc/driver-model/spi-howto.txt

diff --git a/doc/driver-model/spi-howto.txt b/doc/driver-model/spi-howto.txt
new file mode 100644
index 0000000..719dbd5
--- /dev/null
+++ b/doc/driver-model/spi-howto.txt
@@ -0,0 +1,594 @@
+How to port a SPI driver to driver model
+========================================
+
+Here is a rough step-by-step guide. It is based around converting the
+exynos SPI driver to driver model (DM) and the example code is based
+around U-Boot v2014.10-rc2 (commit be9f643).
+
+It is quite long since it includes actual code examples.
+
+Before driver model, SPI drivers have their own private structure which
+contains 'struct spi_slave'. With driver model, 'struct spi_slave' still
+exists, but now it is 'per-child data' for the SPI bus. Each child of the
+SPI bus is a SPI slave. The information that was stored in the
+driver-specific slave structure can now be port in private data for the
+SPI bus.
+
+For example, struct tegra_spi_slave looks like this:
+
+struct tegra_spi_slave {
+	struct spi_slave slave;
+	struct tegra_spi_ctrl *ctrl;
+};
+
+In this case 'slave' will be in per-child data, and 'ctrl' will be in the
+SPI's buses private data.
+
+
+0. How long does this take?
+
+You should be able to complete this within 2 hours, including testing but
+excluding preparing the patches. The API is basically the same as before
+with only minor changes:
+
+- methods to set speed and mode are separated out
+- cs_info is used to get information on a chip select
+
+
+1. Enable driver mode for SPI and SPI flash
+
+Add these to your board config:
+
+#define CONFIG_DM_SPI
+#define CONFIG_DM_SPI_FLASH
+
+
+2. Add the skeleton
+
+Put this code at the bottom of your existing driver file:
+
+struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
+			unsigned int max_hz, unsigned int mode)
+{
+	return NULL;
+}
+
+struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
+				      int spi_node)
+{
+	return NULL;
+}
+
+static int exynos_spi_ofdata_to_platdata(struct udevice *dev)
+{
+	return -ENODEV;
+}
+
+static int exynos_spi_probe(struct udevice *dev)
+{
+	return -ENODEV;
+}
+
+static int exynos_spi_remove(struct udevice *dev)
+{
+	return -ENODEV;
+}
+
+static int exynos_spi_claim_bus(struct udevice *dev)
+{
+
+	return -ENODEV;
+}
+
+static int exynos_spi_release_bus(struct udevice *dev)
+{
+
+	return -ENODEV;
+}
+
+static int exynos_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			    const void *dout, void *din, unsigned long flags)
+{
+
+	return -ENODEV;
+}
+
+static int exynos_spi_set_speed(struct udevice *dev, uint speed)
+{
+	return -ENODEV;
+}
+
+static int exynos_spi_set_mode(struct udevice *dev, uint mode)
+{
+	return -ENODEV;
+}
+
+static int exynos_cs_info(struct udevice *bus, uint cs,
+			  struct spi_cs_info *info)
+{
+	return -ENODEV;
+}
+
+static const struct dm_spi_ops exynos_spi_ops = {
+	.claim_bus	= exynos_spi_claim_bus,
+	.release_bus	= exynos_spi_release_bus,
+	.xfer		= exynos_spi_xfer,
+	.set_speed	= exynos_spi_set_speed,
+	.set_mode	= exynos_spi_set_mode,
+	.cs_info	= exynos_cs_info,
+};
+
+static const struct udevice_id exynos_spi_ids[] = {
+	{ .compatible = "samsung,exynos-spi" },
+	{ }
+};
+
+U_BOOT_DRIVER(exynos_spi) = {
+	.name	= "exynos_spi",
+	.id	= UCLASS_SPI,
+	.of_match = exynos_spi_ids,
+	.ops	= &exynos_spi_ops,
+	.ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
+	.probe	= exynos_spi_probe,
+	.remove	= exynos_spi_remove,
+};
+
+
+3. Replace 'exynos' in the above code with your driver name
+
+
+4. #ifdef out all of the code in your driver except for the above
+
+This will allow you to get it building, which means you can work
+incrementally. Since all the methods return an error initially, there is
+less chance that you will accidentally leave something in.
+
+Also, even though your conversion is basically a rewrite, it might help
+reviewers if you leave functions in the same place in the file,
+particularly for large drivers.
+
+
+5. Add some includes
+
+Add these includes to your driver:
+
+#include <dm.h>
+#include <errno.h>
+
+
+6. Build
+
+At this point you should be able to build U-Boot for your board with the
+empty SPI driver. You still have empty methods in your driver, but we will
+write these one by one.
+
+If you have spi_init() functions or the like that are called from your
+board then the build will fail. Remove these calls and make a note of the
+init that needs to be done.
+
+
+7. Set up your platform data structure
+
+This will hold the information your driver to operate, like its hardware
+address or maximum frequency.
+
+You may already have a struct like this, or you may need to create one
+from some of the #defines or global variables in the driver.
+
+Note that this information is not the run-time information. It should not
+include state that changes. It should be fixed throughout the live of
+U-Boot. Run-time information comes later.
+
+Here is what was in the exynos spi driver:
+
+struct spi_bus {
+	enum periph_id periph_id;
+	s32 frequency;		/* Default clock frequency, -1 for none */
+	struct exynos_spi *regs;
+	int inited;		/* 1 if this bus is ready for use */
+	int node;
+	uint deactivate_delay_us;	/* Delay to wait after deactivate */
+};
+
+Of these, inited is handled by DM and node is the device tree node, which
+DM tells you. The name is not quite right. So in this case we would use:
+
+struct exynos_spi_platdata {
+	enum periph_id periph_id;
+	s32 frequency;		/* Default clock frequency, -1 for none */
+	struct exynos_spi *regs;
+	uint deactivate_delay_us;	/* Delay to wait after deactivate */
+};
+
+
+8a. Write ofdata_to_platdata()   [for device tree only]
+
+This method will convert information in the device tree node into a C
+structure in your driver (called platform data). If you are not using
+device tree, go to 8b.
+
+DM will automatically allocate the struct for us when we are using device
+tree, but we need to tell it the size:
+
+U_BOOT_DRIVER(spi_exynos) = {
+...
+	.platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
+
+
+Here is a sample function. It gets a pointer to the platform data and
+fills in the fields from device tree.
+
+static int exynos_spi_ofdata_to_platdata(struct udevice *bus)
+{
+	struct exynos_spi_platdata *plat = bus->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = bus->of_offset;
+
+	plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
+	plat->periph_id = pinmux_decode_periph_id(blob, node);
+
+	if (plat->periph_id == PERIPH_ID_NONE) {
+		debug("%s: Invalid peripheral ID %d\n", __func__,
+			plat->periph_id);
+		return -FDT_ERR_NOTFOUND;
+	}
+
+	/* Use 500KHz as a suitable default */
+	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+					500000);
+	plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+					"spi-deactivate-delay", 0);
+	debug("%s: regs=%p, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+	      __func__, plat->regs, plat->periph_id, plat->frequency,
+              plat->deactivate_delay_us);
+
+	return 0;
+}
+
+
+8b. Add the platform data  [non-device-tree only]
+
+Specify this data in a U_BOOT_DEVICE() declaration in your board file:
+
+struct exynos_spi_platdata platdata_spi0 = {
+	.periph_id = ...
+	.frequency = ...
+	.regs = ...
+	.deactivate_delay_us = ...
+};
+
+U_BOOT_DEVICE(board_spi0) = {
+	.name = "exynos_spi",
+	.platdata = &platdata_spi0,
+};
+
+You will unfortunately need to put the struct into a header file in this
+case so that your board file can use it.
+
+
+9. Add the device private data
+
+Most devices have some private data which they use to keep track of things
+while active. This is the run-time information and needs to be stored in
+a structure. There is probably a structure in the driver that includes a
+'struct spi_slave', so you can use that.
+
+struct exynos_spi_slave {
+	struct spi_slave slave;
+	struct exynos_spi *regs;
+	unsigned int freq;		/* Default frequency */
+	unsigned int mode;
+	enum periph_id periph_id;	/* Peripheral ID for this device */
+	unsigned int fifo_size;
+	int skip_preamble;
+	struct spi_bus *bus;		/* Pointer to our SPI bus info */
+	ulong last_transaction_us;	/* Time of last transaction end */
+};
+
+
+We should rename this to make its purpose more obvious, and get rid of
+the slave structure, so we have:
+
+struct exynos_spi_priv {
+	struct exynos_spi *regs;
+	unsigned int freq;		/* Default frequency */
+	unsigned int mode;
+	enum periph_id periph_id;	/* Peripheral ID for this device */
+	unsigned int fifo_size;
+	int skip_preamble;
+	ulong last_transaction_us;	/* Time of last transaction end */
+};
+
+
+DM can auto-allocate this also:
+
+U_BOOT_DRIVER(spi_exynos) = {
+...
+	.priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
+
+
+Note that this is created before the probe method is called, and destroyed
+after the remove method is called. It will be zeroed when the probe
+method is called.
+
+
+10. Add the probe() and remove() methods
+
+Note: It's a good idea to build repeatedly as you are working, to avoid a
+huge amount of work getting things compiling at the end.
+
+The probe method is supposed to set up the hardware. U-Boot used to use
+spi_setup_slave() to do this. So take a look at this function and see
+what you can copy out to set things up.
+
+
+static int exynos_spi_probe(struct udevice *bus)
+{
+	struct exynos_spi_platdata *plat = dev_get_platdata(bus);
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+	priv->regs = plat->regs;
+	if (plat->periph_id == PERIPH_ID_SPI1 ||
+	    plat->periph_id == PERIPH_ID_SPI2)
+		priv->fifo_size = 64;
+	else
+		priv->fifo_size = 256;
+
+	priv->skip_preamble = 0;
+	priv->last_transaction_us = timer_get_us();
+	priv->freq = plat->frequency;
+	priv->periph_id = plat->periph_id;
+
+	return 0;
+}
+
+This implementation doesn't actually touch the hardware, which is somewhat
+unusual for a driver. In this case we will do that when the device is
+claimed by something that wants to use the SPI bus.
+
+For remove we could shut down the clocks, but in this case there is
+nothing to do. DM frees any memory that it allocated, so we can just
+remove exynos_spi_remove() and its reference in U_BOOT_DRIVER.
+
+
+11. Implement set_speed()
+
+This should set up clocks so that the SPI bus is running at the right
+speed. With the old API spi_claim_bus() would normally do this and several
+of the following functions, so let's look at that function:
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+	struct exynos_spi *regs = spi_slave->regs;
+	u32 reg = 0;
+	int ret;
+
+	ret = set_spi_clk(spi_slave->periph_id,
+					spi_slave->freq);
+	if (ret < 0) {
+		debug("%s: Failed to setup spi clock\n", __func__);
+		return ret;
+	}
+
+	exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE);
+
+	spi_flush_fifo(slave);
+
+	reg = readl(&regs->ch_cfg);
+	reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
+
+	if (spi_slave->mode & SPI_CPHA)
+		reg |= SPI_CH_CPHA_B;
+
+	if (spi_slave->mode & SPI_CPOL)
+		reg |= SPI_CH_CPOL_L;
+
+	writel(reg, &regs->ch_cfg);
+	writel(SPI_FB_DELAY_180, &regs->fb_clk);
+
+	return 0;
+}
+
+
+It sets up the speed, mode, pinmux, feedback delay and clears the FIFOs.
+With DM these will happen in separate methods.
+
+
+Here is an example for the speed part:
+
+static int exynos_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct exynos_spi_platdata *plat = bus->platdata;
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+	int ret;
+
+	if (speed > plat->frequency)
+		speed = plat->frequency;
+	ret = set_spi_clk(priv->periph_id, speed);
+	if (ret)
+		return ret;
+	priv->freq = speed;
+	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+	return 0;
+}
+
+
+12. Implement set_mode()
+
+This should adjust the SPI mode (polarity, etc.). Again this code probably
+comes from the old spi_claim_bus(). Here is an example:
+
+
+static int exynos_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+	uint32_t reg;
+
+	reg = readl(&priv->regs->ch_cfg);
+	reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
+
+	if (mode & SPI_CPHA)
+		reg |= SPI_CH_CPHA_B;
+
+	if (mode & SPI_CPOL)
+		reg |= SPI_CH_CPOL_L;
+
+	writel(reg, &priv->regs->ch_cfg);
+	priv->mode = mode;
+	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+	return 0;
+}
+
+
+13. Implement claim_bus()
+
+This is where a client wants to make use of the bus, so claims it first.
+At this point we need to make sure everything is set up ready for data
+transfer. Note that this function is wholly internal to the driver - at
+present the SPI uclass never calls it.
+
+Here again we look at the old claim function and see some code that is
+needed. It is anything unrelated to speed and mode:
+
+static int exynos_spi_claim_bus(struct udevice *bus)
+{
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+	exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
+	spi_flush_fifo(priv->regs);
+
+	writel(SPI_FB_DELAY_180, &priv->regs->fb_clk);
+
+	return 0;
+}
+
+The spi_flush_fifo() function is in the removed part of the code, so we
+need to expose it again (perhaps with an #endif before it and '#if 0'
+after it). It only needs access to priv->regs which is why we have
+passed that in:
+
+/**
+ * Flush spi tx, rx fifos and reset the SPI controller
+ *
+ * @param regs	Pointer to SPI registers
+ */
+static void spi_flush_fifo(struct exynos_spi *regs)
+{
+	clrsetbits_le32(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
+	clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
+	setbits_le32(&regs->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
+}
+
+
+14. Implement release_bus()
+
+This releases the bus - in our example the old code in spi_release_bus()
+is a call to spi_flush_fifo, so we add:
+
+static int exynos_spi_release_bus(struct udevice *bus)
+{
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+	spi_flush_fifo(priv->regs);
+
+	return 0;
+}
+
+
+15. Implement xfer()
+
+This is the final method that we need to create, and it is where all the
+work happens. The method parameters are the same as the old spi_xfer() with
+the addition of a 'struct udevice' so conversion is pretty easy. Start
+by copying the contents of spi_xfer() to your new xfer() method and proceed
+from there.
+
+If (flags & SPI_XFER_BEGIN) is non-zero then xfer() normally calls an
+activate function, something like this:
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
+
+	/* If it's too soon to do another transaction, wait */
+	if (spi_slave->bus->deactivate_delay_us &&
+	    spi_slave->last_transaction_us) {
+		ulong delay_us;		/* The delay completed so far */
+		delay_us = timer_get_us() - spi_slave->last_transaction_us;
+		if (delay_us < spi_slave->bus->deactivate_delay_us)
+			udelay(spi_slave->bus->deactivate_delay_us - delay_us);
+	}
+
+	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+	debug("Activate CS, bus %d\n", spi_slave->slave.bus);
+	spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
+}
+
+The new version looks like this:
+
+static void spi_cs_activate(struct udevice *dev)
+{
+	struct udevice *bus = dev->parent;
+	struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
+	struct exynos_spi_priv *priv = dev_get_priv(bus);
+
+	/* If it's too soon to do another transaction, wait */
+	if (pdata->deactivate_delay_us &&
+	    priv->last_transaction_us) {
+		ulong delay_us;		/* The delay completed so far */
+		delay_us = timer_get_us() - priv->last_transaction_us;
+		if (delay_us < pdata->deactivate_delay_us)
+			udelay(pdata->deactivate_delay_us - delay_us);
+	}
+
+	clrbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
+	debug("Activate CS, bus '%s'\n", bus->name);
+	priv->skip_preamble = priv->mode & SPI_PREAMBLE;
+}
+
+All we have really done here is change the pointers and print the device name
+instead of the bus number. Other local static functions can be treated in
+the same way.
+
+
+16. Set up the per-child data and child pre-probe function
+
+To minimise the pain and complexity of the SPI subsystem while the driver
+model change-over is in place, struct spi_slave is used to reference a
+SPI bus slave, even though that slave is actually a struct udevice. In fact
+struct spi_slave is the device's child data. We need to make sure this space
+is available. It is possible to allocate more space that struct spi_slave
+needs, but this is the minimum.
+
+U_BOOT_DRIVER(exynos_spi) = {
+...
+	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
+}
+
+
+17. Optional: Set up cs_info() if you want it
+
+Sometimes it is useful to know whether a SPI chip select is valid, but this
+is not obvious from outside the driver. In this case you can provide a
+method for cs_info() to deal with this. If you don't provide it, then the
+device tree will be used to determine what chip selects are valid.
+
+Return -ENODEV if the supplied chip select is invalid, or 0 if it is valid.
+If you don't provide the cs_info() method, -ENODEV is assumed for all
+chip selects that do not appear in the device tree.
+
+
+18. Test it
+
+Now that you have the code written and it compiles, try testing it using
+the 'sf test' command. You may need to enable CONFIG_CMD_SF_TEST for your
+board.
+
+
+19. Prepare patches and send them to the mailing lists
+
+You can use 'tools/patman/patman' to prepare, check and send patches for
+your work. See the README for details.
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 16/29] exynos: universal_c210: Move to driver model soft_spi
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (14 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 15/29] dm: spi: Add documentation on how to convert over SPI drivers Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 17/29] sf: Tidy up public and private header files Simon Glass
                   ` (14 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Adjust this board to use the driver model soft_spi implementation.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 arch/arm/dts/exynos4210-universal_c210.dts | 13 ++++++++
 board/samsung/universal_c210/universal.c   | 52 ------------------------------
 include/configs/s5pc210_universal.h        | 11 +------
 3 files changed, 14 insertions(+), 62 deletions(-)

diff --git a/arch/arm/dts/exynos4210-universal_c210.dts b/arch/arm/dts/exynos4210-universal_c210.dts
index cf3354f..9139810 100644
--- a/arch/arm/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/dts/exynos4210-universal_c210.dts
@@ -41,6 +41,19 @@
 		status = "disabled";
 	};
 
+	soft-spi {
+		compatible = "u-boot,soft-spi";
+		cs-gpio = <&gpio 235 0>;	/* Y43 */
+		sclk-gpio = <&gpio 225 0>;	/* Y31 */
+		mosi-gpio = <&gpio 227 0>;	/* Y33 */
+		miso-gpio = <&gpio 224 0>;	/* Y30 */
+		spi-delay-us = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		cs at 0 {
+		};
+	};
+
 	fimd at 11c00000 {
 		compatible = "samsung,exynos-fimd";
 		reg = <0x11c00000 0xa4>;
diff --git a/board/samsung/universal_c210/universal.c b/board/samsung/universal_c210/universal.c
index c04f48c..22b0849 100644
--- a/board/samsung/universal_c210/universal.c
+++ b/board/samsung/universal_c210/universal.c
@@ -201,53 +201,6 @@ int exynos_early_init_f(void)
 	return 0;
 }
 
-#ifdef CONFIG_SOFT_SPI
-static void soft_spi_init(void)
-{
-	gpio_direction_output(CONFIG_SOFT_SPI_GPIO_SCLK,
-		CONFIG_SOFT_SPI_MODE & SPI_CPOL);
-	gpio_direction_output(CONFIG_SOFT_SPI_GPIO_MOSI, 1);
-	gpio_direction_input(CONFIG_SOFT_SPI_GPIO_MISO);
-	gpio_direction_output(CONFIG_SOFT_SPI_GPIO_CS,
-		!(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH));
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
-	gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS,
-		!(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH));
-	SPI_SCL(1);
-	gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS,
-		CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
-	gpio_set_value(CONFIG_SOFT_SPI_GPIO_CS,
-		!(CONFIG_SOFT_SPI_MODE & SPI_CS_HIGH));
-}
-
-int  spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-	return bus == 0 && cs == 0;
-}
-
-void universal_spi_scl(int bit)
-{
-	gpio_set_value(CONFIG_SOFT_SPI_GPIO_SCLK, bit);
-}
-
-void universal_spi_sda(int bit)
-{
-	gpio_set_value(CONFIG_SOFT_SPI_GPIO_MOSI, bit);
-}
-
-int universal_spi_read(void)
-{
-	return gpio_get_value(CONFIG_SOFT_SPI_GPIO_MISO);
-}
-#endif
-
 static void init_pmic_lcd(void)
 {
 	unsigned char val;
@@ -332,8 +285,6 @@ void exynos_cfg_lcd_gpio(void)
 	/* gpio pad configuration for LCD reset. */
 	gpio_request(EXYNOS4_GPIO_Y45, "lcd_reset");
 	gpio_cfg_pin(EXYNOS4_GPIO_Y45, S5P_GPIO_OUTPUT);
-
-	spi_init();
 }
 
 int mipi_power(void)
@@ -401,9 +352,6 @@ int exynos_init(void)
 		break;
 	}
 
-#ifdef CONFIG_SOFT_SPI
-	soft_spi_init();
-#endif
 	check_hw_revision();
 	printf("HW Revision:\t0x%x\n", board_rev);
 
diff --git a/include/configs/s5pc210_universal.h b/include/configs/s5pc210_universal.h
index 4fa8d66..4b30d14 100644
--- a/include/configs/s5pc210_universal.h
+++ b/include/configs/s5pc210_universal.h
@@ -187,16 +187,7 @@
  * SPI Settings
  */
 #define CONFIG_SOFT_SPI
-#define CONFIG_SOFT_SPI_MODE SPI_MODE_3
-#define CONFIG_SOFT_SPI_GPIO_SCLK EXYNOS4_GPIO_Y31
-#define CONFIG_SOFT_SPI_GPIO_MOSI EXYNOS4_GPIO_Y33
-#define CONFIG_SOFT_SPI_GPIO_MISO EXYNOS4_GPIO_Y30
-#define CONFIG_SOFT_SPI_GPIO_CS EXYNOS4_GPIO_Y43
-
-#define SPI_DELAY udelay(1)
-#define SPI_SCL(bit) universal_spi_scl(bit)
-#define SPI_SDA(bit) universal_spi_sda(bit)
-#define SPI_READ universal_spi_read()
+
 #ifndef	__ASSEMBLY__
 void universal_spi_scl(int bit);
 void universal_spi_sda(int bit);
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 17/29] sf: Tidy up public and private header files
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (15 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 16/29] exynos: universal_c210: Move to driver model soft_spi Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 18/29] spi: Use error return value in sf_ops Simon Glass
                   ` (13 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Since spi_flash.h is supposed to be the public API for SPI flash, move
private things to sf_internal.h. Also tidy up a few comment nits.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add spi.h header to 3 sh boards
- Rebase to master

Changes in v2: None

 board/buffalo/lsxl/lsxl.c           |  3 +-
 board/renesas/sh7752evb/sh7752evb.c |  1 +
 board/renesas/sh7753evb/sh7753evb.c |  1 +
 board/renesas/sh7757lcr/sh7757lcr.c |  1 +
 common/cmd_sf.c                     |  1 +
 drivers/mtd/spi/ramtron.c           |  1 +
 drivers/mtd/spi/sf_internal.h       | 67 +++++++++++++++++++++++++++++++++----
 drivers/mtd/spi/spi_spl_load.c      |  1 +
 include/spi_flash.h                 | 57 +++----------------------------
 9 files changed, 73 insertions(+), 60 deletions(-)

diff --git a/board/buffalo/lsxl/lsxl.c b/board/buffalo/lsxl/lsxl.c
index 659a124..c1cb07b 100644
--- a/board/buffalo/lsxl/lsxl.c
+++ b/board/buffalo/lsxl/lsxl.c
@@ -13,11 +13,12 @@
 #include <malloc.h>
 #include <netdev.h>
 #include <miiphy.h>
+#include <spi.h>
+#include <spi_flash.h>
 #include <asm/arch/kirkwood.h>
 #include <asm/arch/cpu.h>
 #include <asm/arch/mpp.h>
 #include <asm/arch/gpio.h>
-#include <spi_flash.h>
 
 #include "lsxl.h"
 
diff --git a/board/renesas/sh7752evb/sh7752evb.c b/board/renesas/sh7752evb/sh7752evb.c
index 5eedbf8..3aad532 100644
--- a/board/renesas/sh7752evb/sh7752evb.c
+++ b/board/renesas/sh7752evb/sh7752evb.c
@@ -9,6 +9,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/mmc.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 int checkboard(void)
diff --git a/board/renesas/sh7753evb/sh7753evb.c b/board/renesas/sh7753evb/sh7753evb.c
index 42b920f..9f64945 100644
--- a/board/renesas/sh7753evb/sh7753evb.c
+++ b/board/renesas/sh7753evb/sh7753evb.c
@@ -9,6 +9,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/mmc.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 int checkboard(void)
diff --git a/board/renesas/sh7757lcr/sh7757lcr.c b/board/renesas/sh7757lcr/sh7757lcr.c
index 1464f48..ddcf275 100644
--- a/board/renesas/sh7757lcr/sh7757lcr.c
+++ b/board/renesas/sh7757lcr/sh7757lcr.c
@@ -9,6 +9,7 @@
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/mmc.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 int checkboard(void)
diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index c60e8d1..42d89d4 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -9,6 +9,7 @@
 #include <common.h>
 #include <div64.h>
 #include <malloc.h>
+#include <spi.h>
 #include <spi_flash.h>
 
 #include <asm/io.h>
diff --git a/drivers/mtd/spi/ramtron.c b/drivers/mtd/spi/ramtron.c
index d50da37..a23032c 100644
--- a/drivers/mtd/spi/ramtron.c
+++ b/drivers/mtd/spi/ramtron.c
@@ -35,6 +35,7 @@
 
 #include <common.h>
 #include <malloc.h>
+#include <spi.h>
 #include <spi_flash.h>
 #include "sf_internal.h"
 
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 19d4914..5b7670c 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -10,6 +10,36 @@
 #ifndef _SF_INTERNAL_H_
 #define _SF_INTERNAL_H_
 
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+/* Dual SPI flash memories - see SPI_COMM_DUAL_... */
+enum spi_dual_flash {
+	SF_SINGLE_FLASH	= 0,
+	SF_DUAL_STACKED_FLASH	= 1 << 0,
+	SF_DUAL_PARALLEL_FLASH	= 1 << 1,
+};
+
+/* Enum list - Full read commands */
+enum spi_read_cmds {
+	ARRAY_SLOW		= 1 << 0,
+	DUAL_OUTPUT_FAST	= 1 << 1,
+	DUAL_IO_FAST		= 1 << 2,
+	QUAD_OUTPUT_FAST	= 1 << 3,
+	QUAD_IO_FAST		= 1 << 4,
+};
+
+#define RD_EXTN	(ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+#define RD_FULL	(RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+
+/* sf param flags */
+enum {
+	SECT_4K		= 1 << 0,
+	SECT_32K	= 1 << 1,
+	E_FSR		= 1 << 2,
+	WR_QPP		= 1 << 3,
+};
+
 #define SPI_FLASH_3B_ADDR_LEN		3
 #define SPI_FLASH_CMD_LEN		(1 + SPI_FLASH_3B_ADDR_LEN)
 #define SPI_FLASH_16MB_BOUN		0x1000000
@@ -30,12 +60,12 @@
 #define CMD_WRITE_STATUS		0x01
 #define CMD_PAGE_PROGRAM		0x02
 #define CMD_WRITE_DISABLE		0x04
-#define CMD_READ_STATUS			0x05
+#define CMD_READ_STATUS		0x05
 #define CMD_QUAD_PAGE_PROGRAM		0x32
 #define CMD_READ_STATUS1		0x35
 #define CMD_WRITE_ENABLE		0x06
-#define CMD_READ_CONFIG			0x35
-#define CMD_FLAG_STATUS			0x70
+#define CMD_READ_CONFIG		0x35
+#define CMD_FLAG_STATUS		0x70
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW		0x03
@@ -57,7 +87,7 @@
 /* Common status */
 #define STATUS_WIP			(1 << 0)
 #define STATUS_QEB_WINSPAN		(1 << 1)
-#define STATUS_QEB_MXIC			(1 << 6)
+#define STATUS_QEB_MXIC		(1 << 6)
 #define STATUS_PEC			(1 << 7)
 
 #ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
@@ -66,19 +96,42 @@
 
 /* Flash timeout values */
 #define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ)
-#define SPI_FLASH_PAGE_ERASE_TIMEOUT	(5 * CONFIG_SYS_HZ)
+#define SPI_FLASH_PAGE_ERASE_TIMEOUT		(5 * CONFIG_SYS_HZ)
 #define SPI_FLASH_SECTOR_ERASE_TIMEOUT	(10 * CONFIG_SYS_HZ)
 
 /* SST specific */
 #ifdef CONFIG_SPI_FLASH_SST
-# define SST_WP			0x01	/* Supports AAI word program */
+# define SST_WP		0x01	/* Supports AAI word program */
 # define CMD_SST_BP		0x02    /* Byte Program */
-# define CMD_SST_AAI_WP		0xAD	/* Auto Address Incr Word Program */
+# define CMD_SST_AAI_WP	0xAD	/* Auto Address Incr Word Program */
 
 int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len,
 		const void *buf);
 #endif
 
+/**
+ * struct spi_flash_params - SPI/QSPI flash device params structure
+ *
+ * @name:		Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
+ * @jedec:		Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
+ * @ext_jedec:		Device ext_jedec ID
+ * @sector_size:	Sector size of this device
+ * @nr_sectors:	No.of sectors on this device
+ * @e_rd_cmd:		Enum list for read commands
+ * @flags:		Important param, for flash specific behaviour
+ */
+struct spi_flash_params {
+	const char *name;
+	u32 jedec;
+	u16 ext_jedec;
+	u32 sector_size;
+	u32 nr_sectors;
+	u8 e_rd_cmd;
+	u16 flags;
+};
+
+extern const struct spi_flash_params spi_flash_params_table[];
+
 /* Send a single-byte command to the device and read the response */
 int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len);
 
diff --git a/drivers/mtd/spi/spi_spl_load.c b/drivers/mtd/spi/spi_spl_load.c
index 59cca0f..2e0c871 100644
--- a/drivers/mtd/spi/spi_spl_load.c
+++ b/drivers/mtd/spi/spi_spl_load.c
@@ -10,6 +10,7 @@
  */
 
 #include <common.h>
+#include <spi.h>
 #include <spi_flash.h>
 #include <spl.h>
 
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 408a5b4..223e442 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -15,9 +15,7 @@
 #ifndef _SPI_FLASH_H_
 #define _SPI_FLASH_H_
 
-#include <spi.h>
 #include <linux/types.h>
-#include <linux/compiler.h>
 
 #ifndef CONFIG_SF_DEFAULT_SPEED
 # define CONFIG_SF_DEFAULT_SPEED	1000000
@@ -32,64 +30,19 @@
 # define CONFIG_SF_DEFAULT_BUS		0
 #endif
 
-/* sf param flags */
-#define SECT_4K		1 << 1
-#define SECT_32K	1 << 2
-#define E_FSR		1 << 3
-#define WR_QPP		1 << 4
-
-/* Enum list - Full read commands */
-enum spi_read_cmds {
-	ARRAY_SLOW = 1 << 0,
-	DUAL_OUTPUT_FAST = 1 << 1,
-	DUAL_IO_FAST = 1 << 2,
-	QUAD_OUTPUT_FAST = 1 << 3,
-	QUAD_IO_FAST = 1 << 4,
-};
-#define RD_EXTN		ARRAY_SLOW | DUAL_OUTPUT_FAST | DUAL_IO_FAST
-#define RD_FULL		RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST
-
-/* Dual SPI flash memories */
-enum spi_dual_flash {
-	SF_SINGLE_FLASH = 0,
-	SF_DUAL_STACKED_FLASH = 1 << 0,
-	SF_DUAL_PARALLEL_FLASH = 1 << 1,
-};
-
-/**
- * struct spi_flash_params - SPI/QSPI flash device params structure
- *
- * @name:		Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
- * @jedec:		Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
- * @ext_jedec:		Device ext_jedec ID
- * @sector_size:	Sector size of this device
- * @nr_sectors:		No.of sectors on this device
- * @e_rd_cmd:		Enum list for read commands
- * @flags:		Important param, for flash specific behaviour
- */
-struct spi_flash_params {
-	const char *name;
-	u32 jedec;
-	u16 ext_jedec;
-	u32 sector_size;
-	u32 nr_sectors;
-	u8 e_rd_cmd;
-	u16 flags;
-};
-
-extern const struct spi_flash_params spi_flash_params_table[];
+struct spi_slave;
 
 /**
  * struct spi_flash - SPI flash structure
  *
  * @spi:		SPI slave
  * @name:		Name of SPI flash
- * @dual_flash:		Indicates dual flash memories - dual stacked, parallel
+ * @dual_flash:	Indicates dual flash memories - dual stacked, parallel
  * @shift:		Flash shift useful in dual parallel
  * @size:		Total flash size
  * @page_size:		Write (page) size
  * @sector_size:	Sector size
- * @erase_size:		Erase size
+ * @erase_size:	Erase size
  * @bank_read_cmd:	Bank read cmd
  * @bank_write_cmd:	Bank write cmd
  * @bank_curr:		Current flash bank
@@ -97,8 +50,8 @@ extern const struct spi_flash_params spi_flash_params_table[];
  * @erase_cmd:		Erase cmd 4K, 32K, 64K
  * @read_cmd:		Read cmd - Array Fast, Extn read and quad read.
  * @write_cmd:		Write cmd - page and quad program.
- * @dummy_byte:		Dummy cycles for read operation.
- * @memory_map:		Address of read-only SPI flash access
+ * @dummy_byte:	Dummy cycles for read operation.
+ * @memory_map:	Address of read-only SPI flash access
  * @read:		Flash read ops: Read len bytes@offset into buf
  *			Supported cmds: Fast Array Read
  * @write:		Flash write ops: Write len bytes from buf into offset
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 18/29] spi: Use error return value in sf_ops
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (16 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 17/29] sf: Tidy up public and private header files Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 19/29] dm: sf: Add a uclass for SPI flash Simon Glass
                   ` (12 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Adjust spi_flash_probe_slave() to return an error value instead of a
pointer so we get the correct error return.

Have the caller allocate memory for spi_flash to simplify error handling,
and also so that driver model can use its existing allocated memory.

Add a spi.h include in the sf_params file.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 drivers/mtd/spi/sf_probe.c | 90 +++++++++++++++++++++++++++++-----------------
 1 file changed, 57 insertions(+), 33 deletions(-)

diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 4d148d1..212a825 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
 #include <spi.h>
@@ -95,15 +96,15 @@ static int spi_flash_set_qeb(struct spi_flash *flash, u8 idcode0)
 	}
 }
 
-static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
-		u8 *idcode)
+static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
+				     struct spi_flash *flash)
 {
 	const struct spi_flash_params *params;
-	struct spi_flash *flash;
 	u8 cmd;
 	u16 jedec = idcode[1] << 8 | idcode[2];
 	u16 ext_jedec = idcode[3] << 8 | idcode[4];
 
+	/* Validate params from spi_flash_params table */
 	params = spi_flash_params_table;
 	for (; params->name != NULL; params++) {
 		if ((params->jedec >> 16) == idcode[0]) {
@@ -120,13 +121,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
 		printf("SF: Unsupported flash IDs: ");
 		printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
 		       idcode[0], jedec, ext_jedec);
-		return NULL;
-	}
-
-	flash = calloc(1, sizeof(*flash));
-	if (!flash) {
-		debug("SF: Failed to allocate spi_flash\n");
-		return NULL;
+		return -EPROTONOSUPPORT;
 	}
 
 	/* Assign spi data */
@@ -227,15 +222,18 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
 #ifdef CONFIG_SPI_FLASH_BAR
 	u8 curr_bank = 0;
 	if (flash->size > SPI_FLASH_16MB_BOUN) {
+		int ret;
+
 		flash->bank_read_cmd = (idcode[0] == 0x01) ?
 					CMD_BANKADDR_BRRD : CMD_EXTNADDR_RDEAR;
 		flash->bank_write_cmd = (idcode[0] == 0x01) ?
 					CMD_BANKADDR_BRWR : CMD_EXTNADDR_WREAR;
 
-		if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
-					  &curr_bank, 1)) {
+		ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
+					    &curr_bank, 1);
+		if (ret) {
 			debug("SF: fail to read bank addr register\n");
-			return NULL;
+			return ret;
 		}
 		flash->bank_curr = curr_bank;
 	} else {
@@ -250,7 +248,7 @@ static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
 		spi_flash_cmd_write_status(flash, 0);
 #endif
 
-	return flash;
+	return 0;
 }
 
 #ifdef CONFIG_OF_CONTROL
@@ -309,23 +307,29 @@ static int spi_enable_wp_pin(struct spi_flash *flash)
 }
 #endif
 
-static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
+/**
+ * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
+ *
+ * @spi: Bus to probe
+ * @flashp: Pointer to place to put flash info, which may be NULL if the
+ * space should be allocated
+ */
+int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
 {
-	struct spi_flash *flash = NULL;
 	u8 idcode[5];
 	int ret;
 
 	/* Setup spi_slave */
 	if (!spi) {
 		printf("SF: Failed to set up slave\n");
-		return NULL;
+		return -ENODEV;
 	}
 
 	/* Claim spi bus */
 	ret = spi_claim_bus(spi);
 	if (ret) {
 		debug("SF: Failed to claim SPI bus: %d\n", ret);
-		goto err_claim_bus;
+		return ret;
 	}
 
 	/* Read the ID codes */
@@ -340,10 +344,10 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
 	print_buffer(0, idcode, 1, sizeof(idcode), 0);
 #endif
 
-	/* Validate params from spi_flash_params table */
-	flash = spi_flash_validate_params(spi, idcode);
-	if (!flash)
+	if (spi_flash_validate_params(spi, idcode, flash)) {
+		ret = -EINVAL;
 		goto err_read_id;
+	}
 
 	/* Set the quad enable bit - only for quad commands */
 	if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) ||
@@ -351,13 +355,15 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
 	    (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) {
 		if (spi_flash_set_qeb(flash, idcode[0])) {
 			debug("SF: Fail to set QEB for %02x\n", idcode[0]);
-			return NULL;
+			ret = -EINVAL;
+			goto err_read_id;
 		}
 	}
 
 #ifdef CONFIG_OF_CONTROL
 	if (spi_flash_decode_fdt(gd->fdt_blob, flash)) {
 		debug("SF: FDT decode error\n");
+		ret = -EINVAL;
 		goto err_read_id;
 	}
 #endif
@@ -385,32 +391,50 @@ static struct spi_flash *spi_flash_probe_slave(struct spi_slave *spi)
 	/* Release spi bus */
 	spi_release_bus(spi);
 
-	return flash;
+	return 0;
 
 err_read_id:
 	spi_release_bus(spi);
-err_claim_bus:
-	spi_free_slave(spi);
-	return NULL;
+	return ret;
+}
+
+static struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus)
+{
+	struct spi_flash *flash;
+
+	/* Allocate space if needed (not used by sf-uclass */
+	flash = calloc(1, sizeof(*flash));
+	if (!flash) {
+		debug("SF: Failed to allocate spi_flash\n");
+		return NULL;
+	}
+
+	if (spi_flash_probe_slave(bus, flash)) {
+		spi_free_slave(bus);
+		free(flash);
+		return NULL;
+	}
+
+	return flash;
 }
 
-struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
+struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
 		unsigned int max_hz, unsigned int spi_mode)
 {
-	struct spi_slave *spi;
+	struct spi_slave *bus;
 
-	spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
-	return spi_flash_probe_slave(spi);
+	bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
+	return spi_flash_probe_tail(bus);
 }
 
 #ifdef CONFIG_OF_SPI_FLASH
 struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
 				      int spi_node)
 {
-	struct spi_slave *spi;
+	struct spi_slave *bus;
 
-	spi = spi_setup_slave_fdt(blob, slave_node, spi_node);
-	return spi_flash_probe_slave(spi);
+	bus = spi_setup_slave_fdt(blob, slave_node, spi_node);
+	return spi_flash_probe_tail(bus);
 }
 #endif
 
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 19/29] dm: sf: Add a uclass for SPI flash
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (17 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 18/29] spi: Use error return value in sf_ops Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 20/29] dm: Convert spi_flash_probe() and 'sf probe' to use driver model Simon Glass
                   ` (11 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Add a driver model uclass for SPI flash which supports the common
operations (read, write, erase). Since we must keep support for the
non-dm interface, some modification of the spi_flash header is required.

CONFIG_DM_SPI_FLASH is used to enable driver model for SPI flash.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 drivers/mtd/spi/Makefile    |  7 ++++-
 drivers/mtd/spi/sf-uclass.c | 63 ++++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h      |  1 +
 include/spi_flash.h         | 70 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 140 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/spi/sf-uclass.c

diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 9e18fb4..15789a0 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -5,13 +5,18 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+obj-$(CONFIG_DM_SPI_FLASH) += sf-uclass.o
+
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_SPI_LOAD)	+= spi_spl_load.o
 obj-$(CONFIG_SPL_SPI_BOOT)	+= fsl_espi_spl.o
 endif
 
+#ifndef CONFIG_DM_SPI
+obj-$(CONFIG_SPI_FLASH) += sf_probe.o
+#endif
 obj-$(CONFIG_CMD_SF) += sf.o
-obj-$(CONFIG_SPI_FLASH) += sf_params.o sf_probe.o sf_ops.o
+obj-$(CONFIG_SPI_FLASH) += sf_ops.o sf_params.o
 obj-$(CONFIG_SPI_FRAM_RAMTRON) += ramtron.o
 obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
 obj-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
new file mode 100644
index 0000000..376d815
--- /dev/null
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <dm/device-internal.h>
+#include "sf_internal.h"
+
+/*
+ * TODO(sjg at chromium.org): This is an old-style function. We should remove
+ * it when all SPI flash drivers use dm
+ */
+struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
+				  unsigned int max_hz, unsigned int spi_mode)
+{
+	struct udevice *dev;
+
+	if (spi_flash_probe_bus_cs(bus, cs, max_hz, spi_mode, &dev))
+		return NULL;
+
+	return dev->uclass_priv;
+}
+
+void spi_flash_free(struct spi_flash *flash)
+{
+	spi_flash_remove(flash->spi->dev);
+}
+
+int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
+			   unsigned int max_hz, unsigned int spi_mode,
+			   struct udevice **devp)
+{
+	struct spi_slave *slave;
+	struct udevice *bus;
+	char name[20], *str;
+	int ret;
+
+	snprintf(name, sizeof(name), "%d:%d", busnum, cs);
+	str = strdup(name);
+	ret = spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode,
+				  "spi_flash_std", str, &bus, &slave);
+	if (ret)
+		return ret;
+
+	*devp = slave->dev;
+	return 0;
+}
+
+int spi_flash_remove(struct udevice *dev)
+{
+	return device_remove(dev);
+}
+
+UCLASS_DRIVER(spi_flash) = {
+	.id		= UCLASS_SPI_FLASH,
+	.name		= "spi_flash",
+	.per_device_auto_alloc_size = sizeof(struct spi_flash),
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 6e56382..c92adb4 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -25,6 +25,7 @@ enum uclass_id {
 	UCLASS_SERIAL,		/* Serial UART */
 	UCLASS_SPI,		/* SPI bus */
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
+	UCLASS_SPI_FLASH,	/* SPI flash */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 223e442..5913b39 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -15,6 +15,7 @@
 #ifndef _SPI_FLASH_H_
 #define _SPI_FLASH_H_
 
+#include <dm.h>	/* Because we dereference struct udevice here */
 #include <linux/types.h>
 
 #ifndef CONFIG_SF_DEFAULT_SPEED
@@ -61,7 +62,12 @@ struct spi_slave;
  * return 0 - Success, 1 - Failure
  */
 struct spi_flash {
+#ifdef CONFIG_DM_SPI_FLASH
 	struct spi_slave *spi;
+	struct udevice *dev;
+#else
+	struct spi_slave *spi;
+#endif
 	const char *name;
 	u8 dual_flash;
 	u8 shift;
@@ -82,12 +88,75 @@ struct spi_flash {
 	u8 dummy_byte;
 
 	void *memory_map;
+#ifndef CONFIG_DM_SPI_FLASH
+	/*
+	 * These are not strictly needed for driver model, but keep them here
+	 * whilt the transition is in progress.
+	 *
+	 * Normally each driver would provide its own operations, but for
+	 * SPI flash most chips use the same algorithms. One approach is
+	 * to create a 'common' SPI flash device which knows how to talk
+	 * to most devices, and then allow other drivers to be used instead
+	 * if requird, perhaps with a way of scanning through the list to
+	 * find the driver that matches the device.
+	 */
 	int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
 	int (*write)(struct spi_flash *flash, u32 offset, size_t len,
 			const void *buf);
 	int (*erase)(struct spi_flash *flash, u32 offset, size_t len);
+#endif
+};
+
+struct dm_spi_flash_ops {
+	int (*read)(struct udevice *dev, u32 offset, size_t len, void *buf);
+	int (*write)(struct udevice *dev, u32 offset, size_t len,
+		     const void *buf);
+	int (*erase)(struct udevice *dev, u32 offset, size_t len);
 };
 
+/* Access the serial operations for a device */
+#define sf_get_ops(dev) ((struct dm_spi_flash_ops *)(dev)->driver->ops)
+
+#ifdef CONFIG_DM_SPI_FLASH
+int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
+			   unsigned int max_hz, unsigned int spi_mode,
+			   struct udevice **devp);
+
+/* Compatibility function - this is the old U-Boot API */
+struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
+				  unsigned int max_hz, unsigned int spi_mode);
+
+/* Compatibility function - this is the old U-Boot API */
+void spi_flash_free(struct spi_flash *flash);
+
+int spi_flash_remove(struct udevice *flash);
+
+static inline int spi_flash_read(struct spi_flash *flash, u32 offset,
+		size_t len, void *buf)
+{
+	return sf_get_ops(flash->dev)->read(flash->dev, offset, len, buf);
+}
+
+static inline int spi_flash_write(struct spi_flash *flash, u32 offset,
+		size_t len, const void *buf)
+{
+	return sf_get_ops(flash->dev)->write(flash->dev, offset, len, buf);
+}
+
+static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
+		size_t len)
+{
+	return sf_get_ops(flash->dev)->erase(flash->dev, offset, len);
+}
+
+struct sandbox_state;
+
+int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs,
+			 struct udevice *bus, int of_offset, const char *spec);
+
+void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs);
+
+#else
 struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
 		unsigned int max_hz, unsigned int spi_mode);
 
@@ -122,6 +191,7 @@ static inline int spi_flash_erase(struct spi_flash *flash, u32 offset,
 {
 	return flash->erase(flash, offset, len);
 }
+#endif
 
 void spi_boot(void) __noreturn;
 void spi_spl_load_image(uint32_t offs, unsigned int size, void *vdst);
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 20/29] dm: Convert spi_flash_probe() and 'sf probe' to use driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (18 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 19/29] dm: sf: Add a uclass for SPI flash Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 21/29] dm: sf: sandbox: Convert SPI flash driver to " Simon Glass
                   ` (10 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

We want the SPI flash probing feature to operate as a standard driver.
Add a driver for the basic probing feature used by most boards. This
will be activated by device_probe() as with any other driver.

The 'sf probe' command currently keeps track of the SPI slave that it
last used. This doesn't work with driver model, since some other driver
or system may have probed the device and have access to it too. On the
other hand, if we try to probe a device twice the second probe is a nop
with driver model.

Fix this by searching for the matching device, removing it, and then
probing it again. This should work as expected regardless of other device
activity.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add a debug() in the probe method
- Make sure the old device is both removed and unbound in 'sf probe'

Changes in v2: None

 common/cmd_sf.c            | 25 ++++++++++++++++++
 drivers/mtd/spi/sf_probe.c | 66 ++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 89 insertions(+), 2 deletions(-)

diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index 42d89d4..95a6f89 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -8,11 +8,13 @@
 
 #include <common.h>
 #include <div64.h>
+#include <dm.h>
 #include <malloc.h>
 #include <spi.h>
 #include <spi_flash.h>
 
 #include <asm/io.h>
+#include <dm/device-internal.h>
 
 static struct spi_flash *flash;
 
@@ -81,7 +83,12 @@ static int do_spi_flash_probe(int argc, char * const argv[])
 	unsigned int speed = CONFIG_SF_DEFAULT_SPEED;
 	unsigned int mode = CONFIG_SF_DEFAULT_MODE;
 	char *endp;
+#ifdef CONFIG_DM_SPI_FLASH
+	struct udevice *new, *bus_dev;
+	int ret;
+#else
 	struct spi_flash *new;
+#endif
 
 	if (argc >= 2) {
 		cs = simple_strtoul(argv[1], &endp, 0);
@@ -109,6 +116,23 @@ static int do_spi_flash_probe(int argc, char * const argv[])
 			return -1;
 	}
 
+#ifdef CONFIG_DM_SPI_FLASH
+	/* Remove the old device, otherwise probe will just be a nop */
+	ret = spi_find_bus_and_cs(bus, cs, &bus_dev, &new);
+	if (!ret) {
+		device_remove(new);
+		device_unbind(new);
+	}
+	flash = NULL;
+	ret = spi_flash_probe_bus_cs(bus, cs, speed, mode, &new);
+	if (ret) {
+		printf("Failed to initialize SPI flash at %u:%u (error %d)\n",
+		       bus, cs, ret);
+		return 1;
+	}
+
+	flash = new->uclass_priv;
+#else
 	new = spi_flash_probe(bus, cs, speed, mode);
 	if (!new) {
 		printf("Failed to initialize SPI flash at %u:%u\n", bus, cs);
@@ -118,6 +142,7 @@ static int do_spi_flash_probe(int argc, char * const argv[])
 	if (flash)
 		spi_flash_free(flash);
 	flash = new;
+#endif
 
 	return 0;
 }
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 212a825..2636426 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
@@ -131,13 +132,15 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
 	flash->dual_flash = flash->spi->option;
 
 	/* Assign spi_flash ops */
+#ifndef CONFIG_DM_SPI_FLASH
 	flash->write = spi_flash_cmd_write_ops;
-#ifdef CONFIG_SPI_FLASH_SST
+#if defined(CONFIG_SPI_FLASH_SST)
 	if (params->flags & SST_WP)
 		flash->write = sst_write_wp;
 #endif
 	flash->erase = spi_flash_cmd_erase_ops;
 	flash->read = spi_flash_cmd_read_ops;
+#endif
 
 	/* Compute the flash size */
 	flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0;
@@ -398,7 +401,8 @@ err_read_id:
 	return ret;
 }
 
-static struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus)
+#ifndef CONFIG_DM_SPI_FLASH
+struct spi_flash *spi_flash_probe_tail(struct spi_slave *bus)
 {
 	struct spi_flash *flash;
 
@@ -443,3 +447,61 @@ void spi_flash_free(struct spi_flash *flash)
 	spi_free_slave(flash->spi);
 	free(flash);
 }
+
+#else /* defined CONFIG_DM_SPI_FLASH */
+
+static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
+			      void *buf)
+{
+	struct spi_flash *flash = dev->uclass_priv;
+
+	return spi_flash_cmd_read_ops(flash, offset, len, buf);
+}
+
+int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
+			const void *buf)
+{
+	struct spi_flash *flash = dev->uclass_priv;
+
+	return spi_flash_cmd_write_ops(flash, offset, len, buf);
+}
+
+int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
+{
+	struct spi_flash *flash = dev->uclass_priv;
+
+	return spi_flash_cmd_erase_ops(flash, offset, len);
+}
+
+int spi_flash_std_probe(struct udevice *dev)
+{
+	struct spi_slave *slave = dev_get_parentdata(dev);
+	struct spi_flash *flash;
+
+	flash = dev->uclass_priv;
+	flash->dev = dev;
+	debug("%s: slave=%p, cs=%d\n", __func__, slave, slave->cs);
+	return spi_flash_probe_slave(slave, flash);
+}
+
+static const struct dm_spi_flash_ops spi_flash_std_ops = {
+	.read = spi_flash_std_read,
+	.write = spi_flash_std_write,
+	.erase = spi_flash_std_erase,
+};
+
+static const struct udevice_id spi_flash_std_ids[] = {
+	{ .compatible = "spi-flash" },
+	{ }
+};
+
+U_BOOT_DRIVER(spi_flash_std) = {
+	.name		= "spi_flash_std",
+	.id		= UCLASS_SPI_FLASH,
+	.of_match	= spi_flash_std_ids,
+	.probe		= spi_flash_std_probe,
+	.priv_auto_alloc_size = sizeof(struct spi_flash),
+	.ops		= &spi_flash_std_ops,
+};
+
+#endif /* CONFIG_DM_SPI_FLASH */
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 21/29] dm: sf: sandbox: Convert SPI flash driver to driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (19 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 20/29] dm: Convert spi_flash_probe() and 'sf probe' to use driver model Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 22/29] dm: exynos: config: Use driver model for SPI flash Simon Glass
                   ` (9 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Convert sandbox's spi flash emulation driver to use driver model.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add a few more debug() statements
- Use an explicit chip select value instead of reusing device sequence number

Changes in v2: None

 arch/sandbox/include/asm/spi.h   |  13 --
 arch/sandbox/include/asm/state.h |   1 -
 drivers/mtd/spi/sandbox.c        | 338 +++++++++++++++++++++++++++++++++------
 include/configs/sandbox.h        |   1 +
 4 files changed, 292 insertions(+), 61 deletions(-)

diff --git a/arch/sandbox/include/asm/spi.h b/arch/sandbox/include/asm/spi.h
index 49b4a0f..9985e3c 100644
--- a/arch/sandbox/include/asm/spi.h
+++ b/arch/sandbox/include/asm/spi.h
@@ -33,19 +33,6 @@ struct sandbox_spi_emu_ops {
 };
 
 /*
- * There are times when the data lines are allowed to tristate.  What
- * is actually sensed on the line depends on the hardware.  It could
- * always be 0xFF/0x00 (if there are pull ups/downs), or things could
- * float and so we'd get garbage back.  This func encapsulates that
- * scenario so we can worry about the details here.
- */
-static inline void sandbox_spi_tristate(u8 *buf, uint len)
-{
-	/* XXX: make this into a user config option ? */
-	memset(buf, 0xff, len);
-}
-
-/*
  * Extract the bus/cs from the spi spec and return the start of the spi
  * client spec.  If the bus/cs are invalid for the current config, then
  * it returns NULL.
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index 4e0981a..32d55cc 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -42,7 +42,6 @@ enum state_terminal_raw {
 
 struct sandbox_spi_info {
 	const char *spec;
-	const struct sandbox_spi_emu_ops *ops;
 	struct udevice *emul;
 };
 
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
index 98e0a34..1cf2f98 100644
--- a/drivers/mtd/spi/sandbox.c
+++ b/drivers/mtd/spi/sandbox.c
@@ -9,6 +9,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <malloc.h>
 #include <spi.h>
 #include <os.h>
@@ -19,6 +20,11 @@
 #include <asm/getopt.h>
 #include <asm/spi.h>
 #include <asm/state.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 /*
  * The different states that our SPI flash transitions between.
@@ -34,12 +40,14 @@ enum sandbox_sf_state {
 	SF_ERASE, /* erase the flash */
 	SF_READ_STATUS, /* read the flash's status register */
 	SF_READ_STATUS1, /* read the flash's status register upper 8 bits*/
+	SF_WRITE_STATUS, /* write the flash's status register */
 };
 
 static const char *sandbox_sf_state_name(enum sandbox_sf_state state)
 {
 	static const char * const states[] = {
 		"CMD", "ID", "ADDR", "READ", "WRITE", "ERASE", "READ_STATUS",
+		"READ_STATUS1", "WRITE_STATUS",
 	};
 	return states[state];
 }
@@ -58,6 +66,7 @@ static u8 sandbox_sf_0xff[0x1000];
 
 /* Internal state data for each SPI flash */
 struct sandbox_spi_flash {
+	unsigned int cs;	/* Chip select we are attached to */
 	/*
 	 * As we receive data over the SPI bus, our flash transitions
 	 * between states.  For example, we start off in the SF_CMD
@@ -84,71 +93,124 @@ struct sandbox_spi_flash {
 	int fd;
 };
 
-static int sandbox_sf_setup(void **priv, const char *spec)
+struct sandbox_spi_flash_plat_data {
+	const char *filename;
+	const char *device_name;
+	int bus;
+	int cs;
+};
+
+/**
+ * This is a very strange probe function. If it has platform data (which may
+ * have come from the device tree) then this function gets the filename and
+ * device type from there. Failing that it looks at the command line
+ * parameter.
+ */
+static int sandbox_sf_probe(struct udevice *dev)
 {
 	/* spec = idcode:file */
-	struct sandbox_spi_flash *sbsf;
+	struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
 	const char *file;
 	size_t len, idname_len;
 	const struct spi_flash_params *data;
-
-	file = strchr(spec, ':');
-	if (!file) {
-		printf("sandbox_sf: unable to parse file\n");
-		goto error;
+	struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev);
+	struct sandbox_state *state = state_get_current();
+	struct udevice *bus = dev->parent;
+	const char *spec = NULL;
+	int ret = 0;
+	int cs = -1;
+	int i;
+
+	debug("%s: bus %d, looking for emul=%p: ", __func__, bus->seq, dev);
+	if (bus->seq >= 0 && bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS) {
+		for (i = 0; i < CONFIG_SANDBOX_SPI_MAX_CS; i++) {
+			if (state->spi[bus->seq][i].emul == dev)
+				cs = i;
+		}
+	}
+	if (cs == -1) {
+		printf("Error: Unknown chip select for device '%s'",
+		       dev->name);
+		return -EINVAL;
+	}
+	debug("found at cs %d\n", cs);
+
+	if (!pdata->filename) {
+		struct sandbox_state *state = state_get_current();
+
+		assert(bus->seq != -1);
+		if (bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS)
+			spec = state->spi[bus->seq][cs].spec;
+		if (!spec)
+			return -ENOENT;
+
+		file = strchr(spec, ':');
+		if (!file) {
+			printf("sandbox_sf: unable to parse file\n");
+			ret = -EINVAL;
+			goto error;
+		}
+		idname_len = file - spec;
+		pdata->filename = file + 1;
+		pdata->device_name = spec;
+		++file;
+	} else {
+		spec = strchr(pdata->device_name, ',');
+		if (spec)
+			spec++;
+		else
+			spec = pdata->device_name;
+		idname_len = strlen(spec);
 	}
-	idname_len = file - spec;
-	++file;
+	debug("%s: device='%s'\n", __func__, spec);
 
 	for (data = spi_flash_params_table; data->name; data++) {
 		len = strlen(data->name);
 		if (idname_len != len)
 			continue;
-		if (!memcmp(spec, data->name, len))
+		if (!strncasecmp(spec, data->name, len))
 			break;
 	}
 	if (!data->name) {
 		printf("sandbox_sf: unknown flash '%*s'\n", (int)idname_len,
 		       spec);
+		ret = -EINVAL;
 		goto error;
 	}
 
 	if (sandbox_sf_0xff[0] == 0x00)
 		memset(sandbox_sf_0xff, 0xff, sizeof(sandbox_sf_0xff));
 
-	sbsf = calloc(sizeof(*sbsf), 1);
-	if (!sbsf) {
-		printf("sandbox_sf: out of memory\n");
-		goto error;
-	}
-
-	sbsf->fd = os_open(file, 02);
+	sbsf->fd = os_open(pdata->filename, 02);
 	if (sbsf->fd == -1) {
 		free(sbsf);
-		printf("sandbox_sf: unable to open file '%s'\n", file);
+		printf("sandbox_sf: unable to open file '%s'\n",
+		       pdata->filename);
+		ret = -EIO;
 		goto error;
 	}
 
 	sbsf->data = data;
+	sbsf->cs = cs;
 
-	*priv = sbsf;
 	return 0;
 
  error:
-	return 1;
+	return ret;
 }
 
-static void sandbox_sf_free(void *priv)
+static int sandbox_sf_remove(struct udevice *dev)
 {
-	struct sandbox_spi_flash *sbsf = priv;
+	struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
 
 	os_close(sbsf->fd);
-	free(sbsf);
+
+	return 0;
 }
 
-static void sandbox_sf_cs_activate(void *priv)
+static void sandbox_sf_cs_activate(struct udevice *dev)
 {
-	struct sandbox_spi_flash *sbsf = priv;
+	struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
 
 	debug("sandbox_sf: CS activated; state is fresh!\n");
 
@@ -160,11 +222,24 @@ static void sandbox_sf_cs_activate(void *priv)
 	sbsf->cmd = SF_CMD;
 }
 
-static void sandbox_sf_cs_deactivate(void *priv)
+static void sandbox_sf_cs_deactivate(struct udevice *dev)
 {
 	debug("sandbox_sf: CS deactivated; cmd done processing!\n");
 }
 
+/*
+ * There are times when the data lines are allowed to tristate.  What
+ * is actually sensed on the line depends on the hardware.  It could
+ * always be 0xFF/0x00 (if there are pull ups/downs), or things could
+ * float and so we'd get garbage back.  This func encapsulates that
+ * scenario so we can worry about the details here.
+ */
+static void sandbox_spi_tristate(u8 *buf, uint len)
+{
+	/* XXX: make this into a user config option ? */
+	memset(buf, 0xff, len);
+}
+
 /* Figure out what command this stream is telling us to do */
 static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
 				  u8 *tx)
@@ -172,7 +247,8 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
 	enum sandbox_sf_state oldstate = sbsf->state;
 
 	/* We need to output a byte for the cmd byte we just ate */
-	sandbox_spi_tristate(tx, 1);
+	if (tx)
+		sandbox_spi_tristate(tx, 1);
 
 	sbsf->cmd = rx[0];
 	switch (sbsf->cmd) {
@@ -200,6 +276,9 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
 		debug(" write enabled\n");
 		sbsf->status |= STAT_WEL;
 		break;
+	case CMD_WRITE_STATUS:
+		sbsf->state = SF_WRITE_STATUS;
+		break;
 	default: {
 		int flags = sbsf->data->flags;
 
@@ -216,7 +295,7 @@ static int sandbox_sf_process_cmd(struct sandbox_spi_flash *sbsf, const u8 *rx,
 			sbsf->erase_size = 64 << 10;
 		} else {
 			debug(" cmd unknown: %#x\n", sbsf->cmd);
-			return 1;
+			return -EIO;
 		}
 		sbsf->state = SF_ADDR;
 		break;
@@ -246,20 +325,27 @@ int sandbox_erase_part(struct sandbox_spi_flash *sbsf, int size)
 	return 0;
 }
 
-static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
-		uint bytes)
+static int sandbox_sf_xfer(struct udevice *dev, unsigned int bitlen,
+			   const void *rxp, void *txp, unsigned long flags)
 {
-	struct sandbox_spi_flash *sbsf = priv;
+	struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
+	const uint8_t *rx = rxp;
+	uint8_t *tx = txp;
 	uint cnt, pos = 0;
+	int bytes = bitlen / 8;
 	int ret;
 
 	debug("sandbox_sf: state:%x(%s) bytes:%u\n", sbsf->state,
 	      sandbox_sf_state_name(sbsf->state), bytes);
 
+	if ((flags & SPI_XFER_BEGIN))
+		sandbox_sf_cs_activate(dev);
+
 	if (sbsf->state == SF_CMD) {
 		/* Figure out the initial state */
-		if (sandbox_sf_process_cmd(sbsf, rx, tx))
-			return 1;
+		ret = sandbox_sf_process_cmd(sbsf, rx, tx);
+		if (ret)
+			return ret;
 		++pos;
 	}
 
@@ -290,7 +376,9 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 				sbsf->off = (sbsf->off << 8) | rx[pos];
 			debug("addr:%06x\n", sbsf->off);
 
-			sandbox_spi_tristate(&tx[pos++], 1);
+			if (tx)
+				sandbox_spi_tristate(&tx[pos], 1);
+			pos++;
 
 			/* See if we're done processing */
 			if (sbsf->addr_bytes <
@@ -300,7 +388,7 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 			/* Next state! */
 			if (os_lseek(sbsf->fd, sbsf->off, OS_SEEK_SET) < 0) {
 				puts("sandbox_sf: os_lseek() failed");
-				return 1;
+				return -EIO;
 			}
 			switch (sbsf->cmd) {
 			case CMD_READ_ARRAY_FAST:
@@ -326,10 +414,11 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 
 			cnt = bytes - pos;
 			debug(" tx: read(%u)\n", cnt);
+			assert(tx);
 			ret = os_read(sbsf->fd, tx + pos, cnt);
 			if (ret < 0) {
-				puts("sandbox_spi: os_read() failed\n");
-				return 1;
+				puts("sandbox_sf: os_read() failed\n");
+				return -EIO;
 			}
 			pos += ret;
 			break;
@@ -345,6 +434,10 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 			memset(tx + pos, sbsf->status >> 8, cnt);
 			pos += cnt;
 			break;
+		case SF_WRITE_STATUS:
+			debug(" write status: %#x (ignored)\n", rx[pos]);
+			pos = bytes;
+			break;
 		case SF_WRITE:
 			/*
 			 * XXX: need to handle exotic behavior:
@@ -359,11 +452,12 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 
 			cnt = bytes - pos;
 			debug(" rx: write(%u)\n", cnt);
-			sandbox_spi_tristate(&tx[pos], cnt);
+			if (tx)
+				sandbox_spi_tristate(&tx[pos], cnt);
 			ret = os_write(sbsf->fd, rx + pos, cnt);
 			if (ret < 0) {
 				puts("sandbox_spi: os_write() failed\n");
-				return 1;
+				return -EIO;
 			}
 			pos += ret;
 			sbsf->status &= ~STAT_WEL;
@@ -388,7 +482,8 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 			      sbsf->erase_size);
 
 			cnt = bytes - pos;
-			sandbox_spi_tristate(&tx[pos], cnt);
+			if (tx)
+				sandbox_spi_tristate(&tx[pos], cnt);
 			pos += cnt;
 
 			/*
@@ -410,17 +505,33 @@ static int sandbox_sf_xfer(void *priv, const u8 *rx, u8 *tx,
 	}
 
  done:
-	return pos == bytes ? 0 : 1;
+	if (flags & SPI_XFER_END)
+		sandbox_sf_cs_deactivate(dev);
+	return pos == bytes ? 0 : -EIO;
+}
+
+int sandbox_sf_ofdata_to_platdata(struct udevice *dev)
+{
+	struct sandbox_spi_flash_plat_data *pdata = dev_get_platdata(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+
+	pdata->filename = fdt_getprop(blob, node, "sandbox,filename", NULL);
+	pdata->device_name = fdt_getprop(blob, node, "compatible", NULL);
+	if (!pdata->filename || !pdata->device_name) {
+		debug("%s: Missing properties, filename=%s, device_name=%s\n",
+		      __func__, pdata->filename, pdata->device_name);
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
-static const struct sandbox_spi_emu_ops sandbox_sf_ops = {
-	.setup         = sandbox_sf_setup,
-	.free          = sandbox_sf_free,
-	.cs_activate   = sandbox_sf_cs_activate,
-	.cs_deactivate = sandbox_sf_cs_deactivate,
+static const struct dm_spi_emul_ops sandbox_sf_emul_ops = {
 	.xfer          = sandbox_sf_xfer,
 };
 
+#ifdef CONFIG_SPI_FLASH
 static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state,
 				     const char *arg)
 {
@@ -438,8 +549,141 @@ static int sandbox_cmdline_cb_spi_sf(struct sandbox_state *state,
 	 * spec here, but the problem is that no U-Boot init has been done
 	 * yet. Perhaps we can figure something out.
 	 */
-	state->spi[bus][cs].ops = &sandbox_sf_ops;
 	state->spi[bus][cs].spec = spec;
 	return 0;
 }
 SANDBOX_CMDLINE_OPT(spi_sf, 1, "connect a SPI flash: <bus>:<cs>:<id>:<file>");
+
+int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs,
+			 struct udevice *bus, int of_offset, const char *spec)
+{
+	struct udevice *emul;
+	char name[20], *str;
+	struct driver *drv;
+	int ret;
+
+	/* now the emulator */
+	strncpy(name, spec, sizeof(name) - 6);
+	name[sizeof(name) - 6] = '\0';
+	strcat(name, "-emul");
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	drv = lists_driver_lookup_name("sandbox_sf_emul");
+	if (!drv) {
+		puts("Cannot find sandbox_sf_emul driver\n");
+		return -ENOENT;
+	}
+	ret = device_bind(bus, drv, str, NULL, of_offset, &emul);
+	if (ret) {
+		printf("Cannot create emul device for spec '%s' (err=%d)\n",
+		       spec, ret);
+		return ret;
+	}
+	state->spi[busnum][cs].emul = emul;
+
+	return 0;
+}
+
+void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs)
+{
+	state->spi[busnum][cs].emul = NULL;
+}
+
+static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum,
+				  int cs, const char *spec)
+{
+	struct udevice *bus, *slave;
+	int ret;
+
+	ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, true, &bus);
+	if (ret) {
+		printf("Invalid bus %d for spec '%s' (err=%d)\n", busnum,
+		       spec, ret);
+		return ret;
+	}
+	ret = device_find_child_by_seq(bus, cs, true, &slave);
+	if (!ret) {
+		printf("Chip select %d already exists for spec '%s'\n", cs,
+		       spec);
+		return -EEXIST;
+	}
+
+	ret = spi_bind_device(bus, cs, "spi_flash_std", spec, &slave);
+	if (ret)
+		return ret;
+
+	return sandbox_sf_bind_emul(state, busnum, cs, bus, -1, spec);
+}
+
+int sandbox_spi_get_emul(struct sandbox_state *state,
+			 struct udevice *bus, struct udevice *slave,
+			 struct udevice **emulp)
+{
+	struct sandbox_spi_info *info;
+	int busnum = bus->seq;
+	int cs = spi_chip_select(slave);
+	int ret;
+
+	info = &state->spi[busnum][cs];
+	if (!info->emul) {
+		/* Use the same device tree node as the SPI flash device */
+		debug("%s: busnum=%u, cs=%u: binding SPI flash emulation: ",
+		      __func__, busnum, cs);
+		ret = sandbox_sf_bind_emul(state, busnum, cs, bus,
+					   slave->of_offset, slave->name);
+		if (ret) {
+			debug("failed (err=%d)\n", ret);
+			return ret;
+		}
+		debug("OK\n");
+	}
+	*emulp = info->emul;
+
+	return 0;
+}
+
+int dm_scan_other(bool pre_reloc_only)
+{
+	struct sandbox_state *state = state_get_current();
+	int busnum, cs;
+
+	if (pre_reloc_only)
+		return 0;
+	for (busnum = 0; busnum < CONFIG_SANDBOX_SPI_MAX_BUS; busnum++) {
+		for (cs = 0; cs < CONFIG_SANDBOX_SPI_MAX_CS; cs++) {
+			const char *spec = state->spi[busnum][cs].spec;
+			int ret;
+
+			if (spec) {
+				ret = sandbox_sf_bind_bus_cs(state, busnum,
+							     cs, spec);
+				if (ret) {
+					debug("%s: Bind failed for bus %d, cs %d\n",
+					      __func__, busnum, cs);
+					return ret;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+#endif
+
+static const struct udevice_id sandbox_sf_ids[] = {
+	{ .compatible = "sandbox,spi-flash" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_sf_emul) = {
+	.name		= "sandbox_sf_emul",
+	.id		= UCLASS_SPI_EMUL,
+	.of_match	= sandbox_sf_ids,
+	.ofdata_to_platdata = sandbox_sf_ofdata_to_platdata,
+	.probe		= sandbox_sf_probe,
+	.remove		= sandbox_sf_remove,
+	.priv_auto_alloc_size = sizeof(struct sandbox_spi_flash),
+	.platdata_auto_alloc_size = sizeof(struct sandbox_spi_flash_plat_data),
+	.ops		= &sandbox_sf_emul_ops,
+};
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index c80e4f0..9adc5cc 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -98,6 +98,7 @@
 #define CONFIG_CMD_SPI
 #define CONFIG_SPI_FLASH
 #define CONFIG_DM_SPI
+#define CONFIG_DM_SPI_FLASH
 #define CONFIG_SPI_FLASH_ATMEL
 #define CONFIG_SPI_FLASH_EON
 #define CONFIG_SPI_FLASH_GIGADEVICE
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 22/29] dm: exynos: config: Use driver model for SPI flash
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (20 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 21/29] dm: sf: sandbox: Convert SPI flash driver to " Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 23/29] dm: spi: Add tests Simon Glass
                   ` (8 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Use driver model for exynos5 board SPI flash.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 include/configs/exynos-common.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/configs/exynos-common.h b/include/configs/exynos-common.h
index eb6745e..6ba9bb7 100644
--- a/include/configs/exynos-common.h
+++ b/include/configs/exynos-common.h
@@ -22,6 +22,7 @@
 #define CONFIG_DM_GPIO
 #define CONFIG_DM_SERIAL
 #define CONFIG_DM_SPI
+#define CONFIG_DM_SPI_FLASH
 
 #define CONFIG_ARCH_CPU_INIT
 #define CONFIG_DISPLAY_CPUINFO
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 23/29] dm: spi: Add tests
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (21 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 22/29] dm: exynos: config: Use driver model for SPI flash Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 24/29] dm: sf: Add tests for SPI flash Simon Glass
                   ` (7 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

These tests use SPI flash (and the sandbox emulation) to operate.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Expand SPI tests to cover compatibility functions
- Minor renames for clarity

Changes in v2:
- Create a 'spi.bin' file for the SPI tests

 test/dm/Makefile   |   1 +
 test/dm/spi.c      | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/dm/test-dm.sh |   2 +
 3 files changed, 130 insertions(+)
 create mode 100644 test/dm/spi.c

diff --git a/test/dm/Makefile b/test/dm/Makefile
index 5c2415e..d1b9c9a 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -18,4 +18,5 @@ obj-$(CONFIG_DM_TEST) += core.o
 obj-$(CONFIG_DM_TEST) += ut.o
 ifneq ($(CONFIG_SANDBOX),)
 obj-$(CONFIG_DM_GPIO) += gpio.o
+obj-$(CONFIG_DM_SPI) += spi.o
 endif
diff --git a/test/dm/spi.c b/test/dm/spi.c
new file mode 100644
index 0000000..61b5b25
--- /dev/null
+++ b/test/dm/spi.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <dm/device-internal.h>
+#include <dm/test.h>
+#include <dm/uclass-internal.h>
+#include <dm/ut.h>
+#include <dm/util.h>
+#include <asm/state.h>
+
+/* Test that we can find buses and chip-selects */
+static int dm_test_spi_find(struct dm_test_state *dms)
+{
+	struct sandbox_state *state = state_get_current();
+	struct spi_slave *slave;
+	struct udevice *bus, *dev;
+	const int busnum = 0, cs = 0, mode = 0, speed = 1000000, cs_b = 1;
+	struct spi_cs_info info;
+	int of_offset;
+
+	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_SPI, busnum,
+						       false, &bus));
+
+	/*
+	 * spi_post_bind() will bind devices to chip selects. Check this then
+	 * remove the emulation and the slave device.
+	 */
+	ut_asserteq(0, uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus));
+	ut_assertok(spi_cs_info(bus, cs, &info));
+	of_offset = info.dev->of_offset;
+	sandbox_sf_unbind_emul(state_get_current(), busnum, cs);
+	device_remove(info.dev);
+	device_unbind(info.dev);
+
+	/*
+	 * Even though the device is gone, the sandbox SPI drivers always
+	 * reports that CS 0 is present
+	 */
+	ut_assertok(spi_cs_info(bus, cs, &info));
+	ut_asserteq_ptr(info.dev, NULL);
+
+	/* This finds nothing because we removed the device */
+	ut_asserteq(-ENODEV, spi_find_bus_and_cs(busnum, cs, &bus, &dev));
+	ut_asserteq(-ENODEV, spi_get_bus_and_cs(busnum, cs, speed, mode,
+						NULL, 0, &bus, &slave));
+
+	/*
+	 * This forces the device to be re-added, but there is no emulation
+	 * connected so the probe will fail. We require that bus is left
+	 * alone on failure, and that the spi_get_bus_and_cs() does not add
+	 * a 'partially-inited' device.
+	 */
+	ut_asserteq(-ENODEV, spi_find_bus_and_cs(busnum, cs, &bus, &dev));
+	ut_asserteq(-ENOENT, spi_get_bus_and_cs(busnum, cs, speed, mode,
+						"spi_flash_std", "name", &bus,
+						&slave));
+	ut_assertok(spi_cs_info(bus, cs, &info));
+	ut_asserteq_ptr(info.dev, NULL);
+
+	/* Add the emulation and try again */
+	ut_assertok(sandbox_sf_bind_emul(state, busnum, cs, bus, of_offset,
+					 "name"));
+	ut_assertok(spi_find_bus_and_cs(busnum, cs, &bus, &dev));
+	ut_assertok(spi_get_bus_and_cs(busnum, cs, speed, mode,
+				       "spi_flash_std", "name", &bus, &slave));
+
+	ut_assertok(spi_cs_info(bus, cs, &info));
+	ut_asserteq_ptr(info.dev, slave->dev);
+
+	/* We should be able to add something to another chip select */
+	ut_assertok(sandbox_sf_bind_emul(state, busnum, cs_b, bus, of_offset,
+					 "name"));
+	ut_assertok(spi_get_bus_and_cs(busnum, cs_b, speed, mode,
+				       "spi_flash_std", "name", &bus, &slave));
+	ut_assertok(spi_cs_info(bus, cs_b, &info));
+	ut_asserteq_ptr(info.dev, slave->dev);
+
+	/*
+	 * Since we are about to destroy all devices, we must tell sandbox
+	 * to forget the emulation device
+	 */
+	sandbox_sf_unbind_emul(state_get_current(), busnum, cs);
+	sandbox_sf_unbind_emul(state_get_current(), busnum, cs_b);
+
+	return 0;
+}
+DM_TEST(dm_test_spi_find, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that sandbox SPI works correctly */
+static int dm_test_spi_xfer(struct dm_test_state *dms)
+{
+	struct spi_slave *slave;
+	struct udevice *bus;
+	const int busnum = 0, cs = 0, mode = 0;
+	const char dout[5] = {0x9f};
+	unsigned char din[5];
+
+	ut_assertok(spi_get_bus_and_cs(busnum, cs, 1000000, mode, NULL, 0,
+				       &bus, &slave));
+	ut_assertok(spi_claim_bus(slave));
+	ut_assertok(spi_xfer(slave, 40, dout, din,
+			     SPI_XFER_BEGIN | SPI_XFER_END));
+	ut_asserteq(0xff, din[0]);
+	ut_asserteq(0x20, din[1]);
+	ut_asserteq(0x20, din[2]);
+	ut_asserteq(0x15, din[3]);
+	spi_release_bus(slave);
+
+	/*
+	 * Since we are about to destroy all devices, we must tell sandbox
+	 * to forget the emulation device
+	 */
+#ifdef CONFIG_DM_SPI_FLASH
+	sandbox_sf_unbind_emul(state_get_current(), busnum, cs);
+#endif
+
+	return 0;
+}
+DM_TEST(dm_test_spi_xfer, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-dm.sh b/test/dm/test-dm.sh
index ef5aca5..bb99677 100755
--- a/test/dm/test-dm.sh
+++ b/test/dm/test-dm.sh
@@ -4,4 +4,6 @@ NUM_CPUS=$(cat /proc/cpuinfo |grep -c processor)
 dtc -I dts -O dtb test/dm/test.dts -o test/dm/test.dtb
 make O=sandbox sandbox_config
 make O=sandbox -s -j${NUM_CPUS}
+dd if=/dev/zero of=spi.bin bs=1M count=2
 ./sandbox/u-boot -d test/dm/test.dtb -c "dm test"
+rm spi.bin
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 24/29] dm: sf: Add tests for SPI flash
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (22 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 23/29] dm: spi: Add tests Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 25/29] dm: tegra: dts: Add aliases for spi on tegra30 boards Simon Glass
                   ` (6 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Add a simple test for SPI that uses SPI flash. It operates by creating a
SPI flash file and using the 'sf test' command to test that all
operations work correctly.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 test/dm/Makefile |  1 +
 test/dm/sf.c     | 43 +++++++++++++++++++++++++++++++++++++++++++
 test/dm/test.dts | 17 ++++++++++++++++-
 3 files changed, 60 insertions(+), 1 deletion(-)
 create mode 100644 test/dm/sf.c

diff --git a/test/dm/Makefile b/test/dm/Makefile
index d1b9c9a..75d3d41 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -19,4 +19,5 @@ obj-$(CONFIG_DM_TEST) += ut.o
 ifneq ($(CONFIG_SANDBOX),)
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_SPI) += spi.o
+obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 endif
diff --git a/test/dm/sf.c b/test/dm/sf.c
new file mode 100644
index 0000000..57dd134
--- /dev/null
+++ b/test/dm/sf.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <spi.h>
+#include <spi_flash.h>
+#include <asm/state.h>
+#include <dm/ut.h>
+#include <dm/test.h>
+#include <dm/util.h>
+
+/* Test that sandbox SPI flash works correctly */
+static int dm_test_spi_flash(struct dm_test_state *dms)
+{
+	/*
+	 * Create an empty test file and run the SPI flash tests. This is a
+	 * long way from being a unit test, but it does test SPI device and
+	 * emulator binding, probing, the SPI flash emulator including
+	 * device tree decoding, plus the file-based backing store of SPI.
+	 *
+	 * More targeted tests could be created to perform the above steps
+	 * one at a time. This might not increase test coverage much, but
+	 * it would make bugs easier to find. It's not clear whether the
+	 * benefit is worth the extra complexity.
+	 */
+	ut_asserteq(0, run_command_list(
+		"sb save hostfs - spi.bin 0 200000;"
+		"sf probe;"
+		"sf test 0 10000", -1,  0));
+	/*
+	 * Since we are about to destroy all devices, we must tell sandbox
+	 * to forget the emulation device
+	 */
+	sandbox_sf_unbind_emul(state_get_current(), 0, 0);
+
+	return 0;
+}
+DM_TEST(dm_test_spi_flash, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test.dts b/test/dm/test.dts
index 8489595..1fba792 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -81,7 +81,7 @@
 		compatible = "google,another-fdt-test";
 	};
 
-	base-gpios {
+	gpio_a: base-gpios {
 		compatible = "sandbox,gpio";
 		gpio-bank-name = "a";
 		num-gpios = <20>;
@@ -92,4 +92,19 @@
 		gpio-bank-name = "b";
 		num-gpios = <10>;
 	};
+
+	spi at 0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0>;
+		compatible = "sandbox,spi";
+		cs-gpios = <0>, <&gpio_a 0>;
+		spi.bin at 0 {
+			reg = <0>;
+			compatible = "spansion,m25p16", "spi-flash";
+			spi-max-frequency = <40000000>;
+			sandbox,filename = "spi.bin";
+		};
+	};
+
 };
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 25/29] dm: tegra: dts: Add aliases for spi on tegra30 boards
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (23 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 24/29] dm: sf: Add tests for SPI flash Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 26/29] dm: tegra: spi: Convert to driver model Simon Glass
                   ` (5 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

All boards with a SPI interface have a suitable spi alias except the tegra30
boards. Add these missing aliases.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add new patch to add aliases for spi on tegra30 boards

Changes in v2: None

 arch/arm/dts/tegra20-trimslice.dts | 1 +
 arch/arm/dts/tegra30-beaver.dts    | 1 +
 arch/arm/dts/tegra30-cardhu.dts    | 1 +
 arch/arm/dts/tegra30-colibri.dts   | 1 +
 4 files changed, 4 insertions(+)

diff --git a/arch/arm/dts/tegra20-trimslice.dts b/arch/arm/dts/tegra20-trimslice.dts
index cee5cfe..74e8a16 100644
--- a/arch/arm/dts/tegra20-trimslice.dts
+++ b/arch/arm/dts/tegra20-trimslice.dts
@@ -15,6 +15,7 @@
 		usb1 = "/usb at c5000000";
 		sdhci0 = "/sdhci at c8000600";
 		sdhci1 = "/sdhci at c8000000";
+		spi0 = "/spi at 7000c380";
 	};
 
 	memory {
diff --git a/arch/arm/dts/tegra30-beaver.dts b/arch/arm/dts/tegra30-beaver.dts
index ad140de..9acd84d 100644
--- a/arch/arm/dts/tegra30-beaver.dts
+++ b/arch/arm/dts/tegra30-beaver.dts
@@ -18,6 +18,7 @@
 		i2c4 = "/i2c at 7000c700";
 		sdhci0 = "/sdhci at 78000600";
 		sdhci1 = "/sdhci at 78000000";
+		spi0 = "/spi at 7000da00";
 		usb0 = "/usb at 7d000000";
 		usb1 = "/usb at 7d008000";
 	};
diff --git a/arch/arm/dts/tegra30-cardhu.dts b/arch/arm/dts/tegra30-cardhu.dts
index b4fbe71..1b8ed73 100644
--- a/arch/arm/dts/tegra30-cardhu.dts
+++ b/arch/arm/dts/tegra30-cardhu.dts
@@ -18,6 +18,7 @@
 		i2c4 = "/i2c at 7000c700";
 		sdhci0 = "/sdhci at 78000600";
 		sdhci1 = "/sdhci at 78000000";
+		spi0 = "/spi at 7000da00";
 		usb0 = "/usb at 7d008000";
 	};
 
diff --git a/arch/arm/dts/tegra30-colibri.dts b/arch/arm/dts/tegra30-colibri.dts
index 43d03ca..df79c26 100644
--- a/arch/arm/dts/tegra30-colibri.dts
+++ b/arch/arm/dts/tegra30-colibri.dts
@@ -12,6 +12,7 @@
 		i2c2 = "/i2c at 7000c700";
 		sdhci0 = "/sdhci at 78000600";
 		sdhci1 = "/sdhci at 78000200";
+		spi0 = "/spi at 7000d400";
 		usb0 = "/usb at 7d000000";
 		usb1 = "/usb at 7d004000"; /* on module only, for ASIX */
 		usb2 = "/usb at 7d008000";
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 26/29] dm: tegra: spi: Convert to driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (24 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 25/29] dm: tegra: dts: Add aliases for spi on tegra30 boards Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 22:59   ` Igor Grinberg
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 27/29] dm: cros_ec: Add support for " Simon Glass
                   ` (4 subsequent siblings)
  30 siblings, 1 reply; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

This converts the Tegra SPI drivers to use driver model. This is tested
on:

- Tegra20 - trimslice
- Tegra30 - beaver
- Tegra124 - dalmore

(not tested on Tegra124)

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add implementation/comment for the cs_info() method
- Add new patch to convert Tegra SPI to driver model

Changes in v2: None

 arch/arm/include/asm/arch-tegra114/tegra114_spi.h  |  41 ----
 arch/arm/include/asm/arch-tegra20/tegra20_sflash.h |  41 ----
 arch/arm/include/asm/arch-tegra20/tegra20_slink.h  |  41 ----
 board/compulab/common/eeprom.c                     |   2 +-
 board/nvidia/common/board.c                        |   3 +-
 drivers/spi/Makefile                               |   1 -
 drivers/spi/fdt_spi.c                              | 186 ---------------
 drivers/spi/tegra114_spi.c                         | 254 +++++++++++----------
 drivers/spi/tegra20_sflash.c                       | 238 ++++++++++---------
 drivers/spi/tegra20_slink.c                        | 235 ++++++++++---------
 drivers/spi/tegra_spi.h                            |  12 +
 include/configs/tegra-common-post.h                |   2 +-
 include/configs/tegra-common.h                     |   2 +
 13 files changed, 397 insertions(+), 661 deletions(-)
 delete mode 100644 arch/arm/include/asm/arch-tegra114/tegra114_spi.h
 delete mode 100644 arch/arm/include/asm/arch-tegra20/tegra20_sflash.h
 delete mode 100644 arch/arm/include/asm/arch-tegra20/tegra20_slink.h
 delete mode 100644 drivers/spi/fdt_spi.c
 create mode 100644 drivers/spi/tegra_spi.h

diff --git a/arch/arm/include/asm/arch-tegra114/tegra114_spi.h b/arch/arm/include/asm/arch-tegra114/tegra114_spi.h
deleted file mode 100644
index 48197bc..0000000
--- a/arch/arm/include/asm/arch-tegra114/tegra114_spi.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * NVIDIA Tegra SPI controller
- *
- * Copyright 2010-2013 NVIDIA Corporation
- *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * Version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef _TEGRA114_SPI_H_
-#define _TEGRA114_SPI_H_
-
-#include <asm/types.h>
-
-int tegra114_spi_init(int *node_list, int count);
-int tegra114_spi_cs_is_valid(unsigned int bus, unsigned int cs);
-struct spi_slave *tegra114_spi_setup_slave(unsigned int bus, unsigned int cs,
-				  unsigned int max_hz, unsigned int mode);
-void tegra114_spi_free_slave(struct spi_slave *slave);
-int tegra114_spi_claim_bus(struct spi_slave *slave);
-void tegra114_spi_cs_activate(struct spi_slave *slave);
-void tegra114_spi_cs_deactivate(struct spi_slave *slave);
-int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-		     const void *data_out, void *data_in, unsigned long flags);
-
-#endif	/* _TEGRA114_SPI_H_ */
diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h b/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h
deleted file mode 100644
index e8cc68c..0000000
--- a/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * NVIDIA Tegra20 SPI-FLASH controller
- *
- * Copyright 2010-2012 NVIDIA Corporation
- *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * Version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef _TEGRA20_SPI_H_
-#define _TEGRA20_SPI_H_
-
-#include <asm/types.h>
-
-int tegra20_spi_cs_is_valid(unsigned int bus, unsigned int cs);
-struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs,
-				  unsigned int max_hz, unsigned int mode);
-void tegra20_spi_free_slave(struct spi_slave *slave);
-int tegra20_spi_init(int *node_list, int count);
-int tegra20_spi_claim_bus(struct spi_slave *slave);
-void tegra20_spi_cs_activate(struct spi_slave *slave);
-void tegra20_spi_cs_deactivate(struct spi_slave *slave);
-int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-	     const void *data_out, void *data_in, unsigned long flags);
-
-#endif	/* _TEGRA20_SPI_H_ */
diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_slink.h b/arch/arm/include/asm/arch-tegra20/tegra20_slink.h
deleted file mode 100644
index 5aa74dd..0000000
--- a/arch/arm/include/asm/arch-tegra20/tegra20_slink.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * NVIDIA Tegra SPI-SLINK controller
- *
- * Copyright 2010-2013 NVIDIA Corporation
- *
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * Version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef _TEGRA30_SPI_H_
-#define _TEGRA30_SPI_H_
-
-#include <asm/types.h>
-
-int tegra30_spi_init(int *node_list, int count);
-int tegra30_spi_cs_is_valid(unsigned int bus, unsigned int cs);
-struct spi_slave *tegra30_spi_setup_slave(unsigned int bus, unsigned int cs,
-				  unsigned int max_hz, unsigned int mode);
-void tegra30_spi_free_slave(struct spi_slave *slave);
-int tegra30_spi_claim_bus(struct spi_slave *slave);
-void tegra30_spi_cs_activate(struct spi_slave *slave);
-void tegra30_spi_cs_deactivate(struct spi_slave *slave);
-int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-		     const void *data_out, void *data_in, unsigned long flags);
-
-#endif	/* _TEGRA30_SPI_H_ */
diff --git a/board/compulab/common/eeprom.c b/board/compulab/common/eeprom.c
index 85442cd..ba3a5bf 100644
--- a/board/compulab/common/eeprom.c
+++ b/board/compulab/common/eeprom.c
@@ -33,7 +33,7 @@ static int cl_eeprom_read(uint offset, uchar *buf, int len)
 {
 	int res;
 	unsigned int current_i2c_bus = i2c_get_bus_num();
-
+#define CONFIG_SYS_I2C_EEPROM_BUS 1
 	res = i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS);
 	if (res < 0)
 		return res;
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index d01abce..03f055d 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -114,9 +114,8 @@ int board_init(void)
 	clock_init();
 	clock_verify();
 
-#ifdef CONFIG_FDT_SPI
+#ifdef CONFIG_TEGRA_SPI
 	pin_mux_spi();
-	spi_init();
 #endif
 
 #ifdef CONFIG_PWM_TEGRA
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e718528..eabbf27 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -40,7 +40,6 @@ obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
 obj-$(CONFIG_SH_SPI) += sh_spi.o
 obj-$(CONFIG_SH_QSPI) += sh_qspi.o
 obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
-obj-$(CONFIG_FDT_SPI) += fdt_spi.o
 obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
 obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o
 obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
diff --git a/drivers/spi/fdt_spi.c b/drivers/spi/fdt_spi.c
deleted file mode 100644
index 58f139a..0000000
--- a/drivers/spi/fdt_spi.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Common fdt based SPI driver front end
- *
- * Copyright (c) 2013 NVIDIA Corporation
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-#include <malloc.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-#include <asm/arch/clock.h>
-#include <asm/arch-tegra/clk_rst.h>
-#include <asm/arch-tegra20/tegra20_sflash.h>
-#include <asm/arch-tegra20/tegra20_slink.h>
-#include <asm/arch-tegra114/tegra114_spi.h>
-#include <spi.h>
-#include <fdtdec.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-struct fdt_spi_driver {
-	int compat;
-	int max_ctrls;
-	int (*init)(int *node_list, int count);
-	int (*claim_bus)(struct spi_slave *slave);
-	int (*release_bus)(struct spi_slave *slave);
-	int (*cs_is_valid)(unsigned int bus, unsigned int cs);
-	struct spi_slave *(*setup_slave)(unsigned int bus, unsigned int cs,
-					unsigned int max_hz, unsigned int mode);
-	void (*free_slave)(struct spi_slave *slave);
-	void (*cs_activate)(struct spi_slave *slave);
-	void (*cs_deactivate)(struct spi_slave *slave);
-	int (*xfer)(struct spi_slave *slave, unsigned int bitlen,
-		    const void *data_out, void *data_in, unsigned long flags);
-};
-
-static struct fdt_spi_driver fdt_spi_drivers[] = {
-#ifdef CONFIG_TEGRA20_SFLASH
-	{
-		.compat		= COMPAT_NVIDIA_TEGRA20_SFLASH,
-		.max_ctrls	= 1,
-		.init		= tegra20_spi_init,
-		.claim_bus	= tegra20_spi_claim_bus,
-		.cs_is_valid	= tegra20_spi_cs_is_valid,
-		.setup_slave	= tegra20_spi_setup_slave,
-		.free_slave	= tegra20_spi_free_slave,
-		.cs_activate	= tegra20_spi_cs_activate,
-		.cs_deactivate	= tegra20_spi_cs_deactivate,
-		.xfer		= tegra20_spi_xfer,
-	},
-#endif
-#ifdef CONFIG_TEGRA20_SLINK
-	{
-		.compat		= COMPAT_NVIDIA_TEGRA20_SLINK,
-		.max_ctrls	= CONFIG_TEGRA_SLINK_CTRLS,
-		.init		= tegra30_spi_init,
-		.claim_bus	= tegra30_spi_claim_bus,
-		.cs_is_valid	= tegra30_spi_cs_is_valid,
-		.setup_slave	= tegra30_spi_setup_slave,
-		.free_slave	= tegra30_spi_free_slave,
-		.cs_activate	= tegra30_spi_cs_activate,
-		.cs_deactivate	= tegra30_spi_cs_deactivate,
-		.xfer		= tegra30_spi_xfer,
-	},
-#endif
-#ifdef CONFIG_TEGRA114_SPI
-	{
-		.compat		= COMPAT_NVIDIA_TEGRA114_SPI,
-		.max_ctrls	= CONFIG_TEGRA114_SPI_CTRLS,
-		.init		= tegra114_spi_init,
-		.claim_bus	= tegra114_spi_claim_bus,
-		.cs_is_valid	= tegra114_spi_cs_is_valid,
-		.setup_slave	= tegra114_spi_setup_slave,
-		.free_slave	= tegra114_spi_free_slave,
-		.cs_activate	= tegra114_spi_cs_activate,
-		.cs_deactivate	= tegra114_spi_cs_deactivate,
-		.xfer		= tegra114_spi_xfer,
-	},
-#endif
-};
-
-static struct fdt_spi_driver *driver;
-
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-	if (!driver)
-		return 0;
-	else if (!driver->cs_is_valid)
-		return 1;
-	else
-		return driver->cs_is_valid(bus, cs);
-}
-
-struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
-		unsigned int max_hz, unsigned int mode)
-{
-	if (!driver || !driver->setup_slave)
-		return NULL;
-
-	return driver->setup_slave(bus, cs, max_hz, mode);
-}
-
-void spi_free_slave(struct spi_slave *slave)
-{
-	if (driver && driver->free_slave)
-		return driver->free_slave(slave);
-}
-
-static int spi_init_driver(struct fdt_spi_driver *driver)
-{
-	int count;
-	int node_list[driver->max_ctrls];
-
-	count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi",
-					   driver->compat,
-					   node_list,
-					   driver->max_ctrls);
-	return driver->init(node_list, count);
-}
-
-void spi_init(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(fdt_spi_drivers); i++) {
-		driver = &fdt_spi_drivers[i];
-		if (!spi_init_driver(driver))
-			break;
-	}
-	if (i == ARRAY_SIZE(fdt_spi_drivers))
-		driver = NULL;
-}
-
-int spi_claim_bus(struct spi_slave *slave)
-{
-	if (!driver)
-		return 1;
-	if (!driver->claim_bus)
-		return 0;
-
-	return driver->claim_bus(slave);
-}
-
-void spi_release_bus(struct spi_slave *slave)
-{
-	if (driver && driver->release_bus)
-		driver->release_bus(slave);
-}
-
-void spi_cs_activate(struct spi_slave *slave)
-{
-	if (driver && driver->cs_activate)
-		driver->cs_activate(slave);
-}
-
-void spi_cs_deactivate(struct spi_slave *slave)
-{
-	if (driver && driver->cs_deactivate)
-		driver->cs_deactivate(slave);
-}
-
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-	     const void *data_out, void *data_in, unsigned long flags)
-{
-	if (!driver || !driver->xfer)
-		return -1;
-
-	return driver->xfer(slave, bitlen, data_out, data_in, flags);
-}
diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c
index 810fa47..2d97625 100644
--- a/drivers/spi/tegra114_spi.c
+++ b/drivers/spi/tegra114_spi.c
@@ -22,14 +22,13 @@
  */
 
 #include <common.h>
-#include <malloc.h>
+#include <dm.h>
 #include <asm/io.h>
-#include <asm/gpio.h>
 #include <asm/arch/clock.h>
 #include <asm/arch-tegra/clk_rst.h>
-#include <asm/arch-tegra114/tegra114_spi.h>
 #include <spi.h>
 #include <fdtdec.h>
+#include "tegra_spi.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -104,130 +103,63 @@ struct spi_regs {
 	u32 spare_ctl;	/* 18c:SPI_SPARE_CTRL register */
 };
 
-struct tegra_spi_ctrl {
+struct tegra114_spi_priv {
 	struct spi_regs *regs;
 	unsigned int freq;
 	unsigned int mode;
 	int periph_id;
 	int valid;
+	int last_transaction_us;
 };
 
-struct tegra_spi_slave {
-	struct spi_slave slave;
-	struct tegra_spi_ctrl *ctrl;
-};
-
-static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA114_SPI_CTRLS];
-
-static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave)
+static int tegra114_spi_ofdata_to_platdata(struct udevice *bus)
 {
-	return container_of(slave, struct tegra_spi_slave, slave);
-}
+	struct tegra_spi_platdata *plat = bus->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = bus->of_offset;
 
-int tegra114_spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-	if (bus >= CONFIG_TEGRA114_SPI_CTRLS || cs > 3 || !spi_ctrls[bus].valid)
-		return 0;
-	else
-		return 1;
-}
+	plat->base = fdtdec_get_addr(blob, node, "reg");
+	plat->periph_id = clock_decode_periph_id(blob, node);
 
-struct spi_slave *tegra114_spi_setup_slave(unsigned int bus, unsigned int cs,
-		unsigned int max_hz, unsigned int mode)
-{
-	struct tegra_spi_slave *spi;
-
-	debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__,
-		bus, cs, max_hz, mode);
-
-	if (!spi_cs_is_valid(bus, cs)) {
-		printf("SPI error: unsupported bus %d / chip select %d\n",
-		       bus, cs);
-		return NULL;
-	}
-
-	if (max_hz > TEGRA_SPI_MAX_FREQ) {
-		printf("SPI error: unsupported frequency %d Hz. Max frequency"
-			" is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
-		return NULL;
+	if (plat->periph_id == PERIPH_ID_NONE) {
+		debug("%s: could not decode periph id %d\n", __func__,
+		      plat->periph_id);
+		return -FDT_ERR_NOTFOUND;
 	}
 
-	spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
-	if (!spi) {
-		printf("SPI error: malloc of SPI structure failed\n");
-		return NULL;
-	}
-	spi->ctrl = &spi_ctrls[bus];
-	if (!spi->ctrl) {
-		printf("SPI error: could not find controller for bus %d\n",
-		       bus);
-		return NULL;
-	}
+	/* Use 500KHz as a suitable default */
+	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+					500000);
+	plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+					"spi-deactivate-delay", 0);
+	debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+	      __func__, plat->base, plat->periph_id, plat->frequency,
+	      plat->deactivate_delay_us);
 
-	if (max_hz < spi->ctrl->freq) {
-		debug("%s: limiting frequency from %u to %u\n", __func__,
-		      spi->ctrl->freq, max_hz);
-		spi->ctrl->freq = max_hz;
-	}
-	spi->ctrl->mode = mode;
-
-	return &spi->slave;
-}
-
-void tegra114_spi_free_slave(struct spi_slave *slave)
-{
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-
-	free(spi);
+	return 0;
 }
 
-int tegra114_spi_init(int *node_list, int count)
+static int tegra114_spi_probe(struct udevice *bus)
 {
-	struct tegra_spi_ctrl *ctrl;
-	int i;
-	int node = 0;
-	int found = 0;
-
-	for (i = 0; i < count; i++) {
-		ctrl = &spi_ctrls[i];
-		node = node_list[i];
-
-		ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob,
-								 node, "reg");
-		if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) {
-			debug("%s: no spi register found\n", __func__);
-			continue;
-		}
-		ctrl->freq = fdtdec_get_int(gd->fdt_blob, node,
-					    "spi-max-frequency", 0);
-		if (!ctrl->freq) {
-			debug("%s: no spi max frequency found\n", __func__);
-			continue;
-		}
+	struct tegra_spi_platdata *plat = dev_get_platdata(bus);
+	struct tegra114_spi_priv *priv = dev_get_priv(bus);
 
-		ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
-		if (ctrl->periph_id == PERIPH_ID_NONE) {
-			debug("%s: could not decode periph id\n", __func__);
-			continue;
-		}
-		ctrl->valid = 1;
-		found = 1;
+	priv->regs = (struct spi_regs *)plat->base;
 
-		debug("%s: found controller at %p, freq = %u, periph_id = %d\n",
-		      __func__, ctrl->regs, ctrl->freq, ctrl->periph_id);
-	}
+	priv->last_transaction_us = timer_get_us();
+	priv->freq = plat->frequency;
+	priv->periph_id = plat->periph_id;
 
-	return !found;
+	return 0;
 }
 
-int tegra114_spi_claim_bus(struct spi_slave *slave)
+static int tegra114_spi_claim_bus(struct udevice *bus)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct tegra114_spi_priv *priv = dev_get_priv(bus);
+	struct spi_regs *regs = priv->regs;
 
 	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
-	clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH,
-			       spi->ctrl->freq);
+	clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH, priv->freq);
 
 	/* Clear stale status here */
 	setbits_le32(&regs->fifo_status,
@@ -244,33 +176,64 @@ int tegra114_spi_claim_bus(struct spi_slave *slave)
 
 	/* Set master mode and sw controlled CS */
 	setbits_le32(&regs->command1, SPI_CMD1_M_S | SPI_CMD1_CS_SW_HW |
-		     (spi->ctrl->mode << SPI_CMD1_MODE_SHIFT));
+		     (priv->mode << SPI_CMD1_MODE_SHIFT));
 	debug("%s: COMMAND1 = %08x\n", __func__, readl(&regs->command1));
 
 	return 0;
 }
 
-void tegra114_spi_cs_activate(struct spi_slave *slave)
+/**
+ * Activate the CS by driving it LOW
+ *
+ * @param slave	Pointer to spi_slave to which controller has to
+ *		communicate with
+ */
+static void spi_cs_activate(struct udevice *dev)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+	struct tegra114_spi_priv *priv = dev_get_priv(bus);
+
+	/* If it's too soon to do another transaction, wait */
+	if (pdata->deactivate_delay_us &&
+	    priv->last_transaction_us) {
+		ulong delay_us;		/* The delay completed so far */
+		delay_us = timer_get_us() - priv->last_transaction_us;
+		if (delay_us < pdata->deactivate_delay_us)
+			udelay(pdata->deactivate_delay_us - delay_us);
+	}
 
-	clrbits_le32(&regs->command1, SPI_CMD1_CS_SW_VAL);
+	clrbits_le32(&priv->regs->command1, SPI_CMD1_CS_SW_VAL);
 }
 
-void tegra114_spi_cs_deactivate(struct spi_slave *slave)
+/**
+ * Deactivate the CS by driving it HIGH
+ *
+ * @param slave	Pointer to spi_slave to which controller has to
+ *		communicate with
+ */
+static void spi_cs_deactivate(struct udevice *dev)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+	struct tegra114_spi_priv *priv = dev_get_priv(bus);
+
+	setbits_le32(&priv->regs->command1, SPI_CMD1_CS_SW_VAL);
 
-	setbits_le32(&regs->command1, SPI_CMD1_CS_SW_VAL);
+	/* Remember time of this transaction so we can honour the bus delay */
+	if (pdata->deactivate_delay_us)
+		priv->last_transaction_us = timer_get_us();
+
+	debug("Deactivate CS, bus '%s'\n", bus->name);
 }
 
-int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-		const void *data_out, void *data_in, unsigned long flags)
+static int tegra114_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			     const void *data_out, void *data_in,
+			     unsigned long flags)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra114_spi_priv *priv = dev_get_priv(bus);
+	struct spi_regs *regs = priv->regs;
 	u32 reg, tmpdout, tmpdin = 0;
 	const u8 *dout = data_out;
 	u8 *din = data_in;
@@ -278,7 +241,7 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	int ret;
 
 	debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
-	      __func__, slave->bus, slave->cs, dout, din, bitlen);
+	      __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
 	if (bitlen % 8)
 		return -1;
 	num_bytes = bitlen / 8;
@@ -291,13 +254,13 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
 	clrsetbits_le32(&regs->command1, SPI_CMD1_CS_SW_VAL,
 			SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE |
-			(slave->cs << SPI_CMD1_CS_SEL_SHIFT));
+			(spi_chip_select(dev) << SPI_CMD1_CS_SEL_SHIFT));
 
 	/* set xfer size to 1 block (32 bits) */
 	writel(0, &regs->dma_blk);
 
 	if (flags & SPI_XFER_BEGIN)
-		spi_cs_activate(slave);
+		spi_cs_activate(dev);
 
 	/* handle data in 32-bit chunks */
 	while (num_bytes > 0) {
@@ -383,7 +346,7 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	}
 
 	if (flags & SPI_XFER_END)
-		spi_cs_deactivate(slave);
+		spi_cs_deactivate(dev);
 
 	debug("%s: transfer ended. Value=%08x, fifo_status = %08x\n",
 	      __func__, tmpdin, readl(&regs->fifo_status));
@@ -394,5 +357,56 @@ int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 		return -1;
 	}
 
+	return ret;
+}
+
+static int tegra114_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct tegra_spi_platdata *plat = bus->platdata;
+	struct tegra114_spi_priv *priv = dev_get_priv(bus);
+
+	if (speed > plat->frequency)
+		speed = plat->frequency;
+	priv->freq = speed;
+	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
 	return 0;
 }
+
+static int tegra114_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct tegra114_spi_priv *priv = dev_get_priv(bus);
+
+	priv->mode = mode;
+	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+	return 0;
+}
+
+static const struct dm_spi_ops tegra114_spi_ops = {
+	.claim_bus	= tegra114_spi_claim_bus,
+	.xfer		= tegra114_spi_xfer,
+	.set_speed	= tegra114_spi_set_speed,
+	.set_mode	= tegra114_spi_set_mode,
+	/*
+	 * cs_info is not needed, since we require all chip selects to be
+	 * in the device tree explicitly
+	 */
+};
+
+static const struct udevice_id tegra114_spi_ids[] = {
+	{ .compatible = "nvidia,tegra114-spi" },
+	{ }
+};
+
+U_BOOT_DRIVER(tegra114_spi) = {
+	.name	= "tegra114_spi",
+	.id	= UCLASS_SPI,
+	.of_match = tegra114_spi_ids,
+	.ops	= &tegra114_spi_ops,
+	.ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
+	.priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
+	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
+	.probe	= tegra114_spi_probe,
+};
diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c
index b5d561b..7d0d0f3 100644
--- a/drivers/spi/tegra20_sflash.c
+++ b/drivers/spi/tegra20_sflash.c
@@ -7,15 +7,16 @@
  */
 
 #include <common.h>
-#include <malloc.h>
+#include <dm.h>
+#include <errno.h>
 #include <asm/io.h>
 #include <asm/gpio.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch-tegra/clk_rst.h>
-#include <asm/arch-tegra20/tegra20_sflash.h>
 #include <spi.h>
 #include <fdtdec.h>
+#include "tegra_spi.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -64,129 +65,75 @@ struct spi_regs {
 	u32 rx_fifo;	/* SPI_RX_FIFO_0 register */
 };
 
-struct tegra_spi_ctrl {
+struct tegra20_sflash_priv {
 	struct spi_regs *regs;
 	unsigned int freq;
 	unsigned int mode;
 	int periph_id;
 	int valid;
+	int last_transaction_us;
 };
 
-struct tegra_spi_slave {
-	struct spi_slave slave;
-	struct tegra_spi_ctrl *ctrl;
-};
-
-/* tegra20 only supports one SFLASH controller */
-static struct tegra_spi_ctrl spi_ctrls[1];
-
-static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave)
-{
-	return container_of(slave, struct tegra_spi_slave, slave);
-}
-
-int tegra20_spi_cs_is_valid(unsigned int bus, unsigned int cs)
+int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
+			   struct spi_cs_info *info)
 {
 	/* Tegra20 SPI-Flash - only 1 device ('bus/cs') */
-	if (bus != 0 || cs != 0)
-		return 0;
+	if (cs != 0)
+		return -ENODEV;
 	else
-		return 1;
+		return 0;
 }
 
-struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs,
-				  unsigned int max_hz, unsigned int mode)
+static int tegra20_sflash_ofdata_to_platdata(struct udevice *bus)
 {
-	struct tegra_spi_slave *spi;
+	struct tegra_spi_platdata *plat = bus->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = bus->of_offset;
 
-	if (!spi_cs_is_valid(bus, cs)) {
-		printf("SPI error: unsupported bus %d / chip select %d\n",
-		       bus, cs);
-		return NULL;
-	}
+	plat->base = fdtdec_get_addr(blob, node, "reg");
+	plat->periph_id = clock_decode_periph_id(blob, node);
 
-	if (max_hz > TEGRA_SPI_MAX_FREQ) {
-		printf("SPI error: unsupported frequency %d Hz. Max frequency"
-			" is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
-		return NULL;
+	if (plat->periph_id == PERIPH_ID_NONE) {
+		debug("%s: could not decode periph id %d\n", __func__,
+		      plat->periph_id);
+		return -FDT_ERR_NOTFOUND;
 	}
 
-	spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
-	if (!spi) {
-		printf("SPI error: malloc of SPI structure failed\n");
-		return NULL;
-	}
-	spi->ctrl = &spi_ctrls[bus];
-	if (!spi->ctrl) {
-		printf("SPI error: could not find controller for bus %d\n",
-		       bus);
-		return NULL;
-	}
+	/* Use 500KHz as a suitable default */
+	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+					500000);
+	plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+					"spi-deactivate-delay", 0);
+	debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+	      __func__, plat->base, plat->periph_id, plat->frequency,
+	      plat->deactivate_delay_us);
 
-	if (max_hz < spi->ctrl->freq) {
-		debug("%s: limiting frequency from %u to %u\n", __func__,
-		      spi->ctrl->freq, max_hz);
-		spi->ctrl->freq = max_hz;
-	}
-	spi->ctrl->mode = mode;
-
-	return &spi->slave;
+	return 0;
 }
 
-void tegra20_spi_free_slave(struct spi_slave *slave)
+static int tegra20_sflash_probe(struct udevice *bus)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-
-	free(spi);
-}
+	struct tegra_spi_platdata *plat = dev_get_platdata(bus);
+	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
 
-int tegra20_spi_init(int *node_list, int count)
-{
-	struct tegra_spi_ctrl *ctrl;
-	int i;
-	int node = 0;
-	int found = 0;
-
-	for (i = 0; i < count; i++) {
-		ctrl = &spi_ctrls[i];
-		node = node_list[i];
-
-		ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob,
-								node, "reg");
-		if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) {
-			debug("%s: no slink register found\n", __func__);
-			continue;
-		}
-		ctrl->freq = fdtdec_get_int(gd->fdt_blob, node,
-					    "spi-max-frequency", 0);
-		if (!ctrl->freq) {
-			debug("%s: no slink max frequency found\n", __func__);
-			continue;
-		}
+	priv->regs = (struct spi_regs *)plat->base;
 
-		ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
-		if (ctrl->periph_id == PERIPH_ID_NONE) {
-			debug("%s: could not decode periph id\n", __func__);
-			continue;
-		}
-		ctrl->valid = 1;
-		found = 1;
+	priv->last_transaction_us = timer_get_us();
+	priv->freq = plat->frequency;
+	priv->periph_id = plat->periph_id;
 
-		debug("%s: found controller at %p, freq = %u, periph_id = %d\n",
-		      __func__, ctrl->regs, ctrl->freq, ctrl->periph_id);
-	}
-	return !found;
+	return 0;
 }
 
-int tegra20_spi_claim_bus(struct spi_slave *slave)
+static int tegra20_sflash_claim_bus(struct udevice *bus)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+	struct spi_regs *regs = priv->regs;
 	u32 reg;
 
 	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
-	clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH,
-			       spi->ctrl->freq);
+	clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH,
+			       priv->freq);
 
 	/* Clear stale status here */
 	reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \
@@ -197,8 +144,8 @@ int tegra20_spi_claim_bus(struct spi_slave *slave)
 	/*
 	 * Use sw-controlled CS, so we can clock in data after ReadID, etc.
 	 */
-	reg = (spi->ctrl->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT;
-	if (spi->ctrl->mode & 2)
+	reg = (priv->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT;
+	if (priv->mode & 2)
 		reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT;
 	clrsetbits_le32(&regs->command, SPI_CMD_ACTIVE_SCLK_MASK |
 		SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg);
@@ -215,37 +162,54 @@ int tegra20_spi_claim_bus(struct spi_slave *slave)
 	return 0;
 }
 
-void tegra20_spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_activate(struct udevice *dev)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+
+	/* If it's too soon to do another transaction, wait */
+	if (pdata->deactivate_delay_us &&
+	    priv->last_transaction_us) {
+		ulong delay_us;		/* The delay completed so far */
+		delay_us = timer_get_us() - priv->last_transaction_us;
+		if (delay_us < pdata->deactivate_delay_us)
+			udelay(pdata->deactivate_delay_us - delay_us);
+	}
 
 	/* CS is negated on Tegra, so drive a 1 to get a 0 */
-	setbits_le32(&regs->command, SPI_CMD_CS_VAL);
+	setbits_le32(&priv->regs->command, SPI_CMD_CS_VAL);
 }
 
-void tegra20_spi_cs_deactivate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
 
 	/* CS is negated on Tegra, so drive a 0 to get a 1 */
-	clrbits_le32(&regs->command, SPI_CMD_CS_VAL);
+	clrbits_le32(&priv->regs->command, SPI_CMD_CS_VAL);
+
+	/* Remember time of this transaction so we can honour the bus delay */
+	if (pdata->deactivate_delay_us)
+		priv->last_transaction_us = timer_get_us();
 }
 
-int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-		const void *data_out, void *data_in, unsigned long flags)
+static int tegra20_sflash_xfer(struct udevice *dev, unsigned int bitlen,
+			     const void *data_out, void *data_in,
+			     unsigned long flags)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+	struct spi_regs *regs = priv->regs;
 	u32 reg, tmpdout, tmpdin = 0;
 	const u8 *dout = data_out;
 	u8 *din = data_in;
 	int num_bytes;
 	int ret;
 
-	debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
-	      slave->bus, slave->cs, *(u8 *)dout, *(u8 *)din, bitlen);
+	debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
+	      __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
 	if (bitlen % 8)
 		return -1;
 	num_bytes = bitlen / 8;
@@ -262,7 +226,7 @@ int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	debug("spi_xfer: COMMAND = %08x\n", readl(&regs->command));
 
 	if (flags & SPI_XFER_BEGIN)
-		spi_cs_activate(slave);
+		spi_cs_activate(dev);
 
 	/* handle data in 32-bit chunks */
 	while (num_bytes > 0) {
@@ -327,7 +291,7 @@ int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	}
 
 	if (flags & SPI_XFER_END)
-		spi_cs_deactivate(slave);
+		spi_cs_deactivate(dev);
 
 	debug("spi_xfer: transfer ended. Value=%08x, status = %08x\n",
 		tmpdin, readl(&regs->status));
@@ -339,3 +303,51 @@ int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
 	return 0;
 }
+
+static int tegra20_sflash_set_speed(struct udevice *bus, uint speed)
+{
+	struct tegra_spi_platdata *plat = bus->platdata;
+	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+
+	if (speed > plat->frequency)
+		speed = plat->frequency;
+	priv->freq = speed;
+	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+	return 0;
+}
+
+static int tegra20_sflash_set_mode(struct udevice *bus, uint mode)
+{
+	struct tegra20_sflash_priv *priv = dev_get_priv(bus);
+
+	priv->mode = mode;
+	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+	return 0;
+}
+
+static const struct dm_spi_ops tegra20_sflash_ops = {
+	.claim_bus	= tegra20_sflash_claim_bus,
+	.xfer		= tegra20_sflash_xfer,
+	.set_speed	= tegra20_sflash_set_speed,
+	.set_mode	= tegra20_sflash_set_mode,
+	.cs_info	= tegra20_sflash_cs_info,
+};
+
+static const struct udevice_id tegra20_sflash_ids[] = {
+	{ .compatible = "nvidia,tegra20-sflash" },
+	{ }
+};
+
+U_BOOT_DRIVER(tegra20_sflash) = {
+	.name	= "tegra20_sflash",
+	.id	= UCLASS_SPI,
+	.of_match = tegra20_sflash_ids,
+	.ops	= &tegra20_sflash_ops,
+	.ofdata_to_platdata = tegra20_sflash_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
+	.priv_auto_alloc_size = sizeof(struct tegra20_sflash_priv),
+	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
+	.probe	= tegra20_sflash_probe,
+};
diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c
index 664de6e..213fa5f 100644
--- a/drivers/spi/tegra20_slink.c
+++ b/drivers/spi/tegra20_slink.c
@@ -22,14 +22,13 @@
  */
 
 #include <common.h>
-#include <malloc.h>
+#include <dm.h>
 #include <asm/io.h>
-#include <asm/gpio.h>
 #include <asm/arch/clock.h>
 #include <asm/arch-tegra/clk_rst.h>
-#include <asm/arch-tegra20/tegra20_slink.h>
 #include <spi.h>
 #include <fdtdec.h>
+#include "tegra_spi.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -87,130 +86,70 @@ struct spi_regs {
 	u32 rx_fifo;	/* SLINK_RX_FIFO_0 reg off 180h */
 };
 
-struct tegra_spi_ctrl {
+struct tegra30_spi_priv {
 	struct spi_regs *regs;
 	unsigned int freq;
 	unsigned int mode;
 	int periph_id;
 	int valid;
+	int last_transaction_us;
 };
 
 struct tegra_spi_slave {
 	struct spi_slave slave;
-	struct tegra_spi_ctrl *ctrl;
+	struct tegra30_spi_priv *ctrl;
 };
 
-static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA_SLINK_CTRLS];
-
-static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave)
-{
-	return container_of(slave, struct tegra_spi_slave, slave);
-}
-
-int tegra30_spi_cs_is_valid(unsigned int bus, unsigned int cs)
+static int tegra30_spi_ofdata_to_platdata(struct udevice *bus)
 {
-	if (bus >= CONFIG_TEGRA_SLINK_CTRLS || cs > 3 || !spi_ctrls[bus].valid)
-		return 0;
-	else
-		return 1;
-}
+	struct tegra_spi_platdata *plat = bus->platdata;
+	const void *blob = gd->fdt_blob;
+	int node = bus->of_offset;
 
-struct spi_slave *tegra30_spi_setup_slave(unsigned int bus, unsigned int cs,
-		unsigned int max_hz, unsigned int mode)
-{
-	struct tegra_spi_slave *spi;
+	plat->base = fdtdec_get_addr(blob, node, "reg");
+	plat->periph_id = clock_decode_periph_id(blob, node);
 
-	debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__,
-		bus, cs, max_hz, mode);
-
-	if (!spi_cs_is_valid(bus, cs)) {
-		printf("SPI error: unsupported bus %d / chip select %d\n",
-		       bus, cs);
-		return NULL;
-	}
-
-	if (max_hz > TEGRA_SPI_MAX_FREQ) {
-		printf("SPI error: unsupported frequency %d Hz. Max frequency"
-			" is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
-		return NULL;
+	if (plat->periph_id == PERIPH_ID_NONE) {
+		debug("%s: could not decode periph id %d\n", __func__,
+		      plat->periph_id);
+		return -FDT_ERR_NOTFOUND;
 	}
 
-	spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs);
-	if (!spi) {
-		printf("SPI error: malloc of SPI structure failed\n");
-		return NULL;
-	}
-	spi->ctrl = &spi_ctrls[bus];
-	if (!spi->ctrl) {
-		printf("SPI error: could not find controller for bus %d\n",
-		       bus);
-		return NULL;
-	}
+	/* Use 500KHz as a suitable default */
+	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
+					500000);
+	plat->deactivate_delay_us = fdtdec_get_int(blob, node,
+					"spi-deactivate-delay", 0);
+	debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
+	      __func__, plat->base, plat->periph_id, plat->frequency,
+	      plat->deactivate_delay_us);
 
-	if (max_hz < spi->ctrl->freq) {
-		debug("%s: limiting frequency from %u to %u\n", __func__,
-		      spi->ctrl->freq, max_hz);
-		spi->ctrl->freq = max_hz;
-	}
-	spi->ctrl->mode = mode;
-
-	return &spi->slave;
+	return 0;
 }
 
-void tegra30_spi_free_slave(struct spi_slave *slave)
+static int tegra30_spi_probe(struct udevice *bus)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-
-	free(spi);
-}
+	struct tegra_spi_platdata *plat = dev_get_platdata(bus);
+	struct tegra30_spi_priv *priv = dev_get_priv(bus);
 
-int tegra30_spi_init(int *node_list, int count)
-{
-	struct tegra_spi_ctrl *ctrl;
-	int i;
-	int node = 0;
-	int found = 0;
-
-	for (i = 0; i < count; i++) {
-		ctrl = &spi_ctrls[i];
-		node = node_list[i];
-
-		ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob,
-								node, "reg");
-		if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) {
-			debug("%s: no slink register found\n", __func__);
-			continue;
-		}
-		ctrl->freq = fdtdec_get_int(gd->fdt_blob, node,
-					    "spi-max-frequency", 0);
-		if (!ctrl->freq) {
-			debug("%s: no slink max frequency found\n", __func__);
-			continue;
-		}
+	priv->regs = (struct spi_regs *)plat->base;
 
-		ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node);
-		if (ctrl->periph_id == PERIPH_ID_NONE) {
-			debug("%s: could not decode periph id\n", __func__);
-			continue;
-		}
-		ctrl->valid = 1;
-		found = 1;
+	priv->last_transaction_us = timer_get_us();
+	priv->freq = plat->frequency;
+	priv->periph_id = plat->periph_id;
 
-		debug("%s: found controller at %p, freq = %u, periph_id = %d\n",
-		      __func__, ctrl->regs, ctrl->freq, ctrl->periph_id);
-	}
-	return !found;
+	return 0;
 }
 
-int tegra30_spi_claim_bus(struct spi_slave *slave)
+static int tegra30_spi_claim_bus(struct udevice *bus)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct tegra30_spi_priv *priv = dev_get_priv(bus);
+	struct spi_regs *regs = priv->regs;
 	u32 reg;
 
 	/* Change SPI clock to correct frequency, PLLP_OUT0 source */
-	clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH,
-			       spi->ctrl->freq);
+	clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH,
+			       priv->freq);
 
 	/* Clear stale status here */
 	reg = SLINK_STAT_RDY | SLINK_STAT_RXF_FLUSH | SLINK_STAT_TXF_FLUSH | \
@@ -227,29 +166,46 @@ int tegra30_spi_claim_bus(struct spi_slave *slave)
 	return 0;
 }
 
-void tegra30_spi_cs_activate(struct spi_slave *slave)
+static void spi_cs_activate(struct udevice *dev)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+	struct tegra30_spi_priv *priv = dev_get_priv(bus);
+
+	/* If it's too soon to do another transaction, wait */
+	if (pdata->deactivate_delay_us &&
+	    priv->last_transaction_us) {
+		ulong delay_us;		/* The delay completed so far */
+		delay_us = timer_get_us() - priv->last_transaction_us;
+		if (delay_us < pdata->deactivate_delay_us)
+			udelay(pdata->deactivate_delay_us - delay_us);
+	}
 
 	/* CS is negated on Tegra, so drive a 1 to get a 0 */
-	setbits_le32(&regs->command, SLINK_CMD_CS_VAL);
+	setbits_le32(&priv->regs->command, SLINK_CMD_CS_VAL);
 }
 
-void tegra30_spi_cs_deactivate(struct spi_slave *slave)
+static void spi_cs_deactivate(struct udevice *dev)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
+	struct tegra30_spi_priv *priv = dev_get_priv(bus);
 
 	/* CS is negated on Tegra, so drive a 0 to get a 1 */
-	clrbits_le32(&regs->command, SLINK_CMD_CS_VAL);
+	clrbits_le32(&priv->regs->command, SLINK_CMD_CS_VAL);
+
+	/* Remember time of this transaction so we can honour the bus delay */
+	if (pdata->deactivate_delay_us)
+		priv->last_transaction_us = timer_get_us();
 }
 
-int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-		const void *data_out, void *data_in, unsigned long flags)
+static int tegra30_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			    const void *data_out, void *data_in,
+			    unsigned long flags)
 {
-	struct tegra_spi_slave *spi = to_tegra_spi(slave);
-	struct spi_regs *regs = spi->ctrl->regs;
+	struct udevice *bus = dev->parent;
+	struct tegra30_spi_priv *priv = dev_get_priv(bus);
+	struct spi_regs *regs = priv->regs;
 	u32 reg, tmpdout, tmpdin = 0;
 	const u8 *dout = data_out;
 	u8 *din = data_in;
@@ -257,7 +213,7 @@ int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	int ret;
 
 	debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
-	      __func__, slave->bus, slave->cs, dout, din, bitlen);
+	      __func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
 	if (bitlen % 8)
 		return -1;
 	num_bytes = bitlen / 8;
@@ -276,11 +232,11 @@ int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
 	clrsetbits_le32(&regs->command2, SLINK_CMD2_SS_EN_MASK,
 			SLINK_CMD2_TXEN | SLINK_CMD2_RXEN |
-			(slave->cs << SLINK_CMD2_SS_EN_SHIFT));
+			(spi_chip_select(dev) << SLINK_CMD2_SS_EN_SHIFT));
 	debug("%s entry: COMMAND2 = %08x\n", __func__, readl(&regs->command2));
 
 	if (flags & SPI_XFER_BEGIN)
-		spi_cs_activate(slave);
+		spi_cs_activate(dev);
 
 	/* handle data in 32-bit chunks */
 	while (num_bytes > 0) {
@@ -344,7 +300,7 @@ int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	}
 
 	if (flags & SPI_XFER_END)
-		spi_cs_deactivate(slave);
+		spi_cs_deactivate(dev);
 
 	debug("%s: transfer ended. Value=%08x, status = %08x\n",
 	      __func__, tmpdin, readl(&regs->status));
@@ -357,3 +313,54 @@ int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 
 	return 0;
 }
+
+static int tegra30_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct tegra_spi_platdata *plat = bus->platdata;
+	struct tegra30_spi_priv *priv = dev_get_priv(bus);
+
+	if (speed > plat->frequency)
+		speed = plat->frequency;
+	priv->freq = speed;
+	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
+
+	return 0;
+}
+
+static int tegra30_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct tegra30_spi_priv *priv = dev_get_priv(bus);
+
+	priv->mode = mode;
+	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
+
+	return 0;
+}
+
+static const struct dm_spi_ops tegra30_spi_ops = {
+	.claim_bus	= tegra30_spi_claim_bus,
+	.xfer		= tegra30_spi_xfer,
+	.set_speed	= tegra30_spi_set_speed,
+	.set_mode	= tegra30_spi_set_mode,
+	/*
+	 * cs_info is not needed, since we require all chip selects to be
+	 * in the device tree explicitly
+	 */
+};
+
+static const struct udevice_id tegra30_spi_ids[] = {
+	{ .compatible = "nvidia,tegra20-slink" },
+	{ }
+};
+
+U_BOOT_DRIVER(tegra30_spi) = {
+	.name	= "tegra20_slink",
+	.id	= UCLASS_SPI,
+	.of_match = tegra30_spi_ids,
+	.ops	= &tegra30_spi_ops,
+	.ofdata_to_platdata = tegra30_spi_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
+	.priv_auto_alloc_size = sizeof(struct tegra30_spi_priv),
+	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
+	.probe	= tegra30_spi_probe,
+};
diff --git a/drivers/spi/tegra_spi.h b/drivers/spi/tegra_spi.h
new file mode 100644
index 0000000..fb2b50f
--- /dev/null
+++ b/drivers/spi/tegra_spi.h
@@ -0,0 +1,12 @@
+/*
+ * (C) Copyright 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+struct tegra_spi_platdata {
+	enum periph_id periph_id;
+	int frequency;		/* Default clock frequency, -1 for none */
+	ulong base;
+	uint deactivate_delay_us;	/* Delay to wait after deactivate */
+};
diff --git a/include/configs/tegra-common-post.h b/include/configs/tegra-common-post.h
index 23e3c8a..a258699 100644
--- a/include/configs/tegra-common-post.h
+++ b/include/configs/tegra-common-post.h
@@ -59,7 +59,7 @@
 	BOARD_EXTRA_ENV_SETTINGS
 
 #if defined(CONFIG_TEGRA20_SFLASH) || defined(CONFIG_TEGRA20_SLINK) || defined(CONFIG_TEGRA114_SPI)
-#define CONFIG_FDT_SPI
+#define CONFIG_TEGRA_SPI
 #endif
 
 /* overrides for SPL build here */
diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h
index 834b3d5..4719ee1 100644
--- a/include/configs/tegra-common.h
+++ b/include/configs/tegra-common.h
@@ -24,6 +24,8 @@
 #ifndef CONFIG_SPL_BUILD
 #define CONFIG_DM_SERIAL
 #endif
+#define CONFIG_DM_SPI
+#define CONFIG_DM_SPI_FLASH
 
 #define CONFIG_SYS_TIMER_RATE		1000000
 #define CONFIG_SYS_TIMER_COUNTER	NV_PA_TMRUS_BASE
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 27/29] dm: cros_ec: Add support for driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (25 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 26/29] dm: tegra: spi: Convert to driver model Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 28/29] dm: sandbox: cros_ec: Move sandbox cros_ec to driver module Simon Glass
                   ` (3 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Add support for driver model if enabled. This involves minimal changes
to the code, mostly just plumbing around the edges.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Add a missing tab character

Changes in v2: None

 common/cros_ec.c               |  30 ++++++++++
 drivers/misc/cros_ec.c         | 122 +++++++++++++++++++++++++++++++++++++----
 drivers/misc/cros_ec_sandbox.c |   9 ++-
 include/cros_ec.h              |  27 ++++++++-
 include/dm/uclass-id.h         |   1 +
 5 files changed, 174 insertions(+), 15 deletions(-)

diff --git a/common/cros_ec.c b/common/cros_ec.c
index b8ce1b5..bb299bc 100644
--- a/common/cros_ec.c
+++ b/common/cros_ec.c
@@ -10,25 +10,44 @@
 
 #include <common.h>
 #include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
+
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_DM_CROS_EC
 struct local_info {
 	struct cros_ec_dev *cros_ec_dev;	/* Pointer to cros_ec device */
 	int cros_ec_err;			/* Error for cros_ec, 0 if ok */
 };
 
 static struct local_info local;
+#endif
 
 struct cros_ec_dev *board_get_cros_ec_dev(void)
 {
+#ifdef CONFIG_DM_CROS_EC
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
+	if (ret) {
+		debug("%s: Error %d\n", __func__, ret);
+		return NULL;
+	}
+	return dev->uclass_priv;
+#else
 	return local.cros_ec_dev;
+#endif
 }
 
 static int board_init_cros_ec_devices(const void *blob)
 {
+#ifndef CONFIG_DM_CROS_EC
 	local.cros_ec_err = cros_ec_init(blob, &local.cros_ec_dev);
 	if (local.cros_ec_err)
 		return -1;  /* Will report in board_late_init() */
+#endif
 
 	return 0;
 }
@@ -40,5 +59,16 @@ int cros_ec_board_init(void)
 
 int cros_ec_get_error(void)
 {
+#ifdef CONFIG_DM_CROS_EC
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get_device(UCLASS_CROS_EC, 0, &dev);
+	if (ret && ret != -ENODEV)
+		return ret;
+
+	return 0;
+#else
 	return local.cros_ec_err;
+#endif
 }
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 068373b..521edfd 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -16,6 +16,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <i2c.h>
 #include <cros_ec.h>
 #include <fdtdec.h>
@@ -24,6 +25,8 @@
 #include <asm/errno.h>
 #include <asm/io.h>
 #include <asm-generic/gpio.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
 
 #ifdef DEBUG_TRACE
 #define debug_trace(fmt, b...)	debug(fmt, #b)
@@ -38,7 +41,9 @@ enum {
 	CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
 };
 
+#ifndef CONFIG_DM_CROS_EC
 static struct cros_ec_dev static_dev, *last_dev;
+#endif
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -204,6 +209,9 @@ static int send_command_proto3(struct cros_ec_dev *dev,
 			       const void *dout, int dout_len,
 			       uint8_t **dinp, int din_len)
 {
+#ifdef CONFIG_DM_CROS_EC
+	struct dm_cros_ec_ops *ops;
+#endif
 	int out_bytes, in_bytes;
 	int rv;
 
@@ -218,6 +226,10 @@ static int send_command_proto3(struct cros_ec_dev *dev,
 	if (in_bytes < 0)
 		return in_bytes;
 
+#ifdef CONFIG_DM_CROS_EC
+	ops = dm_cros_ec_get_ops(dev->dev);
+	rv = ops->packet(dev->dev, out_bytes, in_bytes);
+#else
 	switch (dev->interface) {
 #ifdef CONFIG_CROS_EC_SPI
 	case CROS_EC_IF_SPI:
@@ -235,6 +247,7 @@ static int send_command_proto3(struct cros_ec_dev *dev,
 		debug("%s: Unsupported interface\n", __func__);
 		rv = -1;
 	}
+#endif
 	if (rv < 0)
 		return rv;
 
@@ -246,6 +259,9 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 			const void *dout, int dout_len,
 			uint8_t **dinp, int din_len)
 {
+#ifdef CONFIG_DM_CROS_EC
+	struct dm_cros_ec_ops *ops;
+#endif
 	int ret = -1;
 
 	/* Handle protocol version 3 support */
@@ -254,6 +270,11 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 					   dout, dout_len, dinp, din_len);
 	}
 
+#ifdef CONFIG_DM_CROS_EC
+	ops = dm_cros_ec_get_ops(dev->dev);
+	ret = ops->command(dev->dev, cmd, cmd_version,
+			   (const uint8_t *)dout, dout_len, dinp, din_len);
+#else
 	switch (dev->interface) {
 #ifdef CONFIG_CROS_EC_SPI
 	case CROS_EC_IF_SPI:
@@ -280,6 +301,7 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 	default:
 		ret = -1;
 	}
+#endif
 
 	return ret;
 }
@@ -990,6 +1012,7 @@ int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
 	return 0;
 }
 
+#ifndef CONFIG_DM_CROS_EC
 /**
  * Decode EC interface details from the device tree and allocate a suitable
  * device.
@@ -1055,11 +1078,61 @@ static int cros_ec_decode_fdt(const void *blob, int node,
 
 	return 0;
 }
+#endif
 
-int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_register(struct udevice *dev)
 {
+	struct cros_ec_dev *cdev = dev->uclass_priv;
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
 	char id[MSG_BYTES];
+
+	cdev->dev = dev;
+	fdtdec_decode_gpio(blob, node, "ec-interrupt", &cdev->ec_int);
+	cdev->optimise_flash_write = fdtdec_get_bool(blob, node,
+						     "optimise-flash-write");
+
+	/* we will poll the EC interrupt line */
+	fdtdec_setup_gpio(&cdev->ec_int);
+	if (fdt_gpio_isvalid(&cdev->ec_int)) {
+		gpio_request(cdev->ec_int.gpio, "cros-ec-irq");
+		gpio_direction_input(cdev->ec_int.gpio);
+	}
+
+	if (cros_ec_check_version(cdev)) {
+		debug("%s: Could not detect CROS-EC version\n", __func__);
+		return -CROS_EC_ERR_CHECK_VERSION;
+	}
+
+	if (cros_ec_read_id(cdev, id, sizeof(id))) {
+		debug("%s: Could not read KBC ID\n", __func__);
+		return -CROS_EC_ERR_READ_ID;
+	}
+
+	/* Remember this device for use by the cros_ec command */
+	debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
+
+	return 0;
+}
+#else
+int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+{
 	struct cros_ec_dev *dev;
+	char id[MSG_BYTES];
+#ifdef CONFIG_DM_CROS_EC
+	struct udevice *udev;
+	int ret;
+
+	ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev);
+	if (!ret)
+		device_remove(udev);
+	ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
+	if (ret)
+		return ret;
+	dev = udev->uclass_priv;
+	return 0;
+#else
 	int node = 0;
 
 	*cros_ecp = NULL;
@@ -1108,11 +1181,14 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
 	default:
 		return 0;
 	}
+#endif
 
 	/* we will poll the EC interrupt line */
 	fdtdec_setup_gpio(&dev->ec_int);
-	if (fdt_gpio_isvalid(&dev->ec_int))
+	if (fdt_gpio_isvalid(&dev->ec_int)) {
+		gpio_request(dev->ec_int.gpio, "cros-ec-irq");
 		gpio_direction_input(dev->ec_int.gpio);
+	}
 
 	if (cros_ec_check_version(dev)) {
 		debug("%s: Could not detect CROS-EC version\n", __func__);
@@ -1125,11 +1201,15 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
 	}
 
 	/* Remember this device for use by the cros_ec command */
-	last_dev = *cros_ecp = dev;
+	*cros_ecp = dev;
+#ifndef CONFIG_DM_CROS_EC
+	last_dev = dev;
+#endif
 	debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
 
 	return 0;
 }
+#endif
 
 int cros_ec_decode_region(int argc, char * const argv[])
 {
@@ -1147,15 +1227,10 @@ int cros_ec_decode_region(int argc, char * const argv[])
 	return -1;
 }
 
-int cros_ec_decode_ec_flash(const void *blob, struct fdt_cros_ec *config)
+int cros_ec_decode_ec_flash(const void *blob, int node,
+			    struct fdt_cros_ec *config)
 {
-	int flash_node, node;
-
-	node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC);
-	if (node < 0) {
-		debug("Failed to find chrome-ec node'\n");
-		return -1;
-	}
+	int flash_node;
 
 	flash_node = fdt_subnode_offset(blob, node, "flash");
 	if (flash_node < 0) {
@@ -1516,7 +1591,10 @@ static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag,
 
 static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	struct cros_ec_dev *dev = last_dev;
+	struct cros_ec_dev *dev;
+#ifdef CONFIG_DM_CROS_EC
+	struct udevice *udev;
+#endif
 	const char *cmd;
 	int ret = 0;
 
@@ -1525,19 +1603,31 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
 	cmd = argv[1];
 	if (0 == strcmp("init", cmd)) {
+#ifndef CONFIG_DM_CROS_EC
 		ret = cros_ec_init(gd->fdt_blob, &dev);
 		if (ret) {
 			printf("Could not init cros_ec device (err %d)\n", ret);
 			return 1;
 		}
+#endif
 		return 0;
 	}
 
+#ifdef CONFIG_DM_CROS_EC
+	ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
+	if (ret) {
+		printf("Cannot get cros-ec device (err=%d)\n", ret);
+		return 1;
+	}
+	dev = udev->uclass_priv;
+#else
 	/* Just use the last allocated device; there should be only one */
 	if (!last_dev) {
 		printf("No CROS-EC device available\n");
 		return 1;
 	}
+	dev = last_dev;
+#endif
 	if (0 == strcmp("id", cmd)) {
 		char id[MSG_BYTES];
 
@@ -1794,3 +1884,11 @@ U_BOOT_CMD(
 	"crosec i2c mw chip address[.0, .1, .2] value [count] - write to I2C passthru (fill)"
 );
 #endif
+
+#ifdef CONFIG_DM_CROS_EC
+UCLASS_DRIVER(cros_ec) = {
+	.id		= UCLASS_CROS_EC,
+	.name		= "cros_ec",
+	.per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
+};
+#endif
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index 8a04af5..431cf26 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -525,8 +525,13 @@ int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob)
 	int node;
 	int err;
 
-	state = &s_state;
-	err = cros_ec_decode_ec_flash(blob, &ec->ec_config);
+	node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC);
+	if (node < 0) {
+		debug("Failed to find chrome-ec node'\n");
+		return -1;
+	}
+
+	err = cros_ec_decode_ec_flash(blob, node, &ec->ec_config);
 	if (err)
 		return err;
 
diff --git a/include/cros_ec.h b/include/cros_ec.h
index 1e4d8db..9e13146 100644
--- a/include/cros_ec.h
+++ b/include/cros_ec.h
@@ -14,6 +14,7 @@
 #include <fdtdec.h>
 #include <cros_ec_message.h>
 
+#ifndef CONFIG_DM_CROS_EC
 /* Which interface is the device on? */
 enum cros_ec_interface_t {
 	CROS_EC_IF_NONE,
@@ -22,9 +23,13 @@ enum cros_ec_interface_t {
 	CROS_EC_IF_LPC,	/* Intel Low Pin Count interface */
 	CROS_EC_IF_SANDBOX,
 };
+#endif
 
 /* Our configuration information */
 struct cros_ec_dev {
+#ifdef CONFIG_DM_CROS_EC
+	struct udevice *dev;		/* Transport device */
+#else
 	enum cros_ec_interface_t interface;
 	struct spi_slave *spi;		/* Our SPI slave, if using SPI */
 	int node;                       /* Our node */
@@ -33,6 +38,7 @@ struct cros_ec_dev {
 	unsigned int addr;		/* Device address (for I2C) */
 	unsigned int bus_num;		/* Bus number (for I2C) */
 	unsigned int max_frequency;	/* Maximum interface frequency */
+#endif
 	struct fdt_gpio_state ec_int;	/* GPIO used as EC interrupt line */
 	int protocol_version;           /* Protocol version to use */
 	int optimise_flash_write;	/* Don't write erased flash blocks */
@@ -233,6 +239,22 @@ int cros_ec_flash_update_rw(struct cros_ec_dev *dev,
  */
 struct cros_ec_dev *board_get_cros_ec_dev(void);
 
+#ifdef CONFIG_DM_CROS_EC
+
+struct dm_cros_ec_ops {
+	int (*check_version)(struct udevice *dev);
+	int (*command)(struct udevice *dev, uint8_t cmd, int cmd_version,
+		       const uint8_t *dout, int dout_len,
+		       uint8_t **dinp, int din_len);
+	int (*packet)(struct udevice *dev, int out_bytes, int in_bytes);
+};
+
+#define dm_cros_ec_get_ops(dev) \
+		((struct dm_cros_ec_ops *)(dev)->driver->ops)
+
+int cros_ec_register(struct udevice *dev);
+
+#else /* !CONFIG_DM_CROS_EC */
 
 /* Internal interfaces */
 int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob);
@@ -336,6 +358,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes);
 int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes,
 			   int in_bytes);
+#endif
 
 /**
  * Dump a block of data for a command.
@@ -489,9 +512,11 @@ int cros_ec_get_error(void);
  * Returns information from the FDT about the Chrome EC flash
  *
  * @param blob		FDT blob to use
+ * @param node		Node offset to read from
  * @param config	Structure to use to return information
  */
-int cros_ec_decode_ec_flash(const void *blob, struct fdt_cros_ec *config);
+int cros_ec_decode_ec_flash(const void *blob, int node,
+			    struct fdt_cros_ec *config);
 
 /**
  * Check the current keyboard state, in case recovery mode is requested.
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index c92adb4..9800777 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -26,6 +26,7 @@ enum uclass_id {
 	UCLASS_SPI,		/* SPI bus */
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
 	UCLASS_SPI_FLASH,	/* SPI flash */
+	UCLASS_CROS_EC,		/* Chrome OS EC */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 28/29] dm: sandbox: cros_ec: Move sandbox cros_ec to driver module
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (26 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 27/29] dm: cros_ec: Add support for " Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 29/29] dm: exynos: cros_ec: Move cros_ec_spi to driver model Simon Glass
                   ` (2 subsequent siblings)
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Adjust the sandbox cros_ec emulation driver to work with driver model, and
switch over to driver model for sandbox cros_ec.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 drivers/misc/cros_ec_sandbox.c | 90 +++++++++++++++++++++++++++++++++++++++---
 include/configs/sandbox.h      |  1 +
 2 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index 431cf26..99cc529 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -8,6 +8,7 @@
 
 #include <common.h>
 #include <cros_ec.h>
+#include <dm.h>
 #include <ec_commands.h>
 #include <errno.h>
 #include <hash.h>
@@ -85,7 +86,7 @@ struct ec_state {
 	struct ec_keymatrix_entry *matrix;	/* the key matrix info */
 	uint8_t keyscan[KEYBOARD_COLS];
 	bool recovery_req;
-} s_state, *state;
+} s_state, *g_state;
 
 /**
  * cros_ec_read_state() - read the sandbox EC state from the state file
@@ -138,7 +139,7 @@ static int cros_ec_read_state(const void *blob, int node)
  */
 static int cros_ec_write_state(void *blob, int node)
 {
-	struct ec_state *ec = &s_state;
+	struct ec_state *ec = g_state;
 
 	/* We are guaranteed enough space to write basic properties */
 	fdt_setprop_u32(blob, node, "current-image", ec->current_image);
@@ -369,7 +370,7 @@ static int process_cmd(struct ec_state *ec,
 		struct fmap_entry *entry;
 		int ret, size;
 
-		entry = &state->ec_config.region[EC_FLASH_REGION_RW];
+		entry = &ec->ec_config.region[EC_FLASH_REGION_RW];
 
 		switch (req->cmd) {
 		case EC_VBOOT_HASH_RECALC:
@@ -426,7 +427,7 @@ static int process_cmd(struct ec_state *ec,
 		case EC_FLASH_REGION_RO:
 		case EC_FLASH_REGION_RW:
 		case EC_FLASH_REGION_WP_RO:
-			entry = &state->ec_config.region[req->region];
+			entry = &ec->ec_config.region[req->region];
 			resp->offset = entry->offset;
 			resp->size = entry->length;
 			len = sizeof(*resp);
@@ -466,16 +467,24 @@ static int process_cmd(struct ec_state *ec,
 	return len;
 }
 
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_sandbox_packet(struct udevice *udev, int out_bytes, int in_bytes)
+{
+	struct cros_ec_dev *dev = udev->uclass_priv;
+	struct ec_state *ec = dev_get_priv(dev->dev);
+#else
 int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes,
 			   int in_bytes)
 {
+	struct ec_state *ec = &s_state;
+#endif
 	struct ec_host_request *req_hdr = (struct ec_host_request *)dev->dout;
 	const void *req_data = req_hdr + 1;
 	struct ec_host_response *resp_hdr = (struct ec_host_response *)dev->din;
 	void *resp_data = resp_hdr + 1;
 	int len;
 
-	len = process_cmd(&s_state, req_hdr, req_data, resp_hdr, resp_data);
+	len = process_cmd(ec, req_hdr, req_data, resp_hdr, resp_data);
 	if (len < 0)
 		return len;
 
@@ -498,7 +507,11 @@ int cros_ec_sandbox_decode_fdt(struct cros_ec_dev *dev, const void *blob)
 
 void cros_ec_check_keyboard(struct cros_ec_dev *dev)
 {
+#ifdef CONFIG_DM_CROS_EC
+	struct ec_state *ec = dev_get_priv(dev->dev);
+#else
 	struct ec_state *ec = &s_state;
+#endif
 	ulong start;
 
 	printf("Press keys for EC to detect on reset (ESC=recovery)...");
@@ -512,6 +525,52 @@ void cros_ec_check_keyboard(struct cros_ec_dev *dev)
 	}
 }
 
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_probe(struct udevice *dev)
+{
+	struct ec_state *ec = dev->priv;
+	struct cros_ec_dev *cdev = dev->uclass_priv;
+	const void *blob = gd->fdt_blob;
+	int node;
+	int err;
+
+	memcpy(ec, &s_state, sizeof(*ec));
+	err = cros_ec_decode_ec_flash(blob, dev->of_offset, &ec->ec_config);
+	if (err)
+		return err;
+
+	node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB);
+	if (node < 0) {
+		debug("%s: No cros_ec keyboard found\n", __func__);
+	} else if (keyscan_read_fdt_matrix(ec, blob, node)) {
+		debug("%s: Could not read key matrix\n", __func__);
+		return -1;
+	}
+
+	/* If we loaded EC data, check that the length matches */
+	if (ec->flash_data &&
+	    ec->flash_data_len != ec->ec_config.flash.length) {
+		printf("EC data length is %x, expected %x, discarding data\n",
+		       ec->flash_data_len, ec->ec_config.flash.length);
+		os_free(ec->flash_data);
+		ec->flash_data = NULL;
+	}
+
+	/* Otherwise allocate the memory */
+	if (!ec->flash_data) {
+		ec->flash_data_len = ec->ec_config.flash.length;
+		ec->flash_data = os_malloc(ec->flash_data_len);
+		if (!ec->flash_data)
+			return -ENOMEM;
+	}
+
+	cdev->dev = dev;
+	g_state = ec;
+	return cros_ec_register(dev);
+}
+
+#else
+
 /**
  * Initialize sandbox EC emulation.
  *
@@ -562,3 +621,24 @@ int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob)
 
 	return 0;
 }
+#endif
+
+#ifdef CONFIG_DM_CROS_EC
+struct dm_cros_ec_ops cros_ec_ops = {
+	.packet = cros_ec_sandbox_packet,
+};
+
+static const struct udevice_id cros_ec_ids[] = {
+	{ .compatible = "google,cros-ec" },
+	{ }
+};
+
+U_BOOT_DRIVER(cros_ec_sandbox) = {
+	.name		= "cros_ec",
+	.id		= UCLASS_CROS_EC,
+	.of_match	= cros_ec_ids,
+	.probe		= cros_ec_probe,
+	.priv_auto_alloc_size = sizeof(struct ec_state),
+	.ops		= &cros_ec_ops,
+};
+#endif
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 9adc5cc..2fd2c64 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -32,6 +32,7 @@
 #define CONFIG_DM_GPIO
 #define CONFIG_DM_TEST
 #define CONFIG_DM_SERIAL
+#define CONFIG_DM_CROS_EC
 
 #define CONFIG_SYS_STDIO_DEREGISTER
 
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 29/29] dm: exynos: cros_ec: Move cros_ec_spi to driver model
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (27 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 28/29] dm: sandbox: cros_ec: Move sandbox cros_ec to driver module Simon Glass
@ 2014-09-29 19:35 ` Simon Glass
  2014-10-08 20:33 ` [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
  2014-10-11 18:46 ` Jagan Teki
  30 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-09-29 19:35 UTC (permalink / raw)
  To: u-boot

Adjust this driver to use driver model and move smdk5420 boards over to
use it.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

Changes in v3: None
Changes in v2: None

 drivers/misc/cros_ec_spi.c  | 68 +++++++++++++++++++++++++++++++++++++++------
 include/configs/peach-pit.h |  1 +
 2 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index 015333f..89616ce 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -15,23 +15,34 @@
 
 #include <common.h>
 #include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
 #include <spi.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
+{
+	struct cros_ec_dev *dev = udev->uclass_priv;
+#else
 int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
 {
+#endif
+	struct spi_slave *slave = dev_get_parentdata(dev->dev);
 	int rv;
 
 	/* Do the transfer */
-	if (spi_claim_bus(dev->spi)) {
+	if (spi_claim_bus(slave)) {
 		debug("%s: Cannot claim SPI bus\n", __func__);
 		return -1;
 	}
 
-	rv = spi_xfer(dev->spi, max(out_bytes, in_bytes) * 8,
+	rv = spi_xfer(slave, max(out_bytes, in_bytes) * 8,
 		      dev->dout, dev->din,
 		      SPI_XFER_BEGIN | SPI_XFER_END);
 
-	spi_release_bus(dev->spi);
+	spi_release_bus(slave);
 
 	if (rv) {
 		debug("%s: Cannot complete SPI transfer\n", __func__);
@@ -56,10 +67,19 @@ int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
  * @param din_len	Maximum size of response in bytes
  * @return number of bytes in response, or -1 on error
  */
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_spi_command(struct udevice *udev, uint8_t cmd, int cmd_version,
+		     const uint8_t *dout, int dout_len,
+		     uint8_t **dinp, int din_len)
+{
+	struct cros_ec_dev *dev = udev->uclass_priv;
+#else
 int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 		     const uint8_t *dout, int dout_len,
 		     uint8_t **dinp, int din_len)
 {
+#endif
+	struct spi_slave *slave = dev_get_parentdata(dev->dev);
 	int in_bytes = din_len + 4;	/* status, length, checksum, trailer */
 	uint8_t *out;
 	uint8_t *p;
@@ -92,7 +112,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 	 */
 	memset(dev->din, '\0', in_bytes);
 
-	if (spi_claim_bus(dev->spi)) {
+	if (spi_claim_bus(slave)) {
 		debug("%s: Cannot claim SPI bus\n", __func__);
 		return -1;
 	}
@@ -113,10 +133,10 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 	p = dev->din + sizeof(int64_t) - 2;
 	len = dout_len + 4;
 	cros_ec_dump_data("out", cmd, out, len);
-	rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p,
+	rv = spi_xfer(slave, max(len, in_bytes) * 8, out, p,
 		      SPI_XFER_BEGIN | SPI_XFER_END);
 
-	spi_release_bus(dev->spi);
+	spi_release_bus(slave);
 
 	if (rv) {
 		debug("%s: Cannot complete SPI transfer\n", __func__);
@@ -146,6 +166,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 	return len;
 }
 
+#ifndef CONFIG_DM_CROS_EC
 int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
 {
 	/* Decode interface-specific FDT params */
@@ -165,11 +186,40 @@ int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
  */
 int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
 {
-	dev->spi = spi_setup_slave_fdt(blob, dev->node, dev->parent_node);
-	if (!dev->spi) {
+	int ret;
+
+	ret = spi_setup_slave_fdt(blob, dev->node, dev->parent_node,
+				  &slave);
+	if (ret) {
 		debug("%s: Could not setup SPI slave\n", __func__);
-		return -1;
+		return ret;
 	}
 
 	return 0;
 }
+#endif
+
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_probe(struct udevice *dev)
+{
+	return cros_ec_register(dev);
+}
+
+struct dm_cros_ec_ops cros_ec_ops = {
+	.packet = cros_ec_spi_packet,
+	.command = cros_ec_spi_command,
+};
+
+static const struct udevice_id cros_ec_ids[] = {
+	{ .compatible = "google,cros-ec" },
+	{ }
+};
+
+U_BOOT_DRIVER(cros_ec_spi) = {
+	.name		= "cros_ec",
+	.id		= UCLASS_CROS_EC,
+	.of_match	= cros_ec_ids,
+	.probe		= cros_ec_probe,
+	.ops		= &cros_ec_ops,
+};
+#endif
diff --git a/include/configs/peach-pit.h b/include/configs/peach-pit.h
index ab8ac60..91bd37d 100644
--- a/include/configs/peach-pit.h
+++ b/include/configs/peach-pit.h
@@ -38,6 +38,7 @@
 
 #define CONFIG_POWER_TPS65090_EC
 #define CONFIG_CROS_EC_SPI		/* Support CROS_EC over SPI */
+#define CONFIG_DM_CROS_EC
 
 #define CONFIG_USB_XHCI
 #define CONFIG_USB_XHCI_EXYNOS
-- 
2.1.0.rc2.206.gedb03e5

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 26/29] dm: tegra: spi: Convert to driver model
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 26/29] dm: tegra: spi: Convert to driver model Simon Glass
@ 2014-09-29 22:59   ` Igor Grinberg
  2014-10-01  2:23     ` Simon Glass
  0 siblings, 1 reply; 49+ messages in thread
From: Igor Grinberg @ 2014-09-29 22:59 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On 09/29/14 22:35, Simon Glass wrote:

> diff --git a/board/compulab/common/eeprom.c b/board/compulab/common/eeprom.c
> index 85442cd..ba3a5bf 100644
> --- a/board/compulab/common/eeprom.c
> +++ b/board/compulab/common/eeprom.c
> @@ -33,7 +33,7 @@ static int cl_eeprom_read(uint offset, uchar *buf, int len)
>  {
>  	int res;
>  	unsigned int current_i2c_bus = i2c_get_bus_num();
> -
> +#define CONFIG_SYS_I2C_EEPROM_BUS 1
>  	res = i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS);
>  	if (res < 0)
>  		return res;

The above hunk is not related to this patch. Please, remove.
A temporary fix for trimslice if needed can be found here [1].

Albert, patchwork says it is delegated to you.
Are you going to apply it some time soon?

[1] https://patchwork.ozlabs.org/patch/390381/

-- 
Regards,
Igor.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 26/29] dm: tegra: spi: Convert to driver model
  2014-09-29 22:59   ` Igor Grinberg
@ 2014-10-01  2:23     ` Simon Glass
  0 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-10-01  2:23 UTC (permalink / raw)
  To: u-boot

Hi Igor,

On 29 September 2014 16:59, Igor Grinberg <grinberg@compulab.co.il> wrote:
> Hi Simon,
>
> On 09/29/14 22:35, Simon Glass wrote:
>
>> diff --git a/board/compulab/common/eeprom.c b/board/compulab/common/eeprom.c
>> index 85442cd..ba3a5bf 100644
>> --- a/board/compulab/common/eeprom.c
>> +++ b/board/compulab/common/eeprom.c
>> @@ -33,7 +33,7 @@ static int cl_eeprom_read(uint offset, uchar *buf, int len)
>>  {
>>       int res;
>>       unsigned int current_i2c_bus = i2c_get_bus_num();
>> -
>> +#define CONFIG_SYS_I2C_EEPROM_BUS 1
>>       res = i2c_set_bus_num(CONFIG_SYS_I2C_EEPROM_BUS);
>>       if (res < 0)
>>               return res;
>
> The above hunk is not related to this patch. Please, remove.
> A temporary fix for trimslice if needed can be found here [1].

Thanks - yes this is a bit of a mess but I'll wait to sort it out
until the fix is in mainline. It's never easy adding patches to a
broken tree - I tried to bring it something and ended up merging it
into one of the patches by the look of it.

>
> Albert, patchwork says it is delegated to you.
> Are you going to apply it some time soon?
>
> [1] https://patchwork.ozlabs.org/patch/390381/
>
> --
> Regards,
> Igor.

Regards,
Simon

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (28 preceding siblings ...)
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 29/29] dm: exynos: cros_ec: Move cros_ec_spi to driver model Simon Glass
@ 2014-10-08 20:33 ` Simon Glass
  2014-10-09 10:33   ` Jagan Teki
  2014-10-11 18:46 ` Jagan Teki
  30 siblings, 1 reply; 49+ messages in thread
From: Simon Glass @ 2014-10-08 20:33 UTC (permalink / raw)
  To: u-boot

Hi,

On 29 September 2014 13:34, Simon Glass <sjg@chromium.org> wrote:
> Up until now driver model has not been used for any type of bus. Buses
> have some unique properties and needs, so we cannot claim that driver
> model can cover all the common cases unless we have converted a bus over
> to driver model.
>
> SPI is a reasonable choice for this next step. It has a fairly simple
> API and not too many dependencies. The main one is SPI flash so we may
> as well convert that also. Since the boards I test with have cros_ec I
> have also included that, for SPI only.
>
> The technique used is make use of driver model's supported data structures
> to hold information currently kept by each subsystem in a private data
> structure. Since 'struct spi_slave' relates to the slave device on the bus
> it is stored in the 'parent' data with each child device of the bus.
> Since 'struct spi_flash' is a standard interface used for each SPI flash
> driver, it is stored in the SPI FLash uclass's private data for each
> device.
>
> New defines are created to enable driver model for each subsystem. These
> are:
>
>    CONFIG_DM_SPI
>    CONFIG_DM_SPI_FLASH
>    CONFIG_DM_CROS_EC
>
> This allows us to move some boards and drivers to driver model, while
> leaving others behind. A 'big bang' conversion of everything to driver
> model, even at a subsystem level, is never going to work.
>
> There is some cost in changing the uclass interface after it is created,
> so if you have limited time, please spend it reviewing the uclass
> interfaces in spi.h and spi_flash.h. These need to be supported by each
> driver, so changing them later may involve changing multiple drivers.
>
> To assist with the conversion of other SPI drivers, a README file is
> added to walk through the process.
>
> So far, sandbox, exynos and tegra drivers are converted over.
>
> As always, driver model patches are available at u-boot-dm.git branch
> 'working'. There is a branch for just this series called 'spi-working'.

I think this has had enough time out there. So I will push this to
dm/next later this week.

Regards,
Simon

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-10-08 20:33 ` [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
@ 2014-10-09 10:33   ` Jagan Teki
  2014-10-10  2:06     ` Simon Glass
  0 siblings, 1 reply; 49+ messages in thread
From: Jagan Teki @ 2014-10-09 10:33 UTC (permalink / raw)
  To: u-boot

On 9 October 2014 02:03, Simon Glass <sjg@chromium.org> wrote:
> Hi,
>
> On 29 September 2014 13:34, Simon Glass <sjg@chromium.org> wrote:
>> Up until now driver model has not been used for any type of bus. Buses
>> have some unique properties and needs, so we cannot claim that driver
>> model can cover all the common cases unless we have converted a bus over
>> to driver model.
>>
>> SPI is a reasonable choice for this next step. It has a fairly simple
>> API and not too many dependencies. The main one is SPI flash so we may
>> as well convert that also. Since the boards I test with have cros_ec I
>> have also included that, for SPI only.
>>
>> The technique used is make use of driver model's supported data structures
>> to hold information currently kept by each subsystem in a private data
>> structure. Since 'struct spi_slave' relates to the slave device on the bus
>> it is stored in the 'parent' data with each child device of the bus.
>> Since 'struct spi_flash' is a standard interface used for each SPI flash
>> driver, it is stored in the SPI FLash uclass's private data for each
>> device.
>>
>> New defines are created to enable driver model for each subsystem. These
>> are:
>>
>>    CONFIG_DM_SPI
>>    CONFIG_DM_SPI_FLASH
>>    CONFIG_DM_CROS_EC
>>
>> This allows us to move some boards and drivers to driver model, while
>> leaving others behind. A 'big bang' conversion of everything to driver
>> model, even at a subsystem level, is never going to work.
>>
>> There is some cost in changing the uclass interface after it is created,
>> so if you have limited time, please spend it reviewing the uclass
>> interfaces in spi.h and spi_flash.h. These need to be supported by each
>> driver, so changing them later may involve changing multiple drivers.
>>
>> To assist with the conversion of other SPI drivers, a README file is
>> added to walk through the process.
>>
>> So far, sandbox, exynos and tegra drivers are converted over.
>>
>> As always, driver model patches are available at u-boot-dm.git branch
>> 'working'. There is a branch for just this series called 'spi-working'.
>
> I think this has had enough time out there. So I will push this to
> dm/next later this week.

Sorry - I need to review a lot wrt v3.
I do understand that it has been in enough time, but this causes a
significant changes on
entire framework, please hold on for a while I need to think with
respect on qspi stuff with in
the spi framework.

thanks!
-- 
Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-10-09 10:33   ` Jagan Teki
@ 2014-10-10  2:06     ` Simon Glass
  2014-10-10 13:30       ` Jagan Teki
  0 siblings, 1 reply; 49+ messages in thread
From: Simon Glass @ 2014-10-10  2:06 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 9 October 2014 04:33, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> On 9 October 2014 02:03, Simon Glass <sjg@chromium.org> wrote:
>> Hi,
>>
>> On 29 September 2014 13:34, Simon Glass <sjg@chromium.org> wrote:
>>> Up until now driver model has not been used for any type of bus. Buses
>>> have some unique properties and needs, so we cannot claim that driver
>>> model can cover all the common cases unless we have converted a bus over
>>> to driver model.
>>>
>>> SPI is a reasonable choice for this next step. It has a fairly simple
>>> API and not too many dependencies. The main one is SPI flash so we may
>>> as well convert that also. Since the boards I test with have cros_ec I
>>> have also included that, for SPI only.
>>>
>>> The technique used is make use of driver model's supported data structures
>>> to hold information currently kept by each subsystem in a private data
>>> structure. Since 'struct spi_slave' relates to the slave device on the bus
>>> it is stored in the 'parent' data with each child device of the bus.
>>> Since 'struct spi_flash' is a standard interface used for each SPI flash
>>> driver, it is stored in the SPI FLash uclass's private data for each
>>> device.
>>>
>>> New defines are created to enable driver model for each subsystem. These
>>> are:
>>>
>>>    CONFIG_DM_SPI
>>>    CONFIG_DM_SPI_FLASH
>>>    CONFIG_DM_CROS_EC
>>>
>>> This allows us to move some boards and drivers to driver model, while
>>> leaving others behind. A 'big bang' conversion of everything to driver
>>> model, even at a subsystem level, is never going to work.
>>>
>>> There is some cost in changing the uclass interface after it is created,
>>> so if you have limited time, please spend it reviewing the uclass
>>> interfaces in spi.h and spi_flash.h. These need to be supported by each
>>> driver, so changing them later may involve changing multiple drivers.
>>>
>>> To assist with the conversion of other SPI drivers, a README file is
>>> added to walk through the process.
>>>
>>> So far, sandbox, exynos and tegra drivers are converted over.
>>>
>>> As always, driver model patches are available at u-boot-dm.git branch
>>> 'working'. There is a branch for just this series called 'spi-working'.
>>
>> I think this has had enough time out there. So I will push this to
>> dm/next later this week.
>
> Sorry - I need to review a lot wrt v3.
> I do understand that it has been in enough time, but this causes a
> significant changes on
> entire framework, please hold on for a while I need to think with
> respect on qspi stuff with in
> the spi framework.

Well I'm not sure it supports setting of the flags that are needed for
that. I don't have a platform to test with anyway.

On the other hand adding that support to driver model could easily be
a separate effort. I don't see a good reason to hold up the core SPI /
SPI flash support.

Regards,
Simon

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-10-10  2:06     ` Simon Glass
@ 2014-10-10 13:30       ` Jagan Teki
  2014-10-10 13:35         ` Simon Glass
  0 siblings, 1 reply; 49+ messages in thread
From: Jagan Teki @ 2014-10-10 13:30 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On 10 October 2014 07:36, Simon Glass <sjg@chromium.org> wrote:
> Hi Jagan,
>
> On 9 October 2014 04:33, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>> On 9 October 2014 02:03, Simon Glass <sjg@chromium.org> wrote:
>>> Hi,
>>>
>>> On 29 September 2014 13:34, Simon Glass <sjg@chromium.org> wrote:
>>>> Up until now driver model has not been used for any type of bus. Buses
>>>> have some unique properties and needs, so we cannot claim that driver
>>>> model can cover all the common cases unless we have converted a bus over
>>>> to driver model.
>>>>
>>>> SPI is a reasonable choice for this next step. It has a fairly simple
>>>> API and not too many dependencies. The main one is SPI flash so we may
>>>> as well convert that also. Since the boards I test with have cros_ec I
>>>> have also included that, for SPI only.
>>>>
>>>> The technique used is make use of driver model's supported data structures
>>>> to hold information currently kept by each subsystem in a private data
>>>> structure. Since 'struct spi_slave' relates to the slave device on the bus
>>>> it is stored in the 'parent' data with each child device of the bus.
>>>> Since 'struct spi_flash' is a standard interface used for each SPI flash
>>>> driver, it is stored in the SPI FLash uclass's private data for each
>>>> device.
>>>>
>>>> New defines are created to enable driver model for each subsystem. These
>>>> are:
>>>>
>>>>    CONFIG_DM_SPI
>>>>    CONFIG_DM_SPI_FLASH
>>>>    CONFIG_DM_CROS_EC
>>>>
>>>> This allows us to move some boards and drivers to driver model, while
>>>> leaving others behind. A 'big bang' conversion of everything to driver
>>>> model, even at a subsystem level, is never going to work.
>>>>
>>>> There is some cost in changing the uclass interface after it is created,
>>>> so if you have limited time, please spend it reviewing the uclass
>>>> interfaces in spi.h and spi_flash.h. These need to be supported by each
>>>> driver, so changing them later may involve changing multiple drivers.
>>>>
>>>> To assist with the conversion of other SPI drivers, a README file is
>>>> added to walk through the process.
>>>>
>>>> So far, sandbox, exynos and tegra drivers are converted over.
>>>>
>>>> As always, driver model patches are available at u-boot-dm.git branch
>>>> 'working'. There is a branch for just this series called 'spi-working'.
>>>
>>> I think this has had enough time out there. So I will push this to
>>> dm/next later this week.
>>
>> Sorry - I need to review a lot wrt v3.
>> I do understand that it has been in enough time, but this causes a
>> significant changes on
>> entire framework, please hold on for a while I need to think with
>> respect on qspi stuff with in
>> the spi framework.
>
> Well I'm not sure it supports setting of the flags that are needed for
> that. I don't have a platform to test with anyway.
>
> On the other hand adding that support to driver model could easily be
> a separate effort. I don't see a good reason to hold up the core SPI /
> SPI flash support.

Partially agreed at this moment, let me think and review the whole stuff.
I would place all these stuff on to my master-next, once I'm OK.

Any changes based on my strategy wrt qspi stuff - I may change these.
But I will push all these later on the 13/10 release.

Comments?

thanks!
-- 
Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-10-10 13:30       ` Jagan Teki
@ 2014-10-10 13:35         ` Simon Glass
  2014-10-10 13:51           ` Jagan Teki
  0 siblings, 1 reply; 49+ messages in thread
From: Simon Glass @ 2014-10-10 13:35 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 10 October 2014 07:30, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> Hi Simon,
>
> On 10 October 2014 07:36, Simon Glass <sjg@chromium.org> wrote:
>> Hi Jagan,
>>
>> On 9 October 2014 04:33, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>> On 9 October 2014 02:03, Simon Glass <sjg@chromium.org> wrote:
>>>> Hi,
>>>>
>>>> On 29 September 2014 13:34, Simon Glass <sjg@chromium.org> wrote:
>>>>> Up until now driver model has not been used for any type of bus. Buses
>>>>> have some unique properties and needs, so we cannot claim that driver
>>>>> model can cover all the common cases unless we have converted a bus over
>>>>> to driver model.
>>>>>
>>>>> SPI is a reasonable choice for this next step. It has a fairly simple
>>>>> API and not too many dependencies. The main one is SPI flash so we may
>>>>> as well convert that also. Since the boards I test with have cros_ec I
>>>>> have also included that, for SPI only.
>>>>>
>>>>> The technique used is make use of driver model's supported data structures
>>>>> to hold information currently kept by each subsystem in a private data
>>>>> structure. Since 'struct spi_slave' relates to the slave device on the bus
>>>>> it is stored in the 'parent' data with each child device of the bus.
>>>>> Since 'struct spi_flash' is a standard interface used for each SPI flash
>>>>> driver, it is stored in the SPI FLash uclass's private data for each
>>>>> device.
>>>>>
>>>>> New defines are created to enable driver model for each subsystem. These
>>>>> are:
>>>>>
>>>>>    CONFIG_DM_SPI
>>>>>    CONFIG_DM_SPI_FLASH
>>>>>    CONFIG_DM_CROS_EC
>>>>>
>>>>> This allows us to move some boards and drivers to driver model, while
>>>>> leaving others behind. A 'big bang' conversion of everything to driver
>>>>> model, even at a subsystem level, is never going to work.
>>>>>
>>>>> There is some cost in changing the uclass interface after it is created,
>>>>> so if you have limited time, please spend it reviewing the uclass
>>>>> interfaces in spi.h and spi_flash.h. These need to be supported by each
>>>>> driver, so changing them later may involve changing multiple drivers.
>>>>>
>>>>> To assist with the conversion of other SPI drivers, a README file is
>>>>> added to walk through the process.
>>>>>
>>>>> So far, sandbox, exynos and tegra drivers are converted over.
>>>>>
>>>>> As always, driver model patches are available at u-boot-dm.git branch
>>>>> 'working'. There is a branch for just this series called 'spi-working'.
>>>>
>>>> I think this has had enough time out there. So I will push this to
>>>> dm/next later this week.
>>>
>>> Sorry - I need to review a lot wrt v3.
>>> I do understand that it has been in enough time, but this causes a
>>> significant changes on
>>> entire framework, please hold on for a while I need to think with
>>> respect on qspi stuff with in
>>> the spi framework.
>>
>> Well I'm not sure it supports setting of the flags that are needed for
>> that. I don't have a platform to test with anyway.
>>
>> On the other hand adding that support to driver model could easily be
>> a separate effort. I don't see a good reason to hold up the core SPI /
>> SPI flash support.
>
> Partially agreed at this moment, let me think and review the whole stuff.
> I would place all these stuff on to my master-next, once I'm OK.
>
> Any changes based on my strategy wrt qspi stuff - I may change these.
> But I will push all these later on the 13/10 release.
>
> Comments?

Actually I'd like to bring this through the dm tree as I have a lot of
dependent series that need to go that way. What is your timeline for
further review of v3? I'm planning to push this to dm/next soon.

I suggest adding the qspi stuff to sandbox. Then it will be easier to
test with driver model. What do you think?

Regards,
Simon

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-10-10 13:35         ` Simon Glass
@ 2014-10-10 13:51           ` Jagan Teki
  2014-10-10 13:56             ` Simon Glass
  0 siblings, 1 reply; 49+ messages in thread
From: Jagan Teki @ 2014-10-10 13:51 UTC (permalink / raw)
  To: u-boot

On 10 October 2014 19:05, Simon Glass <sjg@chromium.org> wrote:
> Hi Jagan,
>
> On 10 October 2014 07:30, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>> Hi Simon,
>>
>> On 10 October 2014 07:36, Simon Glass <sjg@chromium.org> wrote:
>>> Hi Jagan,
>>>
>>> On 9 October 2014 04:33, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>>> On 9 October 2014 02:03, Simon Glass <sjg@chromium.org> wrote:
>>>>> Hi,
>>>>>
>>>>> On 29 September 2014 13:34, Simon Glass <sjg@chromium.org> wrote:
>>>>>> Up until now driver model has not been used for any type of bus. Buses
>>>>>> have some unique properties and needs, so we cannot claim that driver
>>>>>> model can cover all the common cases unless we have converted a bus over
>>>>>> to driver model.
>>>>>>
>>>>>> SPI is a reasonable choice for this next step. It has a fairly simple
>>>>>> API and not too many dependencies. The main one is SPI flash so we may
>>>>>> as well convert that also. Since the boards I test with have cros_ec I
>>>>>> have also included that, for SPI only.
>>>>>>
>>>>>> The technique used is make use of driver model's supported data structures
>>>>>> to hold information currently kept by each subsystem in a private data
>>>>>> structure. Since 'struct spi_slave' relates to the slave device on the bus
>>>>>> it is stored in the 'parent' data with each child device of the bus.
>>>>>> Since 'struct spi_flash' is a standard interface used for each SPI flash
>>>>>> driver, it is stored in the SPI FLash uclass's private data for each
>>>>>> device.
>>>>>>
>>>>>> New defines are created to enable driver model for each subsystem. These
>>>>>> are:
>>>>>>
>>>>>>    CONFIG_DM_SPI
>>>>>>    CONFIG_DM_SPI_FLASH
>>>>>>    CONFIG_DM_CROS_EC
>>>>>>
>>>>>> This allows us to move some boards and drivers to driver model, while
>>>>>> leaving others behind. A 'big bang' conversion of everything to driver
>>>>>> model, even at a subsystem level, is never going to work.
>>>>>>
>>>>>> There is some cost in changing the uclass interface after it is created,
>>>>>> so if you have limited time, please spend it reviewing the uclass
>>>>>> interfaces in spi.h and spi_flash.h. These need to be supported by each
>>>>>> driver, so changing them later may involve changing multiple drivers.
>>>>>>
>>>>>> To assist with the conversion of other SPI drivers, a README file is
>>>>>> added to walk through the process.
>>>>>>
>>>>>> So far, sandbox, exynos and tegra drivers are converted over.
>>>>>>
>>>>>> As always, driver model patches are available at u-boot-dm.git branch
>>>>>> 'working'. There is a branch for just this series called 'spi-working'.
>>>>>
>>>>> I think this has had enough time out there. So I will push this to
>>>>> dm/next later this week.
>>>>
>>>> Sorry - I need to review a lot wrt v3.
>>>> I do understand that it has been in enough time, but this causes a
>>>> significant changes on
>>>> entire framework, please hold on for a while I need to think with
>>>> respect on qspi stuff with in
>>>> the spi framework.
>>>
>>> Well I'm not sure it supports setting of the flags that are needed for
>>> that. I don't have a platform to test with anyway.
>>>
>>> On the other hand adding that support to driver model could easily be
>>> a separate effort. I don't see a good reason to hold up the core SPI /
>>> SPI flash support.
>>
>> Partially agreed at this moment, let me think and review the whole stuff.
>> I would place all these stuff on to my master-next, once I'm OK.
>>
>> Any changes based on my strategy wrt qspi stuff - I may change these.
>> But I will push all these later on the 13/10 release.
>>
>> Comments?
>
> Actually I'd like to bring this through the dm tree as I have a lot of
> dependent series that need to go that way. What is your timeline for
> further review of v3? I'm planning to push this to dm/next soon.

OK, I will give my first level comments by tomorrow (IST)
May be this will prolong least by next week end, if something need to change.

>
> I suggest adding the qspi stuff to sandbox. Then it will be easier to
> test with driver model. What do you think?

Will comment again on this.

thanks!
-- 
Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-10-10 13:51           ` Jagan Teki
@ 2014-10-10 13:56             ` Simon Glass
  0 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-10-10 13:56 UTC (permalink / raw)
  To: u-boot

Hi,

On 10 October 2014 07:51, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> On 10 October 2014 19:05, Simon Glass <sjg@chromium.org> wrote:
>> Hi Jagan,
>>
>> On 10 October 2014 07:30, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>> Hi Simon,
>>>
>>> On 10 October 2014 07:36, Simon Glass <sjg@chromium.org> wrote:
>>>> Hi Jagan,
>>>>
>>>> On 9 October 2014 04:33, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>>>> On 9 October 2014 02:03, Simon Glass <sjg@chromium.org> wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On 29 September 2014 13:34, Simon Glass <sjg@chromium.org> wrote:
>>>>>>> Up until now driver model has not been used for any type of bus. Buses
>>>>>>> have some unique properties and needs, so we cannot claim that driver
>>>>>>> model can cover all the common cases unless we have converted a bus over
>>>>>>> to driver model.
>>>>>>>
>>>>>>> SPI is a reasonable choice for this next step. It has a fairly simple
>>>>>>> API and not too many dependencies. The main one is SPI flash so we may
>>>>>>> as well convert that also. Since the boards I test with have cros_ec I
>>>>>>> have also included that, for SPI only.
>>>>>>>
>>>>>>> The technique used is make use of driver model's supported data structures
>>>>>>> to hold information currently kept by each subsystem in a private data
>>>>>>> structure. Since 'struct spi_slave' relates to the slave device on the bus
>>>>>>> it is stored in the 'parent' data with each child device of the bus.
>>>>>>> Since 'struct spi_flash' is a standard interface used for each SPI flash
>>>>>>> driver, it is stored in the SPI FLash uclass's private data for each
>>>>>>> device.
>>>>>>>
>>>>>>> New defines are created to enable driver model for each subsystem. These
>>>>>>> are:
>>>>>>>
>>>>>>>    CONFIG_DM_SPI
>>>>>>>    CONFIG_DM_SPI_FLASH
>>>>>>>    CONFIG_DM_CROS_EC
>>>>>>>
>>>>>>> This allows us to move some boards and drivers to driver model, while
>>>>>>> leaving others behind. A 'big bang' conversion of everything to driver
>>>>>>> model, even at a subsystem level, is never going to work.
>>>>>>>
>>>>>>> There is some cost in changing the uclass interface after it is created,
>>>>>>> so if you have limited time, please spend it reviewing the uclass
>>>>>>> interfaces in spi.h and spi_flash.h. These need to be supported by each
>>>>>>> driver, so changing them later may involve changing multiple drivers.
>>>>>>>
>>>>>>> To assist with the conversion of other SPI drivers, a README file is
>>>>>>> added to walk through the process.
>>>>>>>
>>>>>>> So far, sandbox, exynos and tegra drivers are converted over.
>>>>>>>
>>>>>>> As always, driver model patches are available at u-boot-dm.git branch
>>>>>>> 'working'. There is a branch for just this series called 'spi-working'.
>>>>>>
>>>>>> I think this has had enough time out there. So I will push this to
>>>>>> dm/next later this week.
>>>>>
>>>>> Sorry - I need to review a lot wrt v3.
>>>>> I do understand that it has been in enough time, but this causes a
>>>>> significant changes on
>>>>> entire framework, please hold on for a while I need to think with
>>>>> respect on qspi stuff with in
>>>>> the spi framework.
>>>>
>>>> Well I'm not sure it supports setting of the flags that are needed for
>>>> that. I don't have a platform to test with anyway.
>>>>
>>>> On the other hand adding that support to driver model could easily be
>>>> a separate effort. I don't see a good reason to hold up the core SPI /
>>>> SPI flash support.
>>>
>>> Partially agreed at this moment, let me think and review the whole stuff.
>>> I would place all these stuff on to my master-next, once I'm OK.
>>>
>>> Any changes based on my strategy wrt qspi stuff - I may change these.
>>> But I will push all these later on the 13/10 release.
>>>
>>> Comments?
>>
>> Actually I'd like to bring this through the dm tree as I have a lot of
>> dependent series that need to go that way. What is your timeline for
>> further review of v3? I'm planning to push this to dm/next soon.
>
> OK, I will give my first level comments by tomorrow (IST)
> May be this will prolong least by next week end, if something need to change.
>

OK I'll take a look at your comments when I get them.

>>
>> I suggest adding the qspi stuff to sandbox. Then it will be easier to
>> test with driver model. What do you think?
>
> Will comment again on this.

OK.

Regards,
Simon

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-09-29 19:35 ` [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI Simon Glass
@ 2014-10-10 17:31   ` Jagan Teki
  2014-10-10 18:05     ` Simon Glass
  0 siblings, 1 reply; 49+ messages in thread
From: Jagan Teki @ 2014-10-10 17:31 UTC (permalink / raw)
  To: u-boot

Hi Simon,

Can you please see my comments below, I'm relating more about cs and bus
valid scenario which is available on current drivers wrt dm-spi.

On 30 September 2014 01:05, Simon Glass <sjg@chromium.org> wrote:
> Add a uclass which provides access to SPI buses and includes operations
> required by SPI.
>
> For a time driver model will need to co-exist with the legacy SPI interface
> so some parts of the header file are changed depending on which is in use.
> The exports are adjusted also since some functions are not available with
> driver model.
>
> Boards must define CONFIG_DM_SPI to use driver model for SPI.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
> Changes in v3:
> - Add a cs_info() method to the driver model SPI API

I think this gives the enough info regarding cs on particular controller what
about the bus usage - which is also specific to controller it self, right?

Say - spi controller on a particular soc, have spi0, spi1 means two buses
and 4 cs lines, cs0-cs3. How is this works in that case?

And also I saw tegra20_sflash.c validates only cs

int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
                           struct spi_cs_info *info)

What about bus number check this particular tegra spi controller is concern.

> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
> - Add missing comments to spi.h
> - Correct typo where 'slave' should say 'bus'
> - Fix two comment typos
> - Put the cs member back into spi_slave
> - Use an explicit chip select value instead of reusing device sequence number
>
> Changes in v2:
> - Add missing comments for struct spi_slave
> - Fix code nits from Daniel Schwierzeck
> - Use 'bus' instead of 'dev' to make the API clearer
>
>  common/exports.c         |   4 +-
>  drivers/spi/Makefile     |   4 +
>  drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
>  include/dm/uclass-id.h   |   2 +
>  include/spi.h            | 254 +++++++++++++++++++++++++++++-
>  5 files changed, 650 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/spi/spi-uclass.c
>
> diff --git a/common/exports.c b/common/exports.c
> index b97ca48..88fcfc8 100644
> --- a/common/exports.c
> +++ b/common/exports.c
> @@ -27,10 +27,12 @@ unsigned long get_version(void)
>  # define i2c_write         dummy
>  # define i2c_read          dummy
>  #endif
> -#ifndef CONFIG_CMD_SPI
> +#if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI)
>  # define spi_init          dummy
>  # define spi_setup_slave   dummy
>  # define spi_free_slave    dummy
> +#endif
> +#ifndef CONFIG_CMD_SPI
>  # define spi_claim_bus     dummy
>  # define spi_release_bus   dummy
>  # define spi_xfer          dummy
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index f02c35a..d1f1dd0 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -6,7 +6,11 @@
>  #
>
>  # There are many options which enable SPI, so make this library available
> +ifdef CONFIG_DM_SPI
> +obj-y += spi-uclass.o
> +else
>  obj-y += spi.o
> +endif
>
>  obj-$(CONFIG_EP93XX_SPI) += ep93xx_spi.o
>  obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
> diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
> new file mode 100644
> index 0000000..13c6b77
> --- /dev/null
> +++ b/drivers/spi/spi-uclass.c
> @@ -0,0 +1,390 @@
> +/*
> + * Copyright (c) 2014 Google, Inc
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <fdtdec.h>
> +#include <malloc.h>
> +#include <spi.h>
> +#include <dm/device-internal.h>
> +#include <dm/uclass-internal.h>
> +#include <dm/root.h>
> +#include <dm/lists.h>
> +#include <dm/util.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +static int spi_set_speed_mode(struct udevice *bus, int speed, int mode)
> +{
> +       struct dm_spi_ops *ops;
> +       int ret;
> +
> +       ops = spi_get_ops(bus);
> +       if (ops->set_speed)
> +               ret = ops->set_speed(bus, speed);
> +       else
> +               ret = -EINVAL;
> +       if (ret) {
> +               printf("Cannot set speed (err=%d)\n", ret);
> +               return ret;
> +       }
> +
> +       if (ops->set_mode)
> +               ret = ops->set_mode(bus, mode);
> +       else
> +               ret = -EINVAL;
> +       if (ret) {
> +               printf("Cannot set mode (err=%d)\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +int spi_claim_bus(struct spi_slave *slave)
> +{
> +       struct udevice *dev = slave->dev;
> +       struct udevice *bus = dev->parent;
> +       struct dm_spi_ops *ops = spi_get_ops(bus);
> +       struct dm_spi_bus *spi = bus->uclass_priv;
> +       int speed;
> +       int ret;
> +
> +       speed = slave->max_hz;
> +       if (spi->max_hz) {
> +               if (speed)
> +                       speed = min(speed, spi->max_hz);
> +               else
> +                       speed = spi->max_hz;
> +       }
> +       if (!speed)
> +               speed = 100000;
> +       ret = spi_set_speed_mode(bus, speed, slave->mode);
> +       if (ret)
> +               return ret;
> +
> +       return ops->claim_bus ? ops->claim_bus(bus) : 0;
> +}
> +
> +void spi_release_bus(struct spi_slave *slave)
> +{
> +       struct udevice *dev = slave->dev;
> +       struct udevice *bus = dev->parent;
> +       struct dm_spi_ops *ops = spi_get_ops(bus);
> +
> +       if (ops->release_bus)
> +               ops->release_bus(bus);
> +}
> +
> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
> +            const void *dout, void *din, unsigned long flags)
> +{
> +       struct udevice *dev = slave->dev;
> +       struct udevice *bus = dev->parent;
> +
> +       if (bus->uclass->uc_drv->id != UCLASS_SPI)
> +               return -EOPNOTSUPP;
> +
> +       return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
> +}
> +
> +int spi_post_bind(struct udevice *dev)
> +{
> +       /* Scan the bus for devices */
> +       return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
> +}
> +
> +int spi_post_probe(struct udevice *dev)
> +{
> +       struct dm_spi_bus *spi = dev->uclass_priv;
> +
> +       spi->max_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
> +                                    "spi-max-frequency", 0);
> +
> +       return 0;
> +}
> +
> +int spi_chip_select(struct udevice *dev)
> +{
> +       struct spi_slave *slave = dev_get_parentdata(dev);
> +
> +       return slave ? slave->cs : -ENOENT;
> +}
> +
> +/**
> + * spi_find_chip_select() - Find the slave attached to chip select
> + *
> + * @bus:       SPI bus to search
> + * @cs:                Chip select to look for
> + * @devp:      Returns the slave device if found
> + * @return 0 if found, -ENODEV on error
> + */
> +static int spi_find_chip_select(struct udevice *bus, int cs,
> +                               struct udevice **devp)
> +{
> +       struct udevice *dev;
> +
> +       for (device_find_first_child(bus, &dev); dev;
> +            device_find_next_child(&dev)) {
> +               struct spi_slave store;
> +               struct spi_slave *slave = dev_get_parentdata(dev);
> +
> +               if (!slave)  {
> +                       slave = &store;
> +                       spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
> +                                              slave);
> +               }
> +               debug("%s: slave=%p, cs=%d\n", __func__, slave,
> +                     slave ? slave->cs : -1);
> +               if (slave && slave->cs == cs) {
> +                       *devp = dev;
> +                       return 0;
> +               }
> +       }
> +
> +       return -ENODEV;
> +}
> +
> +int spi_cs_is_valid(unsigned int busnum, unsigned int cs)

Who is the caller for this?

> +{
> +       struct spi_cs_info info;
> +       struct udevice *bus;
> +       int ret;
> +
> +       ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus);
> +       if (ret) {
> +               debug("%s: No bus %d\n", __func__, busnum);
> +               return ret;
> +       }
> +
> +       return spi_cs_info(bus, cs, &info);
> +}
> +
> +int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info)
> +{
> +       struct spi_cs_info local_info;
> +       struct dm_spi_ops *ops;
> +       int ret;
> +
> +       if (!info)
> +               info = &local_info;
> +
> +       /* If there is a device attached, return it */
> +       info->dev = NULL;
> +       ret = spi_find_chip_select(bus, cs, &info->dev);
> +       if (!ret)
> +               return 0;
> +
> +       /*
> +        * Otherwise ask the driver. For the moment we don't have CS info.
> +        * When we do we could provide the driver with a helper function
> +        * to figure out what chip selects are valid, or just handle the
> +        * request.
> +        */
> +       ops = spi_get_ops(bus);
> +       if (ops->cs_info)
> +               return ops->cs_info(bus, cs, info);
> +
> +       /*
> +        * We could assume there is at least one valid chip select, but best
> +        * to be sure and return an error in this case. The driver didn't
> +        * care enough to tell us.
> +        */
> +       return -ENODEV;
> +}
> +
> +int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
> +                   const char *dev_name, struct udevice **devp)
> +{
> +       struct driver *drv;
> +       int ret;
> +
> +       drv = lists_driver_lookup_name(drv_name);
> +       if (!drv) {
> +               printf("Cannot find driver '%s'\n", drv_name);
> +               return -ENOENT;
> +       }
> +       ret = device_bind(bus, drv, dev_name, NULL, -1, devp);
> +       if (ret) {
> +               printf("Cannot create device named '%s' (err=%d)\n",
> +                      dev_name, ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
> +                       struct udevice **devp)
> +{
> +       struct udevice *bus, *dev;
> +       int ret;
> +
> +       ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus);
> +       if (ret) {
> +               debug("%s: No bus %d\n", __func__, busnum);
> +               return ret;
> +       }
> +       ret = spi_find_chip_select(bus, cs, &dev);
> +       if (ret) {
> +               debug("%s: No cs %d\n", __func__, cs);
> +               return ret;
> +       }
> +       *busp = bus;
> +       *devp = dev;
> +
> +       return ret;
> +}
> +
> +int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
> +                      const char *drv_name, const char *dev_name,
> +                      struct udevice **busp, struct spi_slave **devp)
> +{
> +       struct udevice *bus, *dev;
> +       struct spi_slave *slave;
> +       bool created = false;
> +       int ret;
> +
> +       ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus);
> +       if (ret) {
> +               printf("Invalid bus %d (err=%d)\n", busnum, ret);
> +               return ret;
> +       }
> +       ret = spi_find_chip_select(bus, cs, &dev);
> +
> +       /*
> +        * If there is no such device, create one automatically. This means
> +        * that we don't need a device tree node or platform data for the
> +        * SPI flash chip - we will bind to the correct driver.
> +        */
> +       if (ret == -ENODEV && drv_name) {
> +               debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
> +                     __func__, dev_name, busnum, cs, drv_name);
> +               ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev);
> +               if (ret)
> +                       return ret;
> +               created = true;
> +       } else if (ret) {
> +               printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs,
> +                      ret);
> +               return ret;
> +       }
> +
> +       if (!device_active(dev)) {
> +               slave = (struct spi_slave *)calloc(1,
> +                                                  sizeof(struct spi_slave));
> +               if (!slave) {
> +                       ret = -ENOMEM;
> +                       goto err;
> +               }
> +
> +               ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
> +                                            slave);
> +               if (ret)
> +                       goto err;
> +               slave->cs = cs;
> +               slave->dev = dev;
> +               ret = device_probe_child(dev, slave);
> +               free(slave);
> +               if (ret)
> +                       goto err;
> +       }
> +
> +       ret = spi_set_speed_mode(bus, speed, mode);
> +       if (ret)
> +               goto err;
> +
> +       *busp = bus;
> +       *devp = dev_get_parentdata(dev);
> +       debug("%s: bus=%p, slave=%p\n", __func__, bus, *devp);
> +
> +       return 0;
> +
> +err:
> +       if (created) {
> +               device_remove(dev);
> +               device_unbind(dev);
> +       }
> +
> +       return ret;
> +}
> +
> +/* Compatibility function - to be removed */
> +struct spi_slave *spi_setup_slave_fdt(const void *blob, int node,
> +                                     int bus_node)
> +{
> +       struct udevice *bus, *dev;
> +       int ret;
> +
> +       ret = uclass_get_device_by_of_offset(UCLASS_SPI, bus_node, &bus);
> +       if (ret)
> +               return NULL;
> +       ret = device_get_child_by_of_offset(bus, node, &dev);
> +       if (ret)
> +               return NULL;
> +       return dev_get_parentdata(dev);
> +}
> +
> +/* Compatibility function - to be removed */
> +struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
> +                                 unsigned int speed, unsigned int mode)
> +{
> +       struct spi_slave *slave;
> +       struct udevice *dev;
> +       int ret;
> +
> +       ret = spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, 0, &dev,
> +                                 &slave);
> +       if (ret)
> +               return NULL;
> +
> +       return slave;
> +}
> +
> +void spi_free_slave(struct spi_slave *slave)
> +{
> +       device_remove(slave->dev);
> +       slave->dev = NULL;
> +}
> +
> +int spi_ofdata_to_platdata(const void *blob, int node,
> +                          struct spi_slave *spi)
> +{
> +       int mode = 0;
> +
> +       spi->cs = fdtdec_get_int(blob, node, "reg", -1);
> +       spi->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
> +       if (fdtdec_get_bool(blob, node, "spi-cpol"))
> +               mode |= SPI_CPOL;
> +       if (fdtdec_get_bool(blob, node, "spi-cpha"))
> +               mode |= SPI_CPHA;
> +       if (fdtdec_get_bool(blob, node, "spi-cs-high"))
> +               mode |= SPI_CS_HIGH;
> +       if (fdtdec_get_bool(blob, node, "spi-half-duplex"))
> +               mode |= SPI_PREAMBLE;
> +       spi->mode = mode;
> +
> +       return 0;
> +}
> +
> +UCLASS_DRIVER(spi) = {
> +       .id             = UCLASS_SPI,
> +       .name           = "spi",
> +       .post_bind      = spi_post_bind,
> +       .post_probe     = spi_post_probe,
> +       .per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
> +};
> +
> +UCLASS_DRIVER(spi_generic) = {
> +       .id             = UCLASS_SPI_GENERIC,
> +       .name           = "spi_generic",
> +};
> +
> +U_BOOT_DRIVER(spi_generic_drv) = {
> +       .name           = "spi_generic_drv",
> +       .id             = UCLASS_SPI_GENERIC,
> +};
> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
> index 7f0e37b..0afdc75 100644
> --- a/include/dm/uclass-id.h
> +++ b/include/dm/uclass-id.h
> @@ -22,6 +22,8 @@ enum uclass_id {
>         /* U-Boot uclasses start here */
>         UCLASS_GPIO,            /* Bank of general-purpose I/O pins */
>         UCLASS_SERIAL,          /* Serial UART */
> +       UCLASS_SPI,             /* SPI bus */
> +       UCLASS_SPI_GENERIC,     /* Generic SPI flash target */
>
>         UCLASS_COUNT,
>         UCLASS_INVALID = -1,
> diff --git a/include/spi.h b/include/spi.h
> index b673be2..89949b1 100644
> --- a/include/spi.h
> +++ b/include/spi.h
> @@ -54,12 +54,31 @@
>
>  #define SPI_DEFAULT_WORDLEN 8
>
> +#ifdef CONFIG_DM_SPI
> +struct dm_spi_bus {
> +       uint max_hz;
> +};
> +
> +#endif /* CONFIG_DM_SPI */
> +
>  /**
>   * struct spi_slave - Representation of a SPI slave
>   *
> - * Drivers are expected to extend this with controller-specific data.
> + * For driver model this is the per-child data used by the SPI bus. It can
> + * be accessed using dev_get_parentdata() on the slave device. Each SPI
> + * driver should define this child data in its U_BOOT_DRIVER() definition:
> + *
> + *     .per_child_auto_alloc_size      = sizeof(struct spi_slave),
>   *
> - * @bus:               ID of the bus that the slave is attached to.
> + * If not using driver model, drivers are expected to extend this with
> + * controller-specific data.
> + *
> + * @dev:               SPI slave device
> + * @max_hz:            Maximum speed for this slave
> + * @mode:              SPI mode to use for this slave (see SPI mode flags)
> + * @bus:               ID of the bus that the slave is attached to. For
> + *                     driver model this is the sequence number of the SPI
> + *                     bus (bus->seq) so does not need to be stored
>   * @cs:                        ID of the chip select connected to the slave.
>   * @op_mode_rx:                SPI RX operation mode.
>   * @op_mode_tx:                SPI TX operation mode.
> @@ -71,7 +90,13 @@
>   * @flags:             Indication of SPI flags.
>   */
>  struct spi_slave {
> +#ifdef CONFIG_DM_SPI
> +       struct udevice *dev;    /* struct spi_slave is dev->parentdata */
> +       uint max_hz;
> +       uint mode;
> +#else
>         unsigned int bus;
> +#endif
>         unsigned int cs;
>         u8 op_mode_rx;
>         u8 op_mode_tx;
> @@ -228,8 +253,9 @@ int  spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
>   * Returns: 1 if bus:cs identifies a valid chip on this board, 0
>   * otherwise.
>   */
> -int  spi_cs_is_valid(unsigned int bus, unsigned int cs);
> +int spi_cs_is_valid(unsigned int bus, unsigned int cs);
>
> +#ifndef CONFIG_DM_SPI
>  /**
>   * Activate a SPI chipselect.
>   * This function is provided by the board code when using a driver
> @@ -255,6 +281,7 @@ void spi_cs_deactivate(struct spi_slave *slave);
>   * @hz:                The transfer speed
>   */
>  void spi_set_speed(struct spi_slave *slave, uint hz);
> +#endif
>
>  /**
>   * Write 8 bits, then read 8 bits.
> @@ -305,4 +332,225 @@ struct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
>  struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum,
>                                            int node);
>
> +#ifdef CONFIG_DM_SPI
> +
> +/**
> + * struct spi_cs_info - Information about a bus chip select
> + *
> + * @dev:       Connected device, or NULL if none
> + */
> +struct spi_cs_info {
> +       struct udevice *dev;
> +};
> +
> +/**
> + * struct struct dm_spi_ops - Driver model SPI operations
> + *
> + * The uclass interface is implemented by all SPI devices which use
> + * driver model.
> + */
> +struct dm_spi_ops {
> +       /**
> +        * Claim the bus and prepare it for communication.
> +        *
> +        * The device provided is the slave device. It's parent controller
> +        * will be used to provide the communication.
> +        *
> +        * This must be called before doing any transfers with a SPI slave. It
> +        * will enable and initialize any SPI hardware as necessary, and make
> +        * sure that the SCK line is in the correct idle state. It is not
> +        * allowed to claim the same bus for several slaves without releasing
> +        * the bus in between.
> +        *
> +        * @bus:        The SPI slave
> +        *
> +        * Returns: 0 if the bus was claimed successfully, or a negative value
> +        * if it wasn't.
> +        */
> +       int (*claim_bus)(struct udevice *bus);
> +
> +       /**
> +        * Release the SPI bus
> +        *
> +        * This must be called once for every call to spi_claim_bus() after
> +        * all transfers have finished. It may disable any SPI hardware as
> +        * appropriate.
> +        *
> +        * @bus:        The SPI slave
> +        */
> +       int (*release_bus)(struct udevice *bus);
> +
> +       /**
> +        * Set the word length for SPI transactions
> +        *
> +        * Set the word length (number of bits per word) for SPI transactions.
> +        *
> +        * @bus:        The SPI slave
> +        * @wordlen:    The number of bits in a word
> +        *
> +        * Returns: 0 on success, -ve on failure.
> +        */
> +       int (*set_wordlen)(struct udevice *bus, unsigned int wordlen);
> +
> +       /**
> +        * SPI transfer
> +        *
> +        * This writes "bitlen" bits out the SPI MOSI port and simultaneously
> +        * clocks "bitlen" bits in the SPI MISO port.  That's just the way SPI
> +        * works.
> +        *
> +        * The source of the outgoing bits is the "dout" parameter and the
> +        * destination of the input bits is the "din" parameter.  Note that
> +        * "dout" and "din" can point to the same memory location, in which
> +        * case the input data overwrites the output data (since both are
> +        * buffered by temporary variables, this is OK).
> +        *
> +        * spi_xfer() interface:
> +        * @dev:        The slave device to communicate with
> +        * @bitlen:     How many bits to write and read.
> +        * @dout:       Pointer to a string of bits to send out.  The bits are
> +        *              held in a byte array and are sent MSB first.
> +        * @din:        Pointer to a string of bits that will be filled in.
> +        * @flags:      A bitwise combination of SPI_XFER_* flags.
> +        *
> +        * Returns: 0 on success, not -1 on failure
> +        */
> +       int (*xfer)(struct udevice *dev, unsigned int bitlen, const void *dout,
> +                   void *din, unsigned long flags);
> +
> +       /**
> +        * Set transfer speed.
> +        * This sets a new speed to be applied for next spi_xfer().
> +        * @bus:        The SPI bus
> +        * @hz:         The transfer speed
> +        * @return 0 if OK, -ve on error
> +        */
> +       int (*set_speed)(struct udevice *bus, uint hz);
> +
> +       /**
> +        * Set the SPI mode/flags
> +        *
> +        * It is unclear if we want to set speed and mode together instead
> +        * of separately.
> +        *
> +        * @bus:        The SPI bus
> +        * @mode:       Requested SPI mode (SPI_... flags)
> +        * @return 0 if OK, -ve on error
> +        */
> +       int (*set_mode)(struct udevice *bus, uint mode);
> +
> +       /**
> +        * Get information on a chip select
> +        *
> +        * This is only called when the SPI uclass does not know about a
> +        * chip select, i.e. it has no attached device. It gives the driver
> +        * a chance to allow activity on that chip select even so.
> +        *
> +        * @bus:        The SPI bus
> +        * @cs:         The chip select (0..n-1)
> +        * @info:       Returns information about the chip select, if valid.
> +        *              On entry info->dev is NULL
> +        * @return 0 if OK (and @info is set up), -ENODEV if the chip select
> +        *         is invalid, other -ve value on error
> +        */
> +       int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
> +};
> +
> +/**
> + * spi_find_bus_and_cs() - Find bus and slave devices by number
> + *
> + * Given a bus number and chip select, this finds the corresponding bus
> + * device and slave device. Neither device is activated by this function,
> + * although they may have been activated previously.
> + *
> + * @busnum:    SPI bus number
> + * @cs:                Chip select to look for
> + * @busp:      Returns bus device
> + * @devp:      Return slave device
> + * @return 0 if found, -ENODEV on error
> + */
> +int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp,
> +                       struct udevice **devp);
> +
> +/**
> + * spi_get_bus_and_cs() - Find and activate bus and slave devices by number
> + *
> + * Given a bus number and chip select, this finds the corresponding bus
> + * device and slave device.
> + *
> + * If no such slave exists, and drv_name is not NULL, then a new slave device
> + * is automatically bound on this chip select.
> + *
> + * Ths new slave device is probed ready for use with the given speed and mode.
> + *
> + * @busnum:    SPI bus number
> + * @cs:                Chip select to look for
> + * @speed:     SPI speed to use for this slave
> + * @mode:      SPI mode to use for this slave
> + * @drv_name:  Name of driver to attach to this chip select
> + * @dev_name:  Name of the new device thus created
> + * @busp:      Returns bus device
> + * @devp:      Return slave device
> + * @return 0 if found, -ve on error
> + */
> +int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
> +                       const char *drv_name, const char *dev_name,
> +                       struct udevice **busp, struct spi_slave **devp);
> +
> +/**
> + * spi_chip_select() - Get the chip select for a slave
> + *
> + * @return the chip select this slave is attached to
> + */
> +int spi_chip_select(struct udevice *slave);
> +
> +/**
> + * spi_bind_device() - bind a device to a bus's chip select
> + *
> + * This binds a new device to an given chip select (which must be unused).
> + *
> + * @bus:       SPI bus to search
> + * @cs:                Chip select to attach to
> + * @drv_name:  Name of driver to attach to this chip select
> + * @dev_name:  Name of the new device thus created
> + * @devp:      Returns the newly bound device
> + */
> +int spi_bind_device(struct udevice *bus, int cs, const char *drv_name,
> +                   const char *dev_name, struct udevice **devp);
> +
> +/**
> + * spi_ofdata_to_platdata() - decode standard SPI platform data
> + *
> + * This decodes the speed and mode from a device tree node and puts it into
> + * the spi_slave structure.
> + *
> + * @blob:      Device tree blob
> + * @node:      Node offset to read from
> + * @spi:       Place to put the decoded information
> + */
> +int spi_ofdata_to_platdata(const void *blob, int node, struct spi_slave *spi);
> +
> +/**
> + * spi_cs_info() - Check information on a chip select
> + *
> + * This checks a particular chip select on a bus to see if it has a device
> + * attached, or is even valid.
> + *
> + * @bus:       The SPI bus
> + * @cs:                The chip select (0..n-1)
> + * @info:      Returns information about the chip select, if valid
> + * @return 0 if OK (and @info is set up), -ENODEV if the chip select
> + *        is invalid, other -ve value on error
> + */
> +int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info);
> +
> +struct sandbox_state;
> +int sandbox_spi_get_emul(struct sandbox_state *state,
> +                        struct udevice *bus, struct udevice *slave,
> +                        struct udevice **emulp);
> +
> +/* Access the serial operations for a device */
> +#define spi_get_ops(dev)       ((struct dm_spi_ops *)(dev)->driver->ops)
> +#endif /* CONFIG_DM_SPI */
> +
>  #endif /* _SPI_H_ */
> --
> 2.1.0.rc2.206.gedb03e5
>

thanks!
-- 
Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-10-10 17:31   ` Jagan Teki
@ 2014-10-10 18:05     ` Simon Glass
  2014-10-10 18:37       ` Jagan Teki
  0 siblings, 1 reply; 49+ messages in thread
From: Simon Glass @ 2014-10-10 18:05 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 10 October 2014 11:31, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> Hi Simon,
>
> Can you please see my comments below, I'm relating more about cs and bus
> valid scenario which is available on current drivers wrt dm-spi.
>
> On 30 September 2014 01:05, Simon Glass <sjg@chromium.org> wrote:
>> Add a uclass which provides access to SPI buses and includes operations
>> required by SPI.
>>
>> For a time driver model will need to co-exist with the legacy SPI interface
>> so some parts of the header file are changed depending on which is in use.
>> The exports are adjusted also since some functions are not available with
>> driver model.
>>
>> Boards must define CONFIG_DM_SPI to use driver model for SPI.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> ---
>>
>> Changes in v3:
>> - Add a cs_info() method to the driver model SPI API
>
> I think this gives the enough info regarding cs on particular controller what
> about the bus usage - which is also specific to controller it self, right?
>
> Say - spi controller on a particular soc, have spi0, spi1 means two buses
> and 4 cs lines, cs0-cs3. How is this works in that case?
>
> And also I saw tegra20_sflash.c validates only cs
>
> int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
>                            struct spi_cs_info *info)
>
> What about bus number check this particular tegra spi controller is concern.

The bus device is passed in as a pointer. The bus number gets looked
up to find the device for that bus number. See spi_get_bus_and_cs()
for that.

This is good because drivers no longer need to validate the bus number.

>
>> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
>> - Add missing comments to spi.h
>> - Correct typo where 'slave' should say 'bus'
>> - Fix two comment typos
>> - Put the cs member back into spi_slave
>> - Use an explicit chip select value instead of reusing device sequence number
>>
>> Changes in v2:
>> - Add missing comments for struct spi_slave
>> - Fix code nits from Daniel Schwierzeck
>> - Use 'bus' instead of 'dev' to make the API clearer
>>
>>  common/exports.c         |   4 +-
>>  drivers/spi/Makefile     |   4 +
>>  drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
>>  include/dm/uclass-id.h   |   2 +
>>  include/spi.h            | 254 +++++++++++++++++++++++++++++-
>>  5 files changed, 650 insertions(+), 4 deletions(-)
>>  create mode 100644 drivers/spi/spi-uclass.c
>>


>> +int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
>
> Who is the caller for this?

This can be called by boards, or anywhere really. It replaces the
function with the same purpose in the old SPI framework.

Regards,
Simon

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-10-10 18:05     ` Simon Glass
@ 2014-10-10 18:37       ` Jagan Teki
  2014-10-10 23:26         ` Simon Glass
  0 siblings, 1 reply; 49+ messages in thread
From: Jagan Teki @ 2014-10-10 18:37 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On 10 October 2014 23:35, Simon Glass <sjg@chromium.org> wrote:
> Hi Jagan,
>
> On 10 October 2014 11:31, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>> Hi Simon,
>>
>> Can you please see my comments below, I'm relating more about cs and bus
>> valid scenario which is available on current drivers wrt dm-spi.
>>
>> On 30 September 2014 01:05, Simon Glass <sjg@chromium.org> wrote:
>>> Add a uclass which provides access to SPI buses and includes operations
>>> required by SPI.
>>>
>>> For a time driver model will need to co-exist with the legacy SPI interface
>>> so some parts of the header file are changed depending on which is in use.
>>> The exports are adjusted also since some functions are not available with
>>> driver model.
>>>
>>> Boards must define CONFIG_DM_SPI to use driver model for SPI.
>>>
>>> Signed-off-by: Simon Glass <sjg@chromium.org>
>>> ---
>>>
>>> Changes in v3:
>>> - Add a cs_info() method to the driver model SPI API
>>
>> I think this gives the enough info regarding cs on particular controller what
>> about the bus usage - which is also specific to controller it self, right?
>>
>> Say - spi controller on a particular soc, have spi0, spi1 means two buses
>> and 4 cs lines, cs0-cs3. How is this works in that case?
>>
>> And also I saw tegra20_sflash.c validates only cs
>>
>> int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
>>                            struct spi_cs_info *info)
>>
>> What about bus number check this particular tegra spi controller is concern.
>
> The bus device is passed in as a pointer. The bus number gets looked
> up to find the device for that bus number. See spi_get_bus_and_cs()
> for that.
>
> This is good because drivers no longer need to validate the bus number.

Agreed, but for controlling "sf probe bus:cs " options bus number
should get from
the respective driver.

I have a suggestion, like in spi_find_bus_and_cs() or spi_get_bus_and_cs()
we have a function calls for uclass_get_device_by_seq() and
spi_find_bus_and_cs()
along with that ops->cs_info(bus, cs, info) by adding bus number check
for the driver.

So-that there is no requirement to call spi_cs_is_valid from any other location
as bus and cs validates through commands itself.

BTW: in tegra20_sflash.c, how does tegra20_sflash_cs_info() called?

>
>>
>>> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
>>> - Add missing comments to spi.h
>>> - Correct typo where 'slave' should say 'bus'
>>> - Fix two comment typos
>>> - Put the cs member back into spi_slave
>>> - Use an explicit chip select value instead of reusing device sequence number
>>>
>>> Changes in v2:
>>> - Add missing comments for struct spi_slave
>>> - Fix code nits from Daniel Schwierzeck
>>> - Use 'bus' instead of 'dev' to make the API clearer
>>>
>>>  common/exports.c         |   4 +-
>>>  drivers/spi/Makefile     |   4 +
>>>  drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
>>>  include/dm/uclass-id.h   |   2 +
>>>  include/spi.h            | 254 +++++++++++++++++++++++++++++-
>>>  5 files changed, 650 insertions(+), 4 deletions(-)
>>>  create mode 100644 drivers/spi/spi-uclass.c
>>>
>
>
>>> +int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
>>
>> Who is the caller for this?
>
> This can be called by boards, or anywhere really. It replaces the
> function with the same purpose in the old SPI framework.

Please see above.

thanks!
-- 
Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-10-10 18:37       ` Jagan Teki
@ 2014-10-10 23:26         ` Simon Glass
  2014-10-11 17:33           ` Jagan Teki
  0 siblings, 1 reply; 49+ messages in thread
From: Simon Glass @ 2014-10-10 23:26 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 10 October 2014 12:37, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> Hi Simon,
>
> On 10 October 2014 23:35, Simon Glass <sjg@chromium.org> wrote:
>> Hi Jagan,
>>
>> On 10 October 2014 11:31, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>> Hi Simon,
>>>
>>> Can you please see my comments below, I'm relating more about cs and bus
>>> valid scenario which is available on current drivers wrt dm-spi.
>>>
>>> On 30 September 2014 01:05, Simon Glass <sjg@chromium.org> wrote:
>>>> Add a uclass which provides access to SPI buses and includes operations
>>>> required by SPI.
>>>>
>>>> For a time driver model will need to co-exist with the legacy SPI interface
>>>> so some parts of the header file are changed depending on which is in use.
>>>> The exports are adjusted also since some functions are not available with
>>>> driver model.
>>>>
>>>> Boards must define CONFIG_DM_SPI to use driver model for SPI.
>>>>
>>>> Signed-off-by: Simon Glass <sjg@chromium.org>
>>>> ---
>>>>
>>>> Changes in v3:
>>>> - Add a cs_info() method to the driver model SPI API
>>>
>>> I think this gives the enough info regarding cs on particular controller what
>>> about the bus usage - which is also specific to controller it self, right?
>>>
>>> Say - spi controller on a particular soc, have spi0, spi1 means two buses
>>> and 4 cs lines, cs0-cs3. How is this works in that case?
>>>
>>> And also I saw tegra20_sflash.c validates only cs
>>>
>>> int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
>>>                            struct spi_cs_info *info)
>>>
>>> What about bus number check this particular tegra spi controller is concern.
>>
>> The bus device is passed in as a pointer. The bus number gets looked
>> up to find the device for that bus number. See spi_get_bus_and_cs()
>> for that.
>>
>> This is good because drivers no longer need to validate the bus number.
>
> Agreed, but for controlling "sf probe bus:cs " options bus number
> should get from
> the respective driver.

I wonder if the issue here is a difference of understanding about bus
and chip select. In my mind, bus is just a device. We use the bus
number to specify which device we mean, but it is just a a
convenience. If there were some other way of finding the device we
would use it (as we do with device tree, for example).

Similarly, chip select is just a device. We look at the bus device,
find the appropriate chip select number, and end up with a child
device which is referred to by that chip select.

>
> I have a suggestion, like in spi_find_bus_and_cs() or spi_get_bus_and_cs()
> we have a function calls for uclass_get_device_by_seq() and
> spi_find_bus_and_cs()
> along with that ops->cs_info(bus, cs, info) by adding bus number check
> for the driver.
>
> So-that there is no requirement to call spi_cs_is_valid from any other location
> as bus and cs validates through commands itself.

At present spi_cs_info() calls spi_find_chip_select(). I think I see
what you are getting at - you don't want a device to be created unless
cs_info() allows it, right? I will take a look.

>
> BTW: in tegra20_sflash.c, how does tegra20_sflash_cs_info() called?

Only if someone calls spi_cs_info(). I don't think there are any
callers at present. With tegra using device tree I'm not sure it would
have any purpose - the chip selects and buses are all known.

>
>>
>>>
>>>> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
>>>> - Add missing comments to spi.h
>>>> - Correct typo where 'slave' should say 'bus'
>>>> - Fix two comment typos
>>>> - Put the cs member back into spi_slave
>>>> - Use an explicit chip select value instead of reusing device sequence number
>>>>
>>>> Changes in v2:
>>>> - Add missing comments for struct spi_slave
>>>> - Fix code nits from Daniel Schwierzeck
>>>> - Use 'bus' instead of 'dev' to make the API clearer
>>>>
>>>>  common/exports.c         |   4 +-
>>>>  drivers/spi/Makefile     |   4 +
>>>>  drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>  include/dm/uclass-id.h   |   2 +
>>>>  include/spi.h            | 254 +++++++++++++++++++++++++++++-
>>>>  5 files changed, 650 insertions(+), 4 deletions(-)
>>>>  create mode 100644 drivers/spi/spi-uclass.c
>>>>
>>
>>
>>>> +int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
>>>
>>> Who is the caller for this?
>>
>> This can be called by boards, or anywhere really. It replaces the
>> function with the same purpose in the old SPI framework.
>
> Please see above.
>
OK

Regards,
Simon

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-10-10 23:26         ` Simon Glass
@ 2014-10-11 17:33           ` Jagan Teki
  2014-10-11 17:43             ` Simon Glass
  0 siblings, 1 reply; 49+ messages in thread
From: Jagan Teki @ 2014-10-11 17:33 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On 11 October 2014 04:56, Simon Glass <sjg@chromium.org> wrote:
> Hi Jagan,
>
> On 10 October 2014 12:37, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>> Hi Simon,
>>
>> On 10 October 2014 23:35, Simon Glass <sjg@chromium.org> wrote:
>>> Hi Jagan,
>>>
>>> On 10 October 2014 11:31, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>>> Hi Simon,
>>>>
>>>> Can you please see my comments below, I'm relating more about cs and bus
>>>> valid scenario which is available on current drivers wrt dm-spi.
>>>>
>>>> On 30 September 2014 01:05, Simon Glass <sjg@chromium.org> wrote:
>>>>> Add a uclass which provides access to SPI buses and includes operations
>>>>> required by SPI.
>>>>>
>>>>> For a time driver model will need to co-exist with the legacy SPI interface
>>>>> so some parts of the header file are changed depending on which is in use.
>>>>> The exports are adjusted also since some functions are not available with
>>>>> driver model.
>>>>>
>>>>> Boards must define CONFIG_DM_SPI to use driver model for SPI.
>>>>>
>>>>> Signed-off-by: Simon Glass <sjg@chromium.org>
>>>>> ---
>>>>>
>>>>> Changes in v3:
>>>>> - Add a cs_info() method to the driver model SPI API
>>>>
>>>> I think this gives the enough info regarding cs on particular controller what
>>>> about the bus usage - which is also specific to controller it self, right?
>>>>
>>>> Say - spi controller on a particular soc, have spi0, spi1 means two buses
>>>> and 4 cs lines, cs0-cs3. How is this works in that case?
>>>>
>>>> And also I saw tegra20_sflash.c validates only cs
>>>>
>>>> int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
>>>>                            struct spi_cs_info *info)
>>>>
>>>> What about bus number check this particular tegra spi controller is concern.
>>>
>>> The bus device is passed in as a pointer. The bus number gets looked
>>> up to find the device for that bus number. See spi_get_bus_and_cs()
>>> for that.
>>>
>>> This is good because drivers no longer need to validate the bus number.
>>
>> Agreed, but for controlling "sf probe bus:cs " options bus number
>> should get from
>> the respective driver.
>
> I wonder if the issue here is a difference of understanding about bus
> and chip select. In my mind, bus is just a device. We use the bus
> number to specify which device we mean, but it is just a a
> convenience. If there were some other way of finding the device we
> would use it (as we do with device tree, for example).

Yes, I do believe that by mentioning bus spi0, spi1 on the devicetree
so the respective bus get's bind'ed till that fine. But as we use runtime
probe using "sf probe bus:cs" where I would mention
# sf probe 2:0
selecting spi2 which is of third bus on the same controller driver will that
spi_cs_is_valid() will show spi2 is invalid for this particular driver?

>
> Similarly, chip select is just a device. We look at the bus device,
> find the appropriate chip select number, and end up with a child
> device which is referred to by that chip select.

Just like validating supported cs, through cs_info I assume the same
works for bus as well as this is a pure driver specific theory.

>
>>
>> I have a suggestion, like in spi_find_bus_and_cs() or spi_get_bus_and_cs()
>> we have a function calls for uclass_get_device_by_seq() and
>> spi_find_bus_and_cs()
>> along with that ops->cs_info(bus, cs, info) by adding bus number check
>> for the driver.
>>
>> So-that there is no requirement to call spi_cs_is_valid from any other location
>> as bus and cs validates through commands itself.
>
> At present spi_cs_info() calls spi_find_chip_select(). I think I see
> what you are getting at - you don't want a device to be created unless
> cs_info() allows it, right? I will take a look.

Yes ie my point, along with that instead of a separate caller for spi_cs_info()
why can't we call in the probe time, either from command or at the time of
bus_cs binding.

Once the bus_cs binding done, and validate the mentioned bus and cs from
command or devicetree and return.

Does this make sense, please comment?

>
>>
>> BTW: in tegra20_sflash.c, how does tegra20_sflash_cs_info() called?
>
> Only if someone calls spi_cs_info(). I don't think there are any
> callers at present. With tegra using device tree I'm not sure it would
> have any purpose - the chip selects and buses are all known.

Yes devicetree will help to take but validating should be require as driver
only knows how many bus's with respective supported chip-selects based
on this command user may verify the same. what do think?

>
>>
>>>
>>>>
>>>>> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
>>>>> - Add missing comments to spi.h
>>>>> - Correct typo where 'slave' should say 'bus'
>>>>> - Fix two comment typos
>>>>> - Put the cs member back into spi_slave
>>>>> - Use an explicit chip select value instead of reusing device sequence number
>>>>>
>>>>> Changes in v2:
>>>>> - Add missing comments for struct spi_slave
>>>>> - Fix code nits from Daniel Schwierzeck
>>>>> - Use 'bus' instead of 'dev' to make the API clearer
>>>>>
>>>>>  common/exports.c         |   4 +-
>>>>>  drivers/spi/Makefile     |   4 +
>>>>>  drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  include/dm/uclass-id.h   |   2 +
>>>>>  include/spi.h            | 254 +++++++++++++++++++++++++++++-
>>>>>  5 files changed, 650 insertions(+), 4 deletions(-)
>>>>>  create mode 100644 drivers/spi/spi-uclass.c
>>>>>
>>>
>>>
>>>>> +int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
>>>>
>>>> Who is the caller for this?
>>>
>>> This can be called by boards, or anywhere really. It replaces the
>>> function with the same purpose in the old SPI framework.
>>
>> Please see above.
>>
> OK

thanks!
-- 
Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-10-11 17:33           ` Jagan Teki
@ 2014-10-11 17:43             ` Simon Glass
  2014-10-11 18:06               ` Jagan Teki
  0 siblings, 1 reply; 49+ messages in thread
From: Simon Glass @ 2014-10-11 17:43 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 11 October 2014 11:33, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> Hi Simon,
>
> On 11 October 2014 04:56, Simon Glass <sjg@chromium.org> wrote:
>> Hi Jagan,
>>
>> On 10 October 2014 12:37, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>> Hi Simon,
>>>
>>> On 10 October 2014 23:35, Simon Glass <sjg@chromium.org> wrote:
>>>> Hi Jagan,
>>>>
>>>> On 10 October 2014 11:31, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>>>> Hi Simon,
>>>>>
>>>>> Can you please see my comments below, I'm relating more about cs and bus
>>>>> valid scenario which is available on current drivers wrt dm-spi.
>>>>>
>>>>> On 30 September 2014 01:05, Simon Glass <sjg@chromium.org> wrote:
>>>>>> Add a uclass which provides access to SPI buses and includes operations
>>>>>> required by SPI.
>>>>>>
>>>>>> For a time driver model will need to co-exist with the legacy SPI interface
>>>>>> so some parts of the header file are changed depending on which is in use.
>>>>>> The exports are adjusted also since some functions are not available with
>>>>>> driver model.
>>>>>>
>>>>>> Boards must define CONFIG_DM_SPI to use driver model for SPI.
>>>>>>
>>>>>> Signed-off-by: Simon Glass <sjg@chromium.org>
>>>>>> ---
>>>>>>
>>>>>> Changes in v3:
>>>>>> - Add a cs_info() method to the driver model SPI API
>>>>>
>>>>> I think this gives the enough info regarding cs on particular controller what
>>>>> about the bus usage - which is also specific to controller it self, right?
>>>>>
>>>>> Say - spi controller on a particular soc, have spi0, spi1 means two buses
>>>>> and 4 cs lines, cs0-cs3. How is this works in that case?
>>>>>
>>>>> And also I saw tegra20_sflash.c validates only cs
>>>>>
>>>>> int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
>>>>>                            struct spi_cs_info *info)
>>>>>
>>>>> What about bus number check this particular tegra spi controller is concern.
>>>>
>>>> The bus device is passed in as a pointer. The bus number gets looked
>>>> up to find the device for that bus number. See spi_get_bus_and_cs()
>>>> for that.
>>>>
>>>> This is good because drivers no longer need to validate the bus number.
>>>
>>> Agreed, but for controlling "sf probe bus:cs " options bus number
>>> should get from
>>> the respective driver.
>>
>> I wonder if the issue here is a difference of understanding about bus
>> and chip select. In my mind, bus is just a device. We use the bus
>> number to specify which device we mean, but it is just a a
>> convenience. If there were some other way of finding the device we
>> would use it (as we do with device tree, for example).
>
> Yes, I do believe that by mentioning bus spi0, spi1 on the devicetree
> so the respective bus get's bind'ed till that fine. But as we use runtime
> probe using "sf probe bus:cs" where I would mention
> # sf probe 2:0
> selecting spi2 which is of third bus on the same controller driver will that
> spi_cs_is_valid() will show spi2 is invalid for this particular driver?

Run-time binding of SPI buses is supported by driver model (just call
device_bind()) but not by the sf probe command. We should know what
SPI buses exist through device tree or platform data.

So no, the that method is intended to validate a chip select, not a bus.

>
>>
>> Similarly, chip select is just a device. We look at the bus device,
>> find the appropriate chip select number, and end up with a child
>> device which is referred to by that chip select.
>
> Just like validating supported cs, through cs_info I assume the same
> works for bus as well as this is a pure driver specific theory.

Not at present. In fact I feel that both bus and cs should be known in
advance, but to keep compatibility (and since there is no platform
data available for chip selects) I have added the auto-bind used by
the 'sf probe' and 'sspi' commands.

>
>>
>>>
>>> I have a suggestion, like in spi_find_bus_and_cs() or spi_get_bus_and_cs()
>>> we have a function calls for uclass_get_device_by_seq() and
>>> spi_find_bus_and_cs()
>>> along with that ops->cs_info(bus, cs, info) by adding bus number check
>>> for the driver.
>>>
>>> So-that there is no requirement to call spi_cs_is_valid from any other location
>>> as bus and cs validates through commands itself.
>>
>> At present spi_cs_info() calls spi_find_chip_select(). I think I see
>> what you are getting at - you don't want a device to be created unless
>> cs_info() allows it, right? I will take a look.
>
> Yes ie my point, along with that instead of a separate caller for spi_cs_info()
> why can't we call in the probe time, either from command or at the time of
> bus_cs binding.
>
> Once the bus_cs binding done, and validate the mentioned bus and cs from
> command or devicetree and return.
>
> Does this make sense, please comment?

I'm starting to feel that (beyond the idea of using cs_info() more)
what you are referring to here is best handled in follow-up discussion
and patches once this initial support is merged. There seem to be
several questions that are hard to answer until we actually come to
implementation:

- qspi (could be implemented in sandbox, I don't have a qspi board at present)
- chip selects via GPIO (I am planning to look at this before long)
- platform data for chip selects (likely will be used for at91 or
something like that

>
>>
>>>
>>> BTW: in tegra20_sflash.c, how does tegra20_sflash_cs_info() called?
>>
>> Only if someone calls spi_cs_info(). I don't think there are any
>> callers at present. With tegra using device tree I'm not sure it would
>> have any purpose - the chip selects and buses are all known.
>
> Yes devicetree will help to take but validating should be require as driver
> only knows how many bus's with respective supported chip-selects based
> on this command user may verify the same. what do think?

I'm not sure what you are saying here. Can you please restate this?

The device tree should be able to completely specify the bus and chip
selects. I can't see a reason not to do this.

Regards,
Simon

>
>>
>>>
>>>>
>>>>>
>>>>>> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
>>>>>> - Add missing comments to spi.h
>>>>>> - Correct typo where 'slave' should say 'bus'
>>>>>> - Fix two comment typos
>>>>>> - Put the cs member back into spi_slave
>>>>>> - Use an explicit chip select value instead of reusing device sequence number
>>>>>>
>>>>>> Changes in v2:
>>>>>> - Add missing comments for struct spi_slave
>>>>>> - Fix code nits from Daniel Schwierzeck
>>>>>> - Use 'bus' instead of 'dev' to make the API clearer
>>>>>>
>>>>>>  common/exports.c         |   4 +-
>>>>>>  drivers/spi/Makefile     |   4 +
>>>>>>  drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>  include/dm/uclass-id.h   |   2 +
>>>>>>  include/spi.h            | 254 +++++++++++++++++++++++++++++-
>>>>>>  5 files changed, 650 insertions(+), 4 deletions(-)
>>>>>>  create mode 100644 drivers/spi/spi-uclass.c
>>>>>>
>>>>
>>>>
>>>>>> +int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
>>>>>
>>>>> Who is the caller for this?
>>>>
>>>> This can be called by boards, or anywhere really. It replaces the
>>>> function with the same purpose in the old SPI framework.
>>>
>>> Please see above.
>>>
>> OK
>
> thanks!
> --
> Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-10-11 17:43             ` Simon Glass
@ 2014-10-11 18:06               ` Jagan Teki
  2014-10-11 18:55                 ` Simon Glass
  0 siblings, 1 reply; 49+ messages in thread
From: Jagan Teki @ 2014-10-11 18:06 UTC (permalink / raw)
  To: u-boot

Hi Simon,

On 11 October 2014 23:13, Simon Glass <sjg@chromium.org> wrote:
> Hi Jagan,
>
> On 11 October 2014 11:33, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>> Hi Simon,
>>
>> On 11 October 2014 04:56, Simon Glass <sjg@chromium.org> wrote:
>>> Hi Jagan,
>>>
>>> On 10 October 2014 12:37, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>>> Hi Simon,
>>>>
>>>> On 10 October 2014 23:35, Simon Glass <sjg@chromium.org> wrote:
>>>>> Hi Jagan,
>>>>>
>>>>> On 10 October 2014 11:31, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>>>>> Hi Simon,
>>>>>>
>>>>>> Can you please see my comments below, I'm relating more about cs and bus
>>>>>> valid scenario which is available on current drivers wrt dm-spi.
>>>>>>
>>>>>> On 30 September 2014 01:05, Simon Glass <sjg@chromium.org> wrote:
>>>>>>> Add a uclass which provides access to SPI buses and includes operations
>>>>>>> required by SPI.
>>>>>>>
>>>>>>> For a time driver model will need to co-exist with the legacy SPI interface
>>>>>>> so some parts of the header file are changed depending on which is in use.
>>>>>>> The exports are adjusted also since some functions are not available with
>>>>>>> driver model.
>>>>>>>
>>>>>>> Boards must define CONFIG_DM_SPI to use driver model for SPI.
>>>>>>>
>>>>>>> Signed-off-by: Simon Glass <sjg@chromium.org>
>>>>>>> ---
>>>>>>>
>>>>>>> Changes in v3:
>>>>>>> - Add a cs_info() method to the driver model SPI API
>>>>>>
>>>>>> I think this gives the enough info regarding cs on particular controller what
>>>>>> about the bus usage - which is also specific to controller it self, right?
>>>>>>
>>>>>> Say - spi controller on a particular soc, have spi0, spi1 means two buses
>>>>>> and 4 cs lines, cs0-cs3. How is this works in that case?
>>>>>>
>>>>>> And also I saw tegra20_sflash.c validates only cs
>>>>>>
>>>>>> int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
>>>>>>                            struct spi_cs_info *info)
>>>>>>
>>>>>> What about bus number check this particular tegra spi controller is concern.
>>>>>
>>>>> The bus device is passed in as a pointer. The bus number gets looked
>>>>> up to find the device for that bus number. See spi_get_bus_and_cs()
>>>>> for that.
>>>>>
>>>>> This is good because drivers no longer need to validate the bus number.
>>>>
>>>> Agreed, but for controlling "sf probe bus:cs " options bus number
>>>> should get from
>>>> the respective driver.
>>>
>>> I wonder if the issue here is a difference of understanding about bus
>>> and chip select. In my mind, bus is just a device. We use the bus
>>> number to specify which device we mean, but it is just a a
>>> convenience. If there were some other way of finding the device we
>>> would use it (as we do with device tree, for example).
>>
>> Yes, I do believe that by mentioning bus spi0, spi1 on the devicetree
>> so the respective bus get's bind'ed till that fine. But as we use runtime
>> probe using "sf probe bus:cs" where I would mention
>> # sf probe 2:0
>> selecting spi2 which is of third bus on the same controller driver will that
>> spi_cs_is_valid() will show spi2 is invalid for this particular driver?
>
> Run-time binding of SPI buses is supported by driver model (just call
> device_bind()) but not by the sf probe command. We should know what
> SPI buses exist through device tree or platform data.
>
> So no, the that method is intended to validate a chip select, not a bus.
>
>>
>>>
>>> Similarly, chip select is just a device. We look at the bus device,
>>> find the appropriate chip select number, and end up with a child
>>> device which is referred to by that chip select.
>>
>> Just like validating supported cs, through cs_info I assume the same
>> works for bus as well as this is a pure driver specific theory.
>
> Not at present. In fact I feel that both bus and cs should be known in
> advance, but to keep compatibility (and since there is no platform
> data available for chip selects) I have added the auto-bind used by
> the 'sf probe' and 'sspi' commands.
>
>>
>>>
>>>>
>>>> I have a suggestion, like in spi_find_bus_and_cs() or spi_get_bus_and_cs()
>>>> we have a function calls for uclass_get_device_by_seq() and
>>>> spi_find_bus_and_cs()
>>>> along with that ops->cs_info(bus, cs, info) by adding bus number check
>>>> for the driver.
>>>>
>>>> So-that there is no requirement to call spi_cs_is_valid from any other location
>>>> as bus and cs validates through commands itself.
>>>
>>> At present spi_cs_info() calls spi_find_chip_select(). I think I see
>>> what you are getting at - you don't want a device to be created unless
>>> cs_info() allows it, right? I will take a look.
>>
>> Yes ie my point, along with that instead of a separate caller for spi_cs_info()
>> why can't we call in the probe time, either from command or at the time of
>> bus_cs binding.
>>
>> Once the bus_cs binding done, and validate the mentioned bus and cs from
>> command or devicetree and return.
>>
>> Does this make sense, please comment?
>
> I'm starting to feel that (beyond the idea of using cs_info() more)
> what you are referring to here is best handled in follow-up discussion
> and patches once this initial support is merged. There seem to be
> several questions that are hard to answer until we actually come to
> implementation:
>
> - qspi (could be implemented in sandbox, I don't have a qspi board at present)
> - chip selects via GPIO (I am planning to look at this before long)
> - platform data for chip selects (likely will be used for at91 or
> something like that

OK then - will start moving with this initial stuff update accordingly
in follow-up
changes/discussions.

>
>>
>>>
>>>>
>>>> BTW: in tegra20_sflash.c, how does tegra20_sflash_cs_info() called?
>>>
>>> Only if someone calls spi_cs_info(). I don't think there are any
>>> callers at present. With tegra using device tree I'm not sure it would
>>> have any purpose - the chip selects and buses are all known.
>>
>> Yes devicetree will help to take but validating should be require as driver
>> only knows how many bus's with respective supported chip-selects based
>> on this command user may verify the same. what do think?
>
> I'm not sure what you are saying here. Can you please restate this?
>
> The device tree should be able to completely specify the bus and chip
> selects. I can't see a reason not to do this.

I just stated, cs and bus numbers we can get it from devicetree but
for validating
how many number of bus's and cs's for a specific controller we can get through
driver specific call through cs_info().[of course bus is not
validating as of now]

>
> Regards,
> Simon
>
>>
>>>
>>>>
>>>>>
>>>>>>
>>>>>>> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
>>>>>>> - Add missing comments to spi.h
>>>>>>> - Correct typo where 'slave' should say 'bus'
>>>>>>> - Fix two comment typos
>>>>>>> - Put the cs member back into spi_slave
>>>>>>> - Use an explicit chip select value instead of reusing device sequence number
>>>>>>>
>>>>>>> Changes in v2:
>>>>>>> - Add missing comments for struct spi_slave
>>>>>>> - Fix code nits from Daniel Schwierzeck
>>>>>>> - Use 'bus' instead of 'dev' to make the API clearer
>>>>>>>
>>>>>>>  common/exports.c         |   4 +-
>>>>>>>  drivers/spi/Makefile     |   4 +
>>>>>>>  drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>  include/dm/uclass-id.h   |   2 +
>>>>>>>  include/spi.h            | 254 +++++++++++++++++++++++++++++-
>>>>>>>  5 files changed, 650 insertions(+), 4 deletions(-)
>>>>>>>  create mode 100644 drivers/spi/spi-uclass.c
>>>>>>>
>>>>>
>>>>>
>>>>>>> +int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
>>>>>>
>>>>>> Who is the caller for this?
>>>>>
>>>>> This can be called by boards, or anywhere really. It replaces the
>>>>> function with the same purpose in the old SPI framework.
>>>>
>>>> Please see above.
>>>>
>>> OK
>>

thanks!
-- 
Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
                   ` (29 preceding siblings ...)
  2014-10-08 20:33 ` [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
@ 2014-10-11 18:46 ` Jagan Teki
  2014-10-23  4:06   ` Simon Glass
  30 siblings, 1 reply; 49+ messages in thread
From: Jagan Teki @ 2014-10-11 18:46 UTC (permalink / raw)
  To: u-boot

On 30 September 2014 01:04, Simon Glass <sjg@chromium.org> wrote:
> Up until now driver model has not been used for any type of bus. Buses
> have some unique properties and needs, so we cannot claim that driver
> model can cover all the common cases unless we have converted a bus over
> to driver model.
>
> SPI is a reasonable choice for this next step. It has a fairly simple
> API and not too many dependencies. The main one is SPI flash so we may
> as well convert that also. Since the boards I test with have cros_ec I
> have also included that, for SPI only.
>
> The technique used is make use of driver model's supported data structures
> to hold information currently kept by each subsystem in a private data
> structure. Since 'struct spi_slave' relates to the slave device on the bus
> it is stored in the 'parent' data with each child device of the bus.
> Since 'struct spi_flash' is a standard interface used for each SPI flash
> driver, it is stored in the SPI FLash uclass's private data for each
> device.
>
> New defines are created to enable driver model for each subsystem. These
> are:
>
>    CONFIG_DM_SPI
>    CONFIG_DM_SPI_FLASH
>    CONFIG_DM_CROS_EC
>
> This allows us to move some boards and drivers to driver model, while
> leaving others behind. A 'big bang' conversion of everything to driver
> model, even at a subsystem level, is never going to work.
>
> There is some cost in changing the uclass interface after it is created,
> so if you have limited time, please spend it reviewing the uclass
> interfaces in spi.h and spi_flash.h. These need to be supported by each
> driver, so changing them later may involve changing multiple drivers.
>
> To assist with the conversion of other SPI drivers, a README file is
> added to walk through the process.
>
> So far, sandbox, exynos and tegra drivers are converted over.
>
> As always, driver model patches are available at u-boot-dm.git branch
> 'working'. There is a branch for just this series called 'spi-working'.
>
> Changes in v3:
> - Add a cs_info() method to the driver model SPI API
> - Add a debug() in the probe method
> - Add a few more debug() statements
> - Add a function comment for sandbox_spi_get_emul()
> - Add a missing tab character
> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
> - Add implementation/comment for the cs_info() method
> - Add missing comments to spi.h
> - Add new functions to iterate through device children
> - Add new patch to add a clarifying comment on struct udevice's seq member
> - Add new patch to add aliases for spi on tegra30 boards
> - Add new patch to allow parents to pass data to children during probe
> - Add new patch to convert Tegra SPI to driver model
> - Add spi.h header to 3 sh boards
> - Correct typo where 'slave' should say 'bus'
> - Expand SPI tests to cover compatibility functions
> - Fix two comment typos
> - Make sure the old device is both removed and unbound in 'sf probe'
> - Minor renames for clarity
> - Put the cs member back into spi_slave
> - Rebase to master
> - Remove the child_pre_probe() method which is no longer needed
> - Update for the new cs_info() method
> - Use a generic SPI device for the 'sspi command'
> - Use an explicit chip select value instead of reusing device sequence number
> - Word-wrap the first paragraph of the binding
>
> Changes in v2:
> - Add additional debug() statements
> - Add missing comments for struct spi_slave
> - Add spi.h header to dfu_sf.c
> - Adjust binding to avoid Linux-specific mentions
> - Adjust xfer() method for new API
> - Correct sandbox's xfer() method signature
> - Create a 'spi.bin' file for the SPI tests
> - Fix a typo in the commit message
> - Fix code nits from Daniel Schwierzeck
> - Fix comment on 'slave' parameter to match the parameter name
> - Fix typos reported by Jagannadha Sutradharudu Teki
> - Update for changes to exynos driver
> - Use 'bus' instead of 'dev' to distinguish bus from slave
> - Use 'bus' instead of 'dev' to make the API clearer
>
> Simon Glass (29):
>   sandbox: dts: Add a SPI device and cros_ec device

Reviewed-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>

>   dm: core: Add functions for iterating through device children
>   dm: core: Allow parents to pass data to children during probe
>   dm: core: Add a clarifying comment on struct udevice's seq member

Acked-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>

>   dm: spi: Add a uclass for SPI

Discussed some follow-up comments which will address in future add-ons

>   dm: sandbox: Add a SPI emulation uclass
>   dm: Remove spi_init() from board_r.c when using driver model
>   dm: Add spi.h header to a few files
>   dm: spi: Adjust cmd_spi to work with driver model
>   dm: sandbox: spi: Move to driver model
>   dm: spi: Rename soft_spi.c to soft_spi_legacy.c
>   dm: spi: Remove SPI_INIT feature
>   dm: spi: Add soft_spi implementation
>   dm: exynos: Convert SPI to driver model
>   dm: spi: Add documentation on how to convert over SPI drivers
>   exynos: universal_c210: Move to driver model soft_spi
>   sf: Tidy up public and private header files
>   spi: Use error return value in sf_ops
>   dm: sf: Add a uclass for SPI flash
>   dm: Convert spi_flash_probe() and 'sf probe' to use driver model
>   dm: sf: sandbox: Convert SPI flash driver to driver model
>   dm: exynos: config: Use driver model for SPI flash

Reviewed-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>

>   dm: spi: Add tests
>   dm: sf: Add tests for SPI flash

Acked-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>

>   dm: tegra: dts: Add aliases for spi on tegra30 boards
>   dm: tegra: spi: Convert to driver model

Reviewed-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>

>   dm: cros_ec: Add support for driver model
>   dm: sandbox: cros_ec: Move sandbox cros_ec to driver module
>   dm: exynos: cros_ec: Move cros_ec_spi to driver model

Acked-by: Jagannadha Sutradharudu Teki <jagannadh.teki@gmail.com>

>
>  arch/arm/dts/exynos4210-universal_c210.dts         |  13 +
>  arch/arm/dts/exynos5250-snow.dts                   |   8 +
>  arch/arm/dts/exynos5420-peach-pit.dts              |   1 +
>  arch/arm/dts/tegra20-trimslice.dts                 |   1 +
>  arch/arm/dts/tegra30-beaver.dts                    |   1 +
>  arch/arm/dts/tegra30-cardhu.dts                    |   1 +
>  arch/arm/dts/tegra30-colibri.dts                   |   1 +
>  arch/arm/include/asm/arch-tegra114/tegra114_spi.h  |  41 --
>  arch/arm/include/asm/arch-tegra20/tegra20_sflash.h |  41 --
>  arch/arm/include/asm/arch-tegra20/tegra20_slink.h  |  41 --
>  arch/sandbox/dts/sandbox.dts                       |  26 +
>  arch/sandbox/include/asm/spi.h                     |  13 -
>  arch/sandbox/include/asm/state.h                   |   2 +-
>  board/buffalo/lsxl/lsxl.c                          |   3 +-
>  board/compulab/common/eeprom.c                     |   2 +-
>  board/nvidia/common/board.c                        |   3 +-
>  board/renesas/sh7752evb/sh7752evb.c                |   1 +
>  board/renesas/sh7753evb/sh7753evb.c                |   1 +
>  board/renesas/sh7757lcr/sh7757lcr.c                |   1 +
>  board/samsung/common/board.c                       |   3 -
>  board/samsung/universal_c210/universal.c           |  52 --
>  common/board_r.c                                   |   2 +-
>  common/cmd_sf.c                                    |  26 +
>  common/cmd_spi.c                                   |  39 +-
>  common/cros_ec.c                                   |  30 ++
>  common/env_sf.c                                    |   1 +
>  common/exports.c                                   |   4 +-
>  doc/device-tree-bindings/mtd/spi/spi-flash.txt     |  25 +
>  doc/device-tree-bindings/spi/soft-spi.txt          |  34 ++
>  doc/driver-model/README.txt                        |   7 +-
>  doc/driver-model/spi-howto.txt                     | 594 +++++++++++++++++++++
>  drivers/core/device.c                              |  36 +-
>  drivers/dfu/dfu_sf.c                               |   1 +
>  drivers/misc/cros_ec.c                             | 122 ++++-
>  drivers/misc/cros_ec_sandbox.c                     |  99 +++-
>  drivers/misc/cros_ec_spi.c                         |  68 ++-
>  drivers/mtd/spi/Makefile                           |   7 +-
>  drivers/mtd/spi/ramtron.c                          |   1 +
>  drivers/mtd/spi/sandbox.c                          | 338 ++++++++++--
>  drivers/mtd/spi/sf-uclass.c                        |  63 +++
>  drivers/mtd/spi/sf_internal.h                      |  67 ++-
>  drivers/mtd/spi/sf_params.c                        |   1 +
>  drivers/mtd/spi/sf_probe.c                         | 154 ++++--
>  drivers/mtd/spi/spi_spl_load.c                     |   1 +
>  drivers/spi/Makefile                               |   9 +-
>  drivers/spi/exynos_spi.c                           | 513 +++++++-----------
>  drivers/spi/fdt_spi.c                              | 186 -------
>  drivers/spi/sandbox_spi.c                          | 200 +++----
>  drivers/spi/soft_spi.c                             | 227 +++++---
>  drivers/spi/soft_spi_legacy.c                      | 176 ++++++
>  drivers/spi/spi-emul-uclass.c                      |  15 +
>  drivers/spi/spi-uclass.c                           | 390 ++++++++++++++
>  drivers/spi/tegra114_spi.c                         | 254 ++++-----
>  drivers/spi/tegra20_sflash.c                       | 238 +++++----
>  drivers/spi/tegra20_slink.c                        | 235 ++++----
>  drivers/spi/tegra_spi.h                            |  12 +
>  include/configs/exynos-common.h                    |   2 +
>  include/configs/peach-pit.h                        |   1 +
>  include/configs/s5pc210_universal.h                |  12 +-
>  include/configs/sacsng.h                           |   1 -
>  include/configs/sandbox.h                          |   5 +-
>  include/configs/tegra-common-post.h                |   2 +-
>  include/configs/tegra-common.h                     |   2 +
>  include/configs/zipitz2.h                          |   1 -
>  include/cros_ec.h                                  |  27 +-
>  include/dm/device-internal.h                       |  13 +
>  include/dm/device.h                                |  25 +-
>  include/dm/uclass-id.h                             |   5 +
>  include/spi.h                                      | 299 ++++++++++-
>  include/spi_flash.h                                | 127 +++--
>  test/dm/Makefile                                   |   2 +
>  test/dm/bus.c                                      |  31 ++
>  test/dm/sf.c                                       |  43 ++
>  test/dm/spi.c                                      | 127 +++++
>  test/dm/test-dm.sh                                 |   2 +
>  test/dm/test.dts                                   |  17 +-
>  76 files changed, 3703 insertions(+), 1472 deletions(-)
>  delete mode 100644 arch/arm/include/asm/arch-tegra114/tegra114_spi.h
>  delete mode 100644 arch/arm/include/asm/arch-tegra20/tegra20_sflash.h
>  delete mode 100644 arch/arm/include/asm/arch-tegra20/tegra20_slink.h
>  create mode 100644 doc/device-tree-bindings/mtd/spi/spi-flash.txt
>  create mode 100644 doc/device-tree-bindings/spi/soft-spi.txt
>  create mode 100644 doc/driver-model/spi-howto.txt
>  create mode 100644 drivers/mtd/spi/sf-uclass.c
>  delete mode 100644 drivers/spi/fdt_spi.c
>  create mode 100644 drivers/spi/soft_spi_legacy.c
>  create mode 100644 drivers/spi/spi-emul-uclass.c
>  create mode 100644 drivers/spi/spi-uclass.c
>  create mode 100644 drivers/spi/tegra_spi.h
>  create mode 100644 test/dm/sf.c
>  create mode 100644 test/dm/spi.c
>
> --
> 2.1.0.rc2.206.gedb03e5
>

thanks!
-- 
Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI
  2014-10-11 18:06               ` Jagan Teki
@ 2014-10-11 18:55                 ` Simon Glass
  0 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-10-11 18:55 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 11 October 2014 12:06, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> Hi Simon,
>
> On 11 October 2014 23:13, Simon Glass <sjg@chromium.org> wrote:
>> Hi Jagan,
>>
>> On 11 October 2014 11:33, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>> Hi Simon,
>>>
>>> On 11 October 2014 04:56, Simon Glass <sjg@chromium.org> wrote:
>>>> Hi Jagan,
>>>>
>>>> On 10 October 2014 12:37, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>>>> Hi Simon,
>>>>>
>>>>> On 10 October 2014 23:35, Simon Glass <sjg@chromium.org> wrote:
>>>>>> Hi Jagan,
>>>>>>
>>>>>> On 10 October 2014 11:31, Jagan Teki <jagannadh.teki@gmail.com> wrote:
>>>>>>> Hi Simon,
>>>>>>>
>>>>>>> Can you please see my comments below, I'm relating more about cs and bus
>>>>>>> valid scenario which is available on current drivers wrt dm-spi.
>>>>>>>
>>>>>>> On 30 September 2014 01:05, Simon Glass <sjg@chromium.org> wrote:
>>>>>>>> Add a uclass which provides access to SPI buses and includes operations
>>>>>>>> required by SPI.
>>>>>>>>
>>>>>>>> For a time driver model will need to co-exist with the legacy SPI interface
>>>>>>>> so some parts of the header file are changed depending on which is in use.
>>>>>>>> The exports are adjusted also since some functions are not available with
>>>>>>>> driver model.
>>>>>>>>
>>>>>>>> Boards must define CONFIG_DM_SPI to use driver model for SPI.
>>>>>>>>
>>>>>>>> Signed-off-by: Simon Glass <sjg@chromium.org>
>>>>>>>> ---
>>>>>>>>
>>>>>>>> Changes in v3:
>>>>>>>> - Add a cs_info() method to the driver model SPI API
>>>>>>>
>>>>>>> I think this gives the enough info regarding cs on particular controller what
>>>>>>> about the bus usage - which is also specific to controller it self, right?
>>>>>>>
>>>>>>> Say - spi controller on a particular soc, have spi0, spi1 means two buses
>>>>>>> and 4 cs lines, cs0-cs3. How is this works in that case?
>>>>>>>
>>>>>>> And also I saw tegra20_sflash.c validates only cs
>>>>>>>
>>>>>>> int tegra20_sflash_cs_info(struct udevice *bus, unsigned int cs,
>>>>>>>                            struct spi_cs_info *info)
>>>>>>>
>>>>>>> What about bus number check this particular tegra spi controller is concern.
>>>>>>
>>>>>> The bus device is passed in as a pointer. The bus number gets looked
>>>>>> up to find the device for that bus number. See spi_get_bus_and_cs()
>>>>>> for that.
>>>>>>
>>>>>> This is good because drivers no longer need to validate the bus number.
>>>>>
>>>>> Agreed, but for controlling "sf probe bus:cs " options bus number
>>>>> should get from
>>>>> the respective driver.
>>>>
>>>> I wonder if the issue here is a difference of understanding about bus
>>>> and chip select. In my mind, bus is just a device. We use the bus
>>>> number to specify which device we mean, but it is just a a
>>>> convenience. If there were some other way of finding the device we
>>>> would use it (as we do with device tree, for example).
>>>
>>> Yes, I do believe that by mentioning bus spi0, spi1 on the devicetree
>>> so the respective bus get's bind'ed till that fine. But as we use runtime
>>> probe using "sf probe bus:cs" where I would mention
>>> # sf probe 2:0
>>> selecting spi2 which is of third bus on the same controller driver will that
>>> spi_cs_is_valid() will show spi2 is invalid for this particular driver?
>>
>> Run-time binding of SPI buses is supported by driver model (just call
>> device_bind()) but not by the sf probe command. We should know what
>> SPI buses exist through device tree or platform data.
>>
>> So no, the that method is intended to validate a chip select, not a bus.
>>
>>>
>>>>
>>>> Similarly, chip select is just a device. We look at the bus device,
>>>> find the appropriate chip select number, and end up with a child
>>>> device which is referred to by that chip select.
>>>
>>> Just like validating supported cs, through cs_info I assume the same
>>> works for bus as well as this is a pure driver specific theory.
>>
>> Not at present. In fact I feel that both bus and cs should be known in
>> advance, but to keep compatibility (and since there is no platform
>> data available for chip selects) I have added the auto-bind used by
>> the 'sf probe' and 'sspi' commands.
>>
>>>
>>>>
>>>>>
>>>>> I have a suggestion, like in spi_find_bus_and_cs() or spi_get_bus_and_cs()
>>>>> we have a function calls for uclass_get_device_by_seq() and
>>>>> spi_find_bus_and_cs()
>>>>> along with that ops->cs_info(bus, cs, info) by adding bus number check
>>>>> for the driver.
>>>>>
>>>>> So-that there is no requirement to call spi_cs_is_valid from any other location
>>>>> as bus and cs validates through commands itself.
>>>>
>>>> At present spi_cs_info() calls spi_find_chip_select(). I think I see
>>>> what you are getting at - you don't want a device to be created unless
>>>> cs_info() allows it, right? I will take a look.
>>>
>>> Yes ie my point, along with that instead of a separate caller for spi_cs_info()
>>> why can't we call in the probe time, either from command or at the time of
>>> bus_cs binding.
>>>
>>> Once the bus_cs binding done, and validate the mentioned bus and cs from
>>> command or devicetree and return.
>>>
>>> Does this make sense, please comment?
>>
>> I'm starting to feel that (beyond the idea of using cs_info() more)
>> what you are referring to here is best handled in follow-up discussion
>> and patches once this initial support is merged. There seem to be
>> several questions that are hard to answer until we actually come to
>> implementation:
>>
>> - qspi (could be implemented in sandbox, I don't have a qspi board at present)
>> - chip selects via GPIO (I am planning to look at this before long)
>> - platform data for chip selects (likely will be used for at91 or
>> something like that
>
> OK then - will start moving with this initial stuff update accordingly
> in follow-up
> changes/discussions.

OK.

>
>>
>>>
>>>>
>>>>>
>>>>> BTW: in tegra20_sflash.c, how does tegra20_sflash_cs_info() called?
>>>>
>>>> Only if someone calls spi_cs_info(). I don't think there are any
>>>> callers at present. With tegra using device tree I'm not sure it would
>>>> have any purpose - the chip selects and buses are all known.
>>>
>>> Yes devicetree will help to take but validating should be require as driver
>>> only knows how many bus's with respective supported chip-selects based
>>> on this command user may verify the same. what do think?
>>
>> I'm not sure what you are saying here. Can you please restate this?
>>
>> The device tree should be able to completely specify the bus and chip
>> selects. I can't see a reason not to do this.
>
> I just stated, cs and bus numbers we can get it from devicetree but
> for validating
> how many number of bus's and cs's for a specific controller we can get through
> driver specific call through cs_info().[of course bus is not
> validating as of now]

Let's pick this up when we have a specific problem to resolve, likely
platform data.

Regards,
Simon

>>>>>
>>>>>>
>>>>>>>
>>>>>>>> - Add a uclass for a generic SPI device (for use with the 'sspi' command)
>>>>>>>> - Add missing comments to spi.h
>>>>>>>> - Correct typo where 'slave' should say 'bus'
>>>>>>>> - Fix two comment typos
>>>>>>>> - Put the cs member back into spi_slave
>>>>>>>> - Use an explicit chip select value instead of reusing device sequence number
>>>>>>>>
>>>>>>>> Changes in v2:
>>>>>>>> - Add missing comments for struct spi_slave
>>>>>>>> - Fix code nits from Daniel Schwierzeck
>>>>>>>> - Use 'bus' instead of 'dev' to make the API clearer
>>>>>>>>
>>>>>>>>  common/exports.c         |   4 +-
>>>>>>>>  drivers/spi/Makefile     |   4 +
>>>>>>>>  drivers/spi/spi-uclass.c | 390 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>>  include/dm/uclass-id.h   |   2 +
>>>>>>>>  include/spi.h            | 254 +++++++++++++++++++++++++++++-
>>>>>>>>  5 files changed, 650 insertions(+), 4 deletions(-)
>>>>>>>>  create mode 100644 drivers/spi/spi-uclass.c
>>>>>>>>
>>>>>>
>>>>>>
>>>>>>>> +int spi_cs_is_valid(unsigned int busnum, unsigned int cs)
>>>>>>>
>>>>>>> Who is the caller for this?
>>>>>>
>>>>>> This can be called by boards, or anywhere really. It replaces the
>>>>>> function with the same purpose in the old SPI framework.
>>>>>
>>>>> Please see above.
>>>>>
>>>> OK
>>>
>
> thanks!
> --
> Jagan.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec
  2014-10-11 18:46 ` Jagan Teki
@ 2014-10-23  4:06   ` Simon Glass
  0 siblings, 0 replies; 49+ messages in thread
From: Simon Glass @ 2014-10-23  4:06 UTC (permalink / raw)
  To: u-boot

Hi,

On 11 October 2014 12:46, Jagan Teki <jagannadh.teki@gmail.com> wrote:
> On 30 September 2014 01:04, Simon Glass <sjg@chromium.org> wrote:
>> Up until now driver model has not been used for any type of bus. Buses
>> have some unique properties and needs, so we cannot claim that driver
>> model can cover all the common cases unless we have converted a bus over
>> to driver model.
>>
>> SPI is a reasonable choice for this next step. It has a fairly simple
>> API and not too many dependencies. The main one is SPI flash so we may
>> as well convert that also. Since the boards I test with have cros_ec I
>> have also included that, for SPI only.
>>
>> The technique used is make use of driver model's supported data structures
>> to hold information currently kept by each subsystem in a private data
>> structure. Since 'struct spi_slave' relates to the slave device on the bus
>> it is stored in the 'parent' data with each child device of the bus.
>> Since 'struct spi_flash' is a standard interface used for each SPI flash
>> driver, it is stored in the SPI FLash uclass's private data for each
>> device.
>>
>> New defines are created to enable driver model for each subsystem. These
>> are:
>>
>>    CONFIG_DM_SPI
>>    CONFIG_DM_SPI_FLASH
>>    CONFIG_DM_CROS_EC
>>
>> This allows us to move some boards and drivers to driver model, while
>> leaving others behind. A 'big bang' conversion of everything to driver
>> model, even at a subsystem level, is never going to work.
>>
>> There is some cost in changing the uclass interface after it is created,
>> so if you have limited time, please spend it reviewing the uclass
>> interfaces in spi.h and spi_flash.h. These need to be supported by each
>> driver, so changing them later may involve changing multiple drivers.
>>
>> To assist with the conversion of other SPI drivers, a README file is
>> added to walk through the process.
>>
>> So far, sandbox, exynos and tegra drivers are converted over.
>>
>> As always, driver model patches are available at u-boot-dm.git branch
>> 'working'. There is a branch for just this series called 'spi-working'.

It has taken me several months but I've sent a pull request for this
series and it should be in mainline soon. Please let me know of any
problems you find with Tegra and Exynos.

Regards,
Simon

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2014-10-23  4:06 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-29 19:34 [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
2014-09-29 19:34 ` [U-Boot] [PATCH v3 01/29] sandbox: dts: Add a SPI device and cros_ec device Simon Glass
2014-09-29 19:34 ` [U-Boot] [PATCH v3 02/29] dm: core: Add functions for iterating through device children Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 03/29] dm: core: Allow parents to pass data to children during probe Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 04/29] dm: core: Add a clarifying comment on struct udevice's seq member Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 05/29] dm: spi: Add a uclass for SPI Simon Glass
2014-10-10 17:31   ` Jagan Teki
2014-10-10 18:05     ` Simon Glass
2014-10-10 18:37       ` Jagan Teki
2014-10-10 23:26         ` Simon Glass
2014-10-11 17:33           ` Jagan Teki
2014-10-11 17:43             ` Simon Glass
2014-10-11 18:06               ` Jagan Teki
2014-10-11 18:55                 ` Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 06/29] dm: sandbox: Add a SPI emulation uclass Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 07/29] dm: Remove spi_init() from board_r.c when using driver model Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 08/29] dm: Add spi.h header to a few files Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 09/29] dm: spi: Adjust cmd_spi to work with driver model Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 10/29] dm: sandbox: spi: Move to " Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 11/29] dm: spi: Rename soft_spi.c to soft_spi_legacy.c Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 12/29] dm: spi: Remove SPI_INIT feature Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 13/29] dm: spi: Add soft_spi implementation Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 14/29] dm: exynos: Convert SPI to driver model Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 15/29] dm: spi: Add documentation on how to convert over SPI drivers Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 16/29] exynos: universal_c210: Move to driver model soft_spi Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 17/29] sf: Tidy up public and private header files Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 18/29] spi: Use error return value in sf_ops Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 19/29] dm: sf: Add a uclass for SPI flash Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 20/29] dm: Convert spi_flash_probe() and 'sf probe' to use driver model Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 21/29] dm: sf: sandbox: Convert SPI flash driver to " Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 22/29] dm: exynos: config: Use driver model for SPI flash Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 23/29] dm: spi: Add tests Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 24/29] dm: sf: Add tests for SPI flash Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 25/29] dm: tegra: dts: Add aliases for spi on tegra30 boards Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 26/29] dm: tegra: spi: Convert to driver model Simon Glass
2014-09-29 22:59   ` Igor Grinberg
2014-10-01  2:23     ` Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 27/29] dm: cros_ec: Add support for " Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 28/29] dm: sandbox: cros_ec: Move sandbox cros_ec to driver module Simon Glass
2014-09-29 19:35 ` [U-Boot] [PATCH v3 29/29] dm: exynos: cros_ec: Move cros_ec_spi to driver model Simon Glass
2014-10-08 20:33 ` [U-Boot] [PATCH v3 0/29] Introduce driver model support for SPI, SPI flash, cros_ec Simon Glass
2014-10-09 10:33   ` Jagan Teki
2014-10-10  2:06     ` Simon Glass
2014-10-10 13:30       ` Jagan Teki
2014-10-10 13:35         ` Simon Glass
2014-10-10 13:51           ` Jagan Teki
2014-10-10 13:56             ` Simon Glass
2014-10-11 18:46 ` Jagan Teki
2014-10-23  4:06   ` Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.