xref: /rk3399_rockchip-uboot/doc/driver-model/spi-howto.txt (revision 21342d4aed6c77a4aa7a5b2579b3c23e21aea31a)
16126c8e8SSimon GlassHow to port a SPI driver to driver model
26126c8e8SSimon Glass========================================
36126c8e8SSimon Glass
46126c8e8SSimon GlassHere is a rough step-by-step guide. It is based around converting the
56126c8e8SSimon Glassexynos SPI driver to driver model (DM) and the example code is based
62017aaefSSimon Glassaround U-Boot v2014.10-rc2 (commit be9f643). This has been updated for
72017aaefSSimon Glassv2015.04.
86126c8e8SSimon Glass
96126c8e8SSimon GlassIt is quite long since it includes actual code examples.
106126c8e8SSimon Glass
116126c8e8SSimon GlassBefore driver model, SPI drivers have their own private structure which
126126c8e8SSimon Glasscontains 'struct spi_slave'. With driver model, 'struct spi_slave' still
136126c8e8SSimon Glassexists, but now it is 'per-child data' for the SPI bus. Each child of the
146126c8e8SSimon GlassSPI bus is a SPI slave. The information that was stored in the
156126c8e8SSimon Glassdriver-specific slave structure can now be port in private data for the
166126c8e8SSimon GlassSPI bus.
176126c8e8SSimon Glass
186126c8e8SSimon GlassFor example, struct tegra_spi_slave looks like this:
196126c8e8SSimon Glass
206126c8e8SSimon Glassstruct tegra_spi_slave {
216126c8e8SSimon Glass	struct spi_slave slave;
226126c8e8SSimon Glass	struct tegra_spi_ctrl *ctrl;
236126c8e8SSimon Glass};
246126c8e8SSimon Glass
256126c8e8SSimon GlassIn this case 'slave' will be in per-child data, and 'ctrl' will be in the
266126c8e8SSimon GlassSPI's buses private data.
276126c8e8SSimon Glass
286126c8e8SSimon Glass
296126c8e8SSimon Glass0. How long does this take?
306126c8e8SSimon Glass
316126c8e8SSimon GlassYou should be able to complete this within 2 hours, including testing but
326126c8e8SSimon Glassexcluding preparing the patches. The API is basically the same as before
336126c8e8SSimon Glasswith only minor changes:
346126c8e8SSimon Glass
356126c8e8SSimon Glass- methods to set speed and mode are separated out
366126c8e8SSimon Glass- cs_info is used to get information on a chip select
376126c8e8SSimon Glass
386126c8e8SSimon Glass
396126c8e8SSimon Glass1. Enable driver mode for SPI and SPI flash
406126c8e8SSimon Glass
416126c8e8SSimon GlassAdd these to your board config:
426126c8e8SSimon Glass
43f94a1bedSSimon GlassCONFIG_DM_SPI
44f94a1bedSSimon GlassCONFIG_DM_SPI_FLASH
456126c8e8SSimon Glass
466126c8e8SSimon Glass
476126c8e8SSimon Glass2. Add the skeleton
486126c8e8SSimon Glass
496126c8e8SSimon GlassPut this code at the bottom of your existing driver file:
506126c8e8SSimon Glass
516126c8e8SSimon Glassstruct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs,
526126c8e8SSimon Glass			unsigned int max_hz, unsigned int mode)
536126c8e8SSimon Glass{
546126c8e8SSimon Glass	return NULL;
556126c8e8SSimon Glass}
566126c8e8SSimon Glass
576126c8e8SSimon Glassstruct spi_slave *spi_setup_slave_fdt(const void *blob, int slave_node,
586126c8e8SSimon Glass				      int spi_node)
596126c8e8SSimon Glass{
606126c8e8SSimon Glass	return NULL;
616126c8e8SSimon Glass}
626126c8e8SSimon Glass
636126c8e8SSimon Glassstatic int exynos_spi_ofdata_to_platdata(struct udevice *dev)
646126c8e8SSimon Glass{
656126c8e8SSimon Glass	return -ENODEV;
666126c8e8SSimon Glass}
676126c8e8SSimon Glass
686126c8e8SSimon Glassstatic int exynos_spi_probe(struct udevice *dev)
696126c8e8SSimon Glass{
706126c8e8SSimon Glass	return -ENODEV;
716126c8e8SSimon Glass}
726126c8e8SSimon Glass
736126c8e8SSimon Glassstatic int exynos_spi_remove(struct udevice *dev)
746126c8e8SSimon Glass{
756126c8e8SSimon Glass	return -ENODEV;
766126c8e8SSimon Glass}
776126c8e8SSimon Glass
786126c8e8SSimon Glassstatic int exynos_spi_claim_bus(struct udevice *dev)
796126c8e8SSimon Glass{
806126c8e8SSimon Glass
816126c8e8SSimon Glass	return -ENODEV;
826126c8e8SSimon Glass}
836126c8e8SSimon Glass
846126c8e8SSimon Glassstatic int exynos_spi_release_bus(struct udevice *dev)
856126c8e8SSimon Glass{
866126c8e8SSimon Glass
876126c8e8SSimon Glass	return -ENODEV;
886126c8e8SSimon Glass}
896126c8e8SSimon Glass
906126c8e8SSimon Glassstatic int exynos_spi_xfer(struct udevice *dev, unsigned int bitlen,
916126c8e8SSimon Glass			    const void *dout, void *din, unsigned long flags)
926126c8e8SSimon Glass{
936126c8e8SSimon Glass
946126c8e8SSimon Glass	return -ENODEV;
956126c8e8SSimon Glass}
966126c8e8SSimon Glass
976126c8e8SSimon Glassstatic int exynos_spi_set_speed(struct udevice *dev, uint speed)
986126c8e8SSimon Glass{
996126c8e8SSimon Glass	return -ENODEV;
1006126c8e8SSimon Glass}
1016126c8e8SSimon Glass
1026126c8e8SSimon Glassstatic int exynos_spi_set_mode(struct udevice *dev, uint mode)
1036126c8e8SSimon Glass{
1046126c8e8SSimon Glass	return -ENODEV;
1056126c8e8SSimon Glass}
1066126c8e8SSimon Glass
1076126c8e8SSimon Glassstatic int exynos_cs_info(struct udevice *bus, uint cs,
1086126c8e8SSimon Glass			  struct spi_cs_info *info)
1096126c8e8SSimon Glass{
1106126c8e8SSimon Glass	return -ENODEV;
1116126c8e8SSimon Glass}
1126126c8e8SSimon Glass
1136126c8e8SSimon Glassstatic const struct dm_spi_ops exynos_spi_ops = {
1146126c8e8SSimon Glass	.claim_bus	= exynos_spi_claim_bus,
1156126c8e8SSimon Glass	.release_bus	= exynos_spi_release_bus,
1166126c8e8SSimon Glass	.xfer		= exynos_spi_xfer,
1176126c8e8SSimon Glass	.set_speed	= exynos_spi_set_speed,
1186126c8e8SSimon Glass	.set_mode	= exynos_spi_set_mode,
1196126c8e8SSimon Glass	.cs_info	= exynos_cs_info,
1206126c8e8SSimon Glass};
1216126c8e8SSimon Glass
1226126c8e8SSimon Glassstatic const struct udevice_id exynos_spi_ids[] = {
1236126c8e8SSimon Glass	{ .compatible = "samsung,exynos-spi" },
1246126c8e8SSimon Glass	{ }
1256126c8e8SSimon Glass};
1266126c8e8SSimon Glass
1276126c8e8SSimon GlassU_BOOT_DRIVER(exynos_spi) = {
1286126c8e8SSimon Glass	.name	= "exynos_spi",
1296126c8e8SSimon Glass	.id	= UCLASS_SPI,
1306126c8e8SSimon Glass	.of_match = exynos_spi_ids,
1316126c8e8SSimon Glass	.ops	= &exynos_spi_ops,
1326126c8e8SSimon Glass	.ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
1336126c8e8SSimon Glass	.probe	= exynos_spi_probe,
1346126c8e8SSimon Glass	.remove	= exynos_spi_remove,
1356126c8e8SSimon Glass};
1366126c8e8SSimon Glass
1376126c8e8SSimon Glass
1386126c8e8SSimon Glass3. Replace 'exynos' in the above code with your driver name
1396126c8e8SSimon Glass
1406126c8e8SSimon Glass
1416126c8e8SSimon Glass4. #ifdef out all of the code in your driver except for the above
1426126c8e8SSimon Glass
1436126c8e8SSimon GlassThis will allow you to get it building, which means you can work
1446126c8e8SSimon Glassincrementally. Since all the methods return an error initially, there is
1456126c8e8SSimon Glassless chance that you will accidentally leave something in.
1466126c8e8SSimon Glass
1476126c8e8SSimon GlassAlso, even though your conversion is basically a rewrite, it might help
1486126c8e8SSimon Glassreviewers if you leave functions in the same place in the file,
1496126c8e8SSimon Glassparticularly for large drivers.
1506126c8e8SSimon Glass
1516126c8e8SSimon Glass
1526126c8e8SSimon Glass5. Add some includes
1536126c8e8SSimon Glass
1546126c8e8SSimon GlassAdd these includes to your driver:
1556126c8e8SSimon Glass
1566126c8e8SSimon Glass#include <dm.h>
1576126c8e8SSimon Glass#include <errno.h>
1586126c8e8SSimon Glass
1596126c8e8SSimon Glass
1606126c8e8SSimon Glass6. Build
1616126c8e8SSimon Glass
1626126c8e8SSimon GlassAt this point you should be able to build U-Boot for your board with the
1636126c8e8SSimon Glassempty SPI driver. You still have empty methods in your driver, but we will
1646126c8e8SSimon Glasswrite these one by one.
1656126c8e8SSimon Glass
1666126c8e8SSimon GlassIf you have spi_init() functions or the like that are called from your
1676126c8e8SSimon Glassboard then the build will fail. Remove these calls and make a note of the
1686126c8e8SSimon Glassinit that needs to be done.
1696126c8e8SSimon Glass
1706126c8e8SSimon Glass
1716126c8e8SSimon Glass7. Set up your platform data structure
1726126c8e8SSimon Glass
1736126c8e8SSimon GlassThis will hold the information your driver to operate, like its hardware
1746126c8e8SSimon Glassaddress or maximum frequency.
1756126c8e8SSimon Glass
1766126c8e8SSimon GlassYou may already have a struct like this, or you may need to create one
1776126c8e8SSimon Glassfrom some of the #defines or global variables in the driver.
1786126c8e8SSimon Glass
1796126c8e8SSimon GlassNote that this information is not the run-time information. It should not
1806126c8e8SSimon Glassinclude state that changes. It should be fixed throughout the live of
1816126c8e8SSimon GlassU-Boot. Run-time information comes later.
1826126c8e8SSimon Glass
1836126c8e8SSimon GlassHere is what was in the exynos spi driver:
1846126c8e8SSimon Glass
1856126c8e8SSimon Glassstruct spi_bus {
1866126c8e8SSimon Glass	enum periph_id periph_id;
1876126c8e8SSimon Glass	s32 frequency;		/* Default clock frequency, -1 for none */
1886126c8e8SSimon Glass	struct exynos_spi *regs;
1896126c8e8SSimon Glass	int inited;		/* 1 if this bus is ready for use */
1906126c8e8SSimon Glass	int node;
1916126c8e8SSimon Glass	uint deactivate_delay_us;	/* Delay to wait after deactivate */
1926126c8e8SSimon Glass};
1936126c8e8SSimon Glass
1946126c8e8SSimon GlassOf these, inited is handled by DM and node is the device tree node, which
1956126c8e8SSimon GlassDM tells you. The name is not quite right. So in this case we would use:
1966126c8e8SSimon Glass
1976126c8e8SSimon Glassstruct exynos_spi_platdata {
1986126c8e8SSimon Glass	enum periph_id periph_id;
1996126c8e8SSimon Glass	s32 frequency;		/* Default clock frequency, -1 for none */
2006126c8e8SSimon Glass	struct exynos_spi *regs;
2016126c8e8SSimon Glass	uint deactivate_delay_us;	/* Delay to wait after deactivate */
2026126c8e8SSimon Glass};
2036126c8e8SSimon Glass
2046126c8e8SSimon Glass
2056126c8e8SSimon Glass8a. Write ofdata_to_platdata()   [for device tree only]
2066126c8e8SSimon Glass
2076126c8e8SSimon GlassThis method will convert information in the device tree node into a C
2086126c8e8SSimon Glassstructure in your driver (called platform data). If you are not using
2096126c8e8SSimon Glassdevice tree, go to 8b.
2106126c8e8SSimon Glass
2116126c8e8SSimon GlassDM will automatically allocate the struct for us when we are using device
2126126c8e8SSimon Glasstree, but we need to tell it the size:
2136126c8e8SSimon Glass
2146126c8e8SSimon GlassU_BOOT_DRIVER(spi_exynos) = {
2156126c8e8SSimon Glass...
2166126c8e8SSimon Glass	.platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
2176126c8e8SSimon Glass
2186126c8e8SSimon Glass
2196126c8e8SSimon GlassHere is a sample function. It gets a pointer to the platform data and
2206126c8e8SSimon Glassfills in the fields from device tree.
2216126c8e8SSimon Glass
2226126c8e8SSimon Glassstatic int exynos_spi_ofdata_to_platdata(struct udevice *bus)
2236126c8e8SSimon Glass{
2246126c8e8SSimon Glass	struct exynos_spi_platdata *plat = bus->platdata;
2256126c8e8SSimon Glass	const void *blob = gd->fdt_blob;
226*e160f7d4SSimon Glass	int node = dev_of_offset(bus);
2276126c8e8SSimon Glass
2286126c8e8SSimon Glass	plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
2296126c8e8SSimon Glass	plat->periph_id = pinmux_decode_periph_id(blob, node);
2306126c8e8SSimon Glass
2316126c8e8SSimon Glass	if (plat->periph_id == PERIPH_ID_NONE) {
2326126c8e8SSimon Glass		debug("%s: Invalid peripheral ID %d\n", __func__,
2336126c8e8SSimon Glass			plat->periph_id);
2346126c8e8SSimon Glass		return -FDT_ERR_NOTFOUND;
2356126c8e8SSimon Glass	}
2366126c8e8SSimon Glass
2376126c8e8SSimon Glass	/* Use 500KHz as a suitable default */
2386126c8e8SSimon Glass	plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
2396126c8e8SSimon Glass					500000);
2406126c8e8SSimon Glass	plat->deactivate_delay_us = fdtdec_get_int(blob, node,
2416126c8e8SSimon Glass					"spi-deactivate-delay", 0);
2426126c8e8SSimon Glass	debug("%s: regs=%p, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
2436126c8e8SSimon Glass	      __func__, plat->regs, plat->periph_id, plat->frequency,
2446126c8e8SSimon Glass              plat->deactivate_delay_us);
2456126c8e8SSimon Glass
2466126c8e8SSimon Glass	return 0;
2476126c8e8SSimon Glass}
2486126c8e8SSimon Glass
2496126c8e8SSimon Glass
2506126c8e8SSimon Glass8b. Add the platform data  [non-device-tree only]
2516126c8e8SSimon Glass
2526126c8e8SSimon GlassSpecify this data in a U_BOOT_DEVICE() declaration in your board file:
2536126c8e8SSimon Glass
2546126c8e8SSimon Glassstruct exynos_spi_platdata platdata_spi0 = {
2556126c8e8SSimon Glass	.periph_id = ...
2566126c8e8SSimon Glass	.frequency = ...
2576126c8e8SSimon Glass	.regs = ...
2586126c8e8SSimon Glass	.deactivate_delay_us = ...
2596126c8e8SSimon Glass};
2606126c8e8SSimon Glass
2616126c8e8SSimon GlassU_BOOT_DEVICE(board_spi0) = {
2626126c8e8SSimon Glass	.name = "exynos_spi",
2636126c8e8SSimon Glass	.platdata = &platdata_spi0,
2646126c8e8SSimon Glass};
2656126c8e8SSimon Glass
2662017aaefSSimon GlassYou will unfortunately need to put the struct definition into a header file
2672017aaefSSimon Glassin this case so that your board file can use it.
2686126c8e8SSimon Glass
2696126c8e8SSimon Glass
2706126c8e8SSimon Glass9. Add the device private data
2716126c8e8SSimon Glass
2726126c8e8SSimon GlassMost devices have some private data which they use to keep track of things
2736126c8e8SSimon Glasswhile active. This is the run-time information and needs to be stored in
2746126c8e8SSimon Glassa structure. There is probably a structure in the driver that includes a
2756126c8e8SSimon Glass'struct spi_slave', so you can use that.
2766126c8e8SSimon Glass
2776126c8e8SSimon Glassstruct exynos_spi_slave {
2786126c8e8SSimon Glass	struct spi_slave slave;
2796126c8e8SSimon Glass	struct exynos_spi *regs;
2806126c8e8SSimon Glass	unsigned int freq;		/* Default frequency */
2816126c8e8SSimon Glass	unsigned int mode;
2826126c8e8SSimon Glass	enum periph_id periph_id;	/* Peripheral ID for this device */
2836126c8e8SSimon Glass	unsigned int fifo_size;
2846126c8e8SSimon Glass	int skip_preamble;
2856126c8e8SSimon Glass	struct spi_bus *bus;		/* Pointer to our SPI bus info */
2866126c8e8SSimon Glass	ulong last_transaction_us;	/* Time of last transaction end */
2876126c8e8SSimon Glass};
2886126c8e8SSimon Glass
2896126c8e8SSimon Glass
2906126c8e8SSimon GlassWe should rename this to make its purpose more obvious, and get rid of
2916126c8e8SSimon Glassthe slave structure, so we have:
2926126c8e8SSimon Glass
2936126c8e8SSimon Glassstruct exynos_spi_priv {
2946126c8e8SSimon Glass	struct exynos_spi *regs;
2956126c8e8SSimon Glass	unsigned int freq;		/* Default frequency */
2966126c8e8SSimon Glass	unsigned int mode;
2976126c8e8SSimon Glass	enum periph_id periph_id;	/* Peripheral ID for this device */
2986126c8e8SSimon Glass	unsigned int fifo_size;
2996126c8e8SSimon Glass	int skip_preamble;
3006126c8e8SSimon Glass	ulong last_transaction_us;	/* Time of last transaction end */
3016126c8e8SSimon Glass};
3026126c8e8SSimon Glass
3036126c8e8SSimon Glass
3046126c8e8SSimon GlassDM can auto-allocate this also:
3056126c8e8SSimon Glass
3066126c8e8SSimon GlassU_BOOT_DRIVER(spi_exynos) = {
3076126c8e8SSimon Glass...
3086126c8e8SSimon Glass	.priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
3096126c8e8SSimon Glass
3106126c8e8SSimon Glass
3116126c8e8SSimon GlassNote that this is created before the probe method is called, and destroyed
3126126c8e8SSimon Glassafter the remove method is called. It will be zeroed when the probe
3136126c8e8SSimon Glassmethod is called.
3146126c8e8SSimon Glass
3156126c8e8SSimon Glass
3166126c8e8SSimon Glass10. Add the probe() and remove() methods
3176126c8e8SSimon Glass
3186126c8e8SSimon GlassNote: It's a good idea to build repeatedly as you are working, to avoid a
3196126c8e8SSimon Glasshuge amount of work getting things compiling at the end.
3206126c8e8SSimon Glass
3216126c8e8SSimon GlassThe probe method is supposed to set up the hardware. U-Boot used to use
3226126c8e8SSimon Glassspi_setup_slave() to do this. So take a look at this function and see
3236126c8e8SSimon Glasswhat you can copy out to set things up.
3246126c8e8SSimon Glass
3256126c8e8SSimon Glass
3266126c8e8SSimon Glassstatic int exynos_spi_probe(struct udevice *bus)
3276126c8e8SSimon Glass{
3286126c8e8SSimon Glass	struct exynos_spi_platdata *plat = dev_get_platdata(bus);
3296126c8e8SSimon Glass	struct exynos_spi_priv *priv = dev_get_priv(bus);
3306126c8e8SSimon Glass
3316126c8e8SSimon Glass	priv->regs = plat->regs;
3326126c8e8SSimon Glass	if (plat->periph_id == PERIPH_ID_SPI1 ||
3336126c8e8SSimon Glass	    plat->periph_id == PERIPH_ID_SPI2)
3346126c8e8SSimon Glass		priv->fifo_size = 64;
3356126c8e8SSimon Glass	else
3366126c8e8SSimon Glass		priv->fifo_size = 256;
3376126c8e8SSimon Glass
3386126c8e8SSimon Glass	priv->skip_preamble = 0;
3396126c8e8SSimon Glass	priv->last_transaction_us = timer_get_us();
3406126c8e8SSimon Glass	priv->freq = plat->frequency;
3416126c8e8SSimon Glass	priv->periph_id = plat->periph_id;
3426126c8e8SSimon Glass
3436126c8e8SSimon Glass	return 0;
3446126c8e8SSimon Glass}
3456126c8e8SSimon Glass
3466126c8e8SSimon GlassThis implementation doesn't actually touch the hardware, which is somewhat
3476126c8e8SSimon Glassunusual for a driver. In this case we will do that when the device is
3486126c8e8SSimon Glassclaimed by something that wants to use the SPI bus.
3496126c8e8SSimon Glass
3506126c8e8SSimon GlassFor remove we could shut down the clocks, but in this case there is
3516126c8e8SSimon Glassnothing to do. DM frees any memory that it allocated, so we can just
3526126c8e8SSimon Glassremove exynos_spi_remove() and its reference in U_BOOT_DRIVER.
3536126c8e8SSimon Glass
3546126c8e8SSimon Glass
3556126c8e8SSimon Glass11. Implement set_speed()
3566126c8e8SSimon Glass
3576126c8e8SSimon GlassThis should set up clocks so that the SPI bus is running at the right
3586126c8e8SSimon Glassspeed. With the old API spi_claim_bus() would normally do this and several
3596126c8e8SSimon Glassof the following functions, so let's look at that function:
3606126c8e8SSimon Glass
3616126c8e8SSimon Glassint spi_claim_bus(struct spi_slave *slave)
3626126c8e8SSimon Glass{
3636126c8e8SSimon Glass	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
3646126c8e8SSimon Glass	struct exynos_spi *regs = spi_slave->regs;
3656126c8e8SSimon Glass	u32 reg = 0;
3666126c8e8SSimon Glass	int ret;
3676126c8e8SSimon Glass
3686126c8e8SSimon Glass	ret = set_spi_clk(spi_slave->periph_id,
3696126c8e8SSimon Glass					spi_slave->freq);
3706126c8e8SSimon Glass	if (ret < 0) {
3716126c8e8SSimon Glass		debug("%s: Failed to setup spi clock\n", __func__);
3726126c8e8SSimon Glass		return ret;
3736126c8e8SSimon Glass	}
3746126c8e8SSimon Glass
3756126c8e8SSimon Glass	exynos_pinmux_config(spi_slave->periph_id, PINMUX_FLAG_NONE);
3766126c8e8SSimon Glass
3776126c8e8SSimon Glass	spi_flush_fifo(slave);
3786126c8e8SSimon Glass
3796126c8e8SSimon Glass	reg = readl(&regs->ch_cfg);
3806126c8e8SSimon Glass	reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
3816126c8e8SSimon Glass
3826126c8e8SSimon Glass	if (spi_slave->mode & SPI_CPHA)
3836126c8e8SSimon Glass		reg |= SPI_CH_CPHA_B;
3846126c8e8SSimon Glass
3856126c8e8SSimon Glass	if (spi_slave->mode & SPI_CPOL)
3866126c8e8SSimon Glass		reg |= SPI_CH_CPOL_L;
3876126c8e8SSimon Glass
3886126c8e8SSimon Glass	writel(reg, &regs->ch_cfg);
3896126c8e8SSimon Glass	writel(SPI_FB_DELAY_180, &regs->fb_clk);
3906126c8e8SSimon Glass
3916126c8e8SSimon Glass	return 0;
3926126c8e8SSimon Glass}
3936126c8e8SSimon Glass
3946126c8e8SSimon Glass
3956126c8e8SSimon GlassIt sets up the speed, mode, pinmux, feedback delay and clears the FIFOs.
3966126c8e8SSimon GlassWith DM these will happen in separate methods.
3976126c8e8SSimon Glass
3986126c8e8SSimon Glass
3996126c8e8SSimon GlassHere is an example for the speed part:
4006126c8e8SSimon Glass
4016126c8e8SSimon Glassstatic int exynos_spi_set_speed(struct udevice *bus, uint speed)
4026126c8e8SSimon Glass{
4036126c8e8SSimon Glass	struct exynos_spi_platdata *plat = bus->platdata;
4046126c8e8SSimon Glass	struct exynos_spi_priv *priv = dev_get_priv(bus);
4056126c8e8SSimon Glass	int ret;
4066126c8e8SSimon Glass
4076126c8e8SSimon Glass	if (speed > plat->frequency)
4086126c8e8SSimon Glass		speed = plat->frequency;
4096126c8e8SSimon Glass	ret = set_spi_clk(priv->periph_id, speed);
4106126c8e8SSimon Glass	if (ret)
4116126c8e8SSimon Glass		return ret;
4126126c8e8SSimon Glass	priv->freq = speed;
4136126c8e8SSimon Glass	debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
4146126c8e8SSimon Glass
4156126c8e8SSimon Glass	return 0;
4166126c8e8SSimon Glass}
4176126c8e8SSimon Glass
4186126c8e8SSimon Glass
4196126c8e8SSimon Glass12. Implement set_mode()
4206126c8e8SSimon Glass
4216126c8e8SSimon GlassThis should adjust the SPI mode (polarity, etc.). Again this code probably
4226126c8e8SSimon Glasscomes from the old spi_claim_bus(). Here is an example:
4236126c8e8SSimon Glass
4246126c8e8SSimon Glass
4256126c8e8SSimon Glassstatic int exynos_spi_set_mode(struct udevice *bus, uint mode)
4266126c8e8SSimon Glass{
4276126c8e8SSimon Glass	struct exynos_spi_priv *priv = dev_get_priv(bus);
4286126c8e8SSimon Glass	uint32_t reg;
4296126c8e8SSimon Glass
4306126c8e8SSimon Glass	reg = readl(&priv->regs->ch_cfg);
4316126c8e8SSimon Glass	reg &= ~(SPI_CH_CPHA_B | SPI_CH_CPOL_L);
4326126c8e8SSimon Glass
4336126c8e8SSimon Glass	if (mode & SPI_CPHA)
4346126c8e8SSimon Glass		reg |= SPI_CH_CPHA_B;
4356126c8e8SSimon Glass
4366126c8e8SSimon Glass	if (mode & SPI_CPOL)
4376126c8e8SSimon Glass		reg |= SPI_CH_CPOL_L;
4386126c8e8SSimon Glass
4396126c8e8SSimon Glass	writel(reg, &priv->regs->ch_cfg);
4406126c8e8SSimon Glass	priv->mode = mode;
4416126c8e8SSimon Glass	debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
4426126c8e8SSimon Glass
4436126c8e8SSimon Glass	return 0;
4446126c8e8SSimon Glass}
4456126c8e8SSimon Glass
4466126c8e8SSimon Glass
4476126c8e8SSimon Glass13. Implement claim_bus()
4486126c8e8SSimon Glass
4496126c8e8SSimon GlassThis is where a client wants to make use of the bus, so claims it first.
4506126c8e8SSimon GlassAt this point we need to make sure everything is set up ready for data
4516126c8e8SSimon Glasstransfer. Note that this function is wholly internal to the driver - at
4526126c8e8SSimon Glasspresent the SPI uclass never calls it.
4536126c8e8SSimon Glass
4546126c8e8SSimon GlassHere again we look at the old claim function and see some code that is
4556126c8e8SSimon Glassneeded. It is anything unrelated to speed and mode:
4566126c8e8SSimon Glass
4576126c8e8SSimon Glassstatic int exynos_spi_claim_bus(struct udevice *bus)
4586126c8e8SSimon Glass{
4596126c8e8SSimon Glass	struct exynos_spi_priv *priv = dev_get_priv(bus);
4606126c8e8SSimon Glass
4616126c8e8SSimon Glass	exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
4626126c8e8SSimon Glass	spi_flush_fifo(priv->regs);
4636126c8e8SSimon Glass
4646126c8e8SSimon Glass	writel(SPI_FB_DELAY_180, &priv->regs->fb_clk);
4656126c8e8SSimon Glass
4666126c8e8SSimon Glass	return 0;
4676126c8e8SSimon Glass}
4686126c8e8SSimon Glass
4696126c8e8SSimon GlassThe spi_flush_fifo() function is in the removed part of the code, so we
4706126c8e8SSimon Glassneed to expose it again (perhaps with an #endif before it and '#if 0'
4716126c8e8SSimon Glassafter it). It only needs access to priv->regs which is why we have
4726126c8e8SSimon Glasspassed that in:
4736126c8e8SSimon Glass
4746126c8e8SSimon Glass/**
4756126c8e8SSimon Glass * Flush spi tx, rx fifos and reset the SPI controller
4766126c8e8SSimon Glass *
4776126c8e8SSimon Glass * @param regs	Pointer to SPI registers
4786126c8e8SSimon Glass */
4796126c8e8SSimon Glassstatic void spi_flush_fifo(struct exynos_spi *regs)
4806126c8e8SSimon Glass{
4816126c8e8SSimon Glass	clrsetbits_le32(&regs->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
4826126c8e8SSimon Glass	clrbits_le32(&regs->ch_cfg, SPI_CH_RST);
4836126c8e8SSimon Glass	setbits_le32(&regs->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
4846126c8e8SSimon Glass}
4856126c8e8SSimon Glass
4866126c8e8SSimon Glass
4876126c8e8SSimon Glass14. Implement release_bus()
4886126c8e8SSimon Glass
4896126c8e8SSimon GlassThis releases the bus - in our example the old code in spi_release_bus()
4906126c8e8SSimon Glassis a call to spi_flush_fifo, so we add:
4916126c8e8SSimon Glass
4926126c8e8SSimon Glassstatic int exynos_spi_release_bus(struct udevice *bus)
4936126c8e8SSimon Glass{
4946126c8e8SSimon Glass	struct exynos_spi_priv *priv = dev_get_priv(bus);
4956126c8e8SSimon Glass
4966126c8e8SSimon Glass	spi_flush_fifo(priv->regs);
4976126c8e8SSimon Glass
4986126c8e8SSimon Glass	return 0;
4996126c8e8SSimon Glass}
5006126c8e8SSimon Glass
5016126c8e8SSimon Glass
5026126c8e8SSimon Glass15. Implement xfer()
5036126c8e8SSimon Glass
5046126c8e8SSimon GlassThis is the final method that we need to create, and it is where all the
5056126c8e8SSimon Glasswork happens. The method parameters are the same as the old spi_xfer() with
5066126c8e8SSimon Glassthe addition of a 'struct udevice' so conversion is pretty easy. Start
5076126c8e8SSimon Glassby copying the contents of spi_xfer() to your new xfer() method and proceed
5086126c8e8SSimon Glassfrom there.
5096126c8e8SSimon Glass
5106126c8e8SSimon GlassIf (flags & SPI_XFER_BEGIN) is non-zero then xfer() normally calls an
5116126c8e8SSimon Glassactivate function, something like this:
5126126c8e8SSimon Glass
5136126c8e8SSimon Glassvoid spi_cs_activate(struct spi_slave *slave)
5146126c8e8SSimon Glass{
5156126c8e8SSimon Glass	struct exynos_spi_slave *spi_slave = to_exynos_spi(slave);
5166126c8e8SSimon Glass
5176126c8e8SSimon Glass	/* If it's too soon to do another transaction, wait */
5186126c8e8SSimon Glass	if (spi_slave->bus->deactivate_delay_us &&
5196126c8e8SSimon Glass	    spi_slave->last_transaction_us) {
5206126c8e8SSimon Glass		ulong delay_us;		/* The delay completed so far */
5216126c8e8SSimon Glass		delay_us = timer_get_us() - spi_slave->last_transaction_us;
5226126c8e8SSimon Glass		if (delay_us < spi_slave->bus->deactivate_delay_us)
5236126c8e8SSimon Glass			udelay(spi_slave->bus->deactivate_delay_us - delay_us);
5246126c8e8SSimon Glass	}
5256126c8e8SSimon Glass
5266126c8e8SSimon Glass	clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT);
5276126c8e8SSimon Glass	debug("Activate CS, bus %d\n", spi_slave->slave.bus);
5286126c8e8SSimon Glass	spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE;
5296126c8e8SSimon Glass}
5306126c8e8SSimon Glass
5316126c8e8SSimon GlassThe new version looks like this:
5326126c8e8SSimon Glass
5336126c8e8SSimon Glassstatic void spi_cs_activate(struct udevice *dev)
5346126c8e8SSimon Glass{
5356126c8e8SSimon Glass	struct udevice *bus = dev->parent;
5366126c8e8SSimon Glass	struct exynos_spi_platdata *pdata = dev_get_platdata(bus);
5376126c8e8SSimon Glass	struct exynos_spi_priv *priv = dev_get_priv(bus);
5386126c8e8SSimon Glass
5396126c8e8SSimon Glass	/* If it's too soon to do another transaction, wait */
5406126c8e8SSimon Glass	if (pdata->deactivate_delay_us &&
5416126c8e8SSimon Glass	    priv->last_transaction_us) {
5426126c8e8SSimon Glass		ulong delay_us;		/* The delay completed so far */
5436126c8e8SSimon Glass		delay_us = timer_get_us() - priv->last_transaction_us;
5446126c8e8SSimon Glass		if (delay_us < pdata->deactivate_delay_us)
5456126c8e8SSimon Glass			udelay(pdata->deactivate_delay_us - delay_us);
5466126c8e8SSimon Glass	}
5476126c8e8SSimon Glass
5486126c8e8SSimon Glass	clrbits_le32(&priv->regs->cs_reg, SPI_SLAVE_SIG_INACT);
5496126c8e8SSimon Glass	debug("Activate CS, bus '%s'\n", bus->name);
5506126c8e8SSimon Glass	priv->skip_preamble = priv->mode & SPI_PREAMBLE;
5516126c8e8SSimon Glass}
5526126c8e8SSimon Glass
5536126c8e8SSimon GlassAll we have really done here is change the pointers and print the device name
5546126c8e8SSimon Glassinstead of the bus number. Other local static functions can be treated in
5556126c8e8SSimon Glassthe same way.
5566126c8e8SSimon Glass
5576126c8e8SSimon Glass
5586126c8e8SSimon Glass16. Set up the per-child data and child pre-probe function
5596126c8e8SSimon Glass
5606126c8e8SSimon GlassTo minimise the pain and complexity of the SPI subsystem while the driver
5616126c8e8SSimon Glassmodel change-over is in place, struct spi_slave is used to reference a
5626126c8e8SSimon GlassSPI bus slave, even though that slave is actually a struct udevice. In fact
5636126c8e8SSimon Glassstruct spi_slave is the device's child data. We need to make sure this space
5646126c8e8SSimon Glassis available. It is possible to allocate more space that struct spi_slave
5656126c8e8SSimon Glassneeds, but this is the minimum.
5666126c8e8SSimon Glass
5676126c8e8SSimon GlassU_BOOT_DRIVER(exynos_spi) = {
5686126c8e8SSimon Glass...
5696126c8e8SSimon Glass	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
5706126c8e8SSimon Glass}
5716126c8e8SSimon Glass
5726126c8e8SSimon Glass
5736126c8e8SSimon Glass17. Optional: Set up cs_info() if you want it
5746126c8e8SSimon Glass
5756126c8e8SSimon GlassSometimes it is useful to know whether a SPI chip select is valid, but this
5766126c8e8SSimon Glassis not obvious from outside the driver. In this case you can provide a
5776126c8e8SSimon Glassmethod for cs_info() to deal with this. If you don't provide it, then the
5786126c8e8SSimon Glassdevice tree will be used to determine what chip selects are valid.
5796126c8e8SSimon Glass
5806126c8e8SSimon GlassReturn -ENODEV if the supplied chip select is invalid, or 0 if it is valid.
5816126c8e8SSimon GlassIf you don't provide the cs_info() method, -ENODEV is assumed for all
5826126c8e8SSimon Glasschip selects that do not appear in the device tree.
5836126c8e8SSimon Glass
5846126c8e8SSimon Glass
5856126c8e8SSimon Glass18. Test it
5866126c8e8SSimon Glass
5876126c8e8SSimon GlassNow that you have the code written and it compiles, try testing it using
5886126c8e8SSimon Glassthe 'sf test' command. You may need to enable CONFIG_CMD_SF_TEST for your
5896126c8e8SSimon Glassboard.
5906126c8e8SSimon Glass
5916126c8e8SSimon Glass
5926126c8e8SSimon Glass19. Prepare patches and send them to the mailing lists
5936126c8e8SSimon Glass
5946126c8e8SSimon GlassYou can use 'tools/patman/patman' to prepare, check and send patches for
5956126c8e8SSimon Glassyour work. See the README for details.
5962017aaefSSimon Glass
5972017aaefSSimon Glass20. A little note about SPI uclass features:
5982017aaefSSimon Glass
5992017aaefSSimon GlassThe SPI uclass keeps some information about each device 'dev' on the bus:
6002017aaefSSimon Glass
6012017aaefSSimon Glass   struct dm_spi_slave_platdata - this is device_get_parent_platdata(dev)
6022017aaefSSimon Glass		This is where the chip select number is stored, along with
6032017aaefSSimon Glass		the default bus speed and mode. It is automatically read
6042017aaefSSimon Glass		from the device tree in spi_child_post_bind(). It must not
6052017aaefSSimon Glass		be changed at run-time after being set up because platform
6062017aaefSSimon Glass		data is supposed to be immutable at run-time.
6072017aaefSSimon Glass   struct spi_slave - this is device_get_parentdata(dev)
6082017aaefSSimon Glass		Already mentioned above. It holds run-time information about
6092017aaefSSimon Glass		the device.
6102017aaefSSimon Glass
6112017aaefSSimon GlassThere are also some SPI uclass methods that get called behind the scenes:
6122017aaefSSimon Glass
6132017aaefSSimon Glass   spi_post_bind() - called when a new bus is bound
6142017aaefSSimon Glass		This scans the device tree for devices on the bus, and binds
6152017aaefSSimon Glass		each one. This in turn causes spi_child_post_bind() to be
6162017aaefSSimon Glass		called for each, which reads the device tree information
6172017aaefSSimon Glass		into the parent (per-child) platform data.
6182017aaefSSimon Glass   spi_child_post_bind() - called when a new child is bound
6192017aaefSSimon Glass		As mentioned above this reads the device tree information
6202017aaefSSimon Glass		into the per-child platform data
6212017aaefSSimon Glass   spi_child_pre_probe() - called before a new child is probed
6222017aaefSSimon Glass		This sets up the mode and speed in struct spi_slave by
6232017aaefSSimon Glass		copying it from the parent's platform data for this child.
6242017aaefSSimon Glass		It also sets the 'dev' pointer, needed to permit passing
6252017aaefSSimon Glass		'struct spi_slave' around the place without needing a
6262017aaefSSimon Glass		separate 'struct udevice' pointer.
6272017aaefSSimon Glass
6282017aaefSSimon GlassThe above housekeeping makes it easier to write your SPI driver.
629