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(®s->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, ®s->ch_cfg); 3896126c8e8SSimon Glass writel(SPI_FB_DELAY_180, ®s->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(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST); 4826126c8e8SSimon Glass clrbits_le32(®s->ch_cfg, SPI_CH_RST); 4836126c8e8SSimon Glass setbits_le32(®s->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