18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instruments. 48c2ecf20Sopenharmony_ci * Copyright (C) 2010 EF Johnson Technologies 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 168c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 208c2ecf20Sopenharmony_ci#include <linux/spi/spi_bitbang.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/platform_data/spi-davinci.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define CS_DEFAULT 0xFF 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define SPIFMT_PHASE_MASK BIT(16) 288c2ecf20Sopenharmony_ci#define SPIFMT_POLARITY_MASK BIT(17) 298c2ecf20Sopenharmony_ci#define SPIFMT_DISTIMER_MASK BIT(18) 308c2ecf20Sopenharmony_ci#define SPIFMT_SHIFTDIR_MASK BIT(20) 318c2ecf20Sopenharmony_ci#define SPIFMT_WAITENA_MASK BIT(21) 328c2ecf20Sopenharmony_ci#define SPIFMT_PARITYENA_MASK BIT(22) 338c2ecf20Sopenharmony_ci#define SPIFMT_ODD_PARITY_MASK BIT(23) 348c2ecf20Sopenharmony_ci#define SPIFMT_WDELAY_MASK 0x3f000000u 358c2ecf20Sopenharmony_ci#define SPIFMT_WDELAY_SHIFT 24 368c2ecf20Sopenharmony_ci#define SPIFMT_PRESCALE_SHIFT 8 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* SPIPC0 */ 398c2ecf20Sopenharmony_ci#define SPIPC0_DIFUN_MASK BIT(11) /* MISO */ 408c2ecf20Sopenharmony_ci#define SPIPC0_DOFUN_MASK BIT(10) /* MOSI */ 418c2ecf20Sopenharmony_ci#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */ 428c2ecf20Sopenharmony_ci#define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define SPIINT_MASKALL 0x0101035F 458c2ecf20Sopenharmony_ci#define SPIINT_MASKINT 0x0000015F 468c2ecf20Sopenharmony_ci#define SPI_INTLVL_1 0x000001FF 478c2ecf20Sopenharmony_ci#define SPI_INTLVL_0 0x00000000 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* SPIDAT1 (upper 16 bit defines) */ 508c2ecf20Sopenharmony_ci#define SPIDAT1_CSHOLD_MASK BIT(12) 518c2ecf20Sopenharmony_ci#define SPIDAT1_WDEL BIT(10) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* SPIGCR1 */ 548c2ecf20Sopenharmony_ci#define SPIGCR1_CLKMOD_MASK BIT(1) 558c2ecf20Sopenharmony_ci#define SPIGCR1_MASTER_MASK BIT(0) 568c2ecf20Sopenharmony_ci#define SPIGCR1_POWERDOWN_MASK BIT(8) 578c2ecf20Sopenharmony_ci#define SPIGCR1_LOOPBACK_MASK BIT(16) 588c2ecf20Sopenharmony_ci#define SPIGCR1_SPIENA_MASK BIT(24) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* SPIBUF */ 618c2ecf20Sopenharmony_ci#define SPIBUF_TXFULL_MASK BIT(29) 628c2ecf20Sopenharmony_ci#define SPIBUF_RXEMPTY_MASK BIT(31) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* SPIDELAY */ 658c2ecf20Sopenharmony_ci#define SPIDELAY_C2TDELAY_SHIFT 24 668c2ecf20Sopenharmony_ci#define SPIDELAY_C2TDELAY_MASK (0xFF << SPIDELAY_C2TDELAY_SHIFT) 678c2ecf20Sopenharmony_ci#define SPIDELAY_T2CDELAY_SHIFT 16 688c2ecf20Sopenharmony_ci#define SPIDELAY_T2CDELAY_MASK (0xFF << SPIDELAY_T2CDELAY_SHIFT) 698c2ecf20Sopenharmony_ci#define SPIDELAY_T2EDELAY_SHIFT 8 708c2ecf20Sopenharmony_ci#define SPIDELAY_T2EDELAY_MASK (0xFF << SPIDELAY_T2EDELAY_SHIFT) 718c2ecf20Sopenharmony_ci#define SPIDELAY_C2EDELAY_SHIFT 0 728c2ecf20Sopenharmony_ci#define SPIDELAY_C2EDELAY_MASK 0xFF 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* Error Masks */ 758c2ecf20Sopenharmony_ci#define SPIFLG_DLEN_ERR_MASK BIT(0) 768c2ecf20Sopenharmony_ci#define SPIFLG_TIMEOUT_MASK BIT(1) 778c2ecf20Sopenharmony_ci#define SPIFLG_PARERR_MASK BIT(2) 788c2ecf20Sopenharmony_ci#define SPIFLG_DESYNC_MASK BIT(3) 798c2ecf20Sopenharmony_ci#define SPIFLG_BITERR_MASK BIT(4) 808c2ecf20Sopenharmony_ci#define SPIFLG_OVRRUN_MASK BIT(6) 818c2ecf20Sopenharmony_ci#define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24) 828c2ecf20Sopenharmony_ci#define SPIFLG_ERROR_MASK (SPIFLG_DLEN_ERR_MASK \ 838c2ecf20Sopenharmony_ci | SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \ 848c2ecf20Sopenharmony_ci | SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \ 858c2ecf20Sopenharmony_ci | SPIFLG_OVRRUN_MASK) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define SPIINT_DMA_REQ_EN BIT(16) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* SPI Controller registers */ 908c2ecf20Sopenharmony_ci#define SPIGCR0 0x00 918c2ecf20Sopenharmony_ci#define SPIGCR1 0x04 928c2ecf20Sopenharmony_ci#define SPIINT 0x08 938c2ecf20Sopenharmony_ci#define SPILVL 0x0c 948c2ecf20Sopenharmony_ci#define SPIFLG 0x10 958c2ecf20Sopenharmony_ci#define SPIPC0 0x14 968c2ecf20Sopenharmony_ci#define SPIDAT1 0x3c 978c2ecf20Sopenharmony_ci#define SPIBUF 0x40 988c2ecf20Sopenharmony_ci#define SPIDELAY 0x48 998c2ecf20Sopenharmony_ci#define SPIDEF 0x4c 1008c2ecf20Sopenharmony_ci#define SPIFMT0 0x50 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define DMA_MIN_BYTES 16 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* SPI Controller driver's private data. */ 1058c2ecf20Sopenharmony_cistruct davinci_spi { 1068c2ecf20Sopenharmony_ci struct spi_bitbang bitbang; 1078c2ecf20Sopenharmony_ci struct clk *clk; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci u8 version; 1108c2ecf20Sopenharmony_ci resource_size_t pbase; 1118c2ecf20Sopenharmony_ci void __iomem *base; 1128c2ecf20Sopenharmony_ci u32 irq; 1138c2ecf20Sopenharmony_ci struct completion done; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci const void *tx; 1168c2ecf20Sopenharmony_ci void *rx; 1178c2ecf20Sopenharmony_ci int rcount; 1188c2ecf20Sopenharmony_ci int wcount; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci struct dma_chan *dma_rx; 1218c2ecf20Sopenharmony_ci struct dma_chan *dma_tx; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci struct davinci_spi_platform_data pdata; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci void (*get_rx)(u32 rx_data, struct davinci_spi *); 1268c2ecf20Sopenharmony_ci u32 (*get_tx)(struct davinci_spi *); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci u8 *bytes_per_word; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci u8 prescaler_limit; 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic struct davinci_spi_config davinci_spi_default_cfg; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *dspi) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci if (dspi->rx) { 1388c2ecf20Sopenharmony_ci u8 *rx = dspi->rx; 1398c2ecf20Sopenharmony_ci *rx++ = (u8)data; 1408c2ecf20Sopenharmony_ci dspi->rx = rx; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *dspi) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci if (dspi->rx) { 1478c2ecf20Sopenharmony_ci u16 *rx = dspi->rx; 1488c2ecf20Sopenharmony_ci *rx++ = (u16)data; 1498c2ecf20Sopenharmony_ci dspi->rx = rx; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci u32 data = 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (dspi->tx) { 1588c2ecf20Sopenharmony_ci const u8 *tx = dspi->tx; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci data = *tx++; 1618c2ecf20Sopenharmony_ci dspi->tx = tx; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci return data; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic u32 davinci_spi_tx_buf_u16(struct davinci_spi *dspi) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci u32 data = 0; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (dspi->tx) { 1718c2ecf20Sopenharmony_ci const u16 *tx = dspi->tx; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci data = *tx++; 1748c2ecf20Sopenharmony_ci dspi->tx = tx; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci return data; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic inline void set_io_bits(void __iomem *addr, u32 bits) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci u32 v = ioread32(addr); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci v |= bits; 1848c2ecf20Sopenharmony_ci iowrite32(v, addr); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic inline void clear_io_bits(void __iomem *addr, u32 bits) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci u32 v = ioread32(addr); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci v &= ~bits; 1928c2ecf20Sopenharmony_ci iowrite32(v, addr); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* 1968c2ecf20Sopenharmony_ci * Interface to control the chip select signal 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_cistatic void davinci_spi_chipselect(struct spi_device *spi, int value) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct davinci_spi *dspi; 2018c2ecf20Sopenharmony_ci struct davinci_spi_config *spicfg = spi->controller_data; 2028c2ecf20Sopenharmony_ci u8 chip_sel = spi->chip_select; 2038c2ecf20Sopenharmony_ci u16 spidat1 = CS_DEFAULT; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci dspi = spi_master_get_devdata(spi->master); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* program delay transfers if tx_delay is non zero */ 2088c2ecf20Sopenharmony_ci if (spicfg && spicfg->wdelay) 2098c2ecf20Sopenharmony_ci spidat1 |= SPIDAT1_WDEL; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* 2128c2ecf20Sopenharmony_ci * Board specific chip select logic decides the polarity and cs 2138c2ecf20Sopenharmony_ci * line for the controller 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci if (spi->cs_gpiod) { 2168c2ecf20Sopenharmony_ci if (value == BITBANG_CS_ACTIVE) 2178c2ecf20Sopenharmony_ci gpiod_set_value(spi->cs_gpiod, 1); 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci gpiod_set_value(spi->cs_gpiod, 0); 2208c2ecf20Sopenharmony_ci } else { 2218c2ecf20Sopenharmony_ci if (value == BITBANG_CS_ACTIVE) { 2228c2ecf20Sopenharmony_ci if (!(spi->mode & SPI_CS_WORD)) 2238c2ecf20Sopenharmony_ci spidat1 |= SPIDAT1_CSHOLD_MASK; 2248c2ecf20Sopenharmony_ci spidat1 &= ~(0x1 << chip_sel); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci iowrite16(spidat1, dspi->base + SPIDAT1 + 2); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/** 2328c2ecf20Sopenharmony_ci * davinci_spi_get_prescale - Calculates the correct prescale value 2338c2ecf20Sopenharmony_ci * @dspi: the controller data 2348c2ecf20Sopenharmony_ci * @max_speed_hz: the maximum rate the SPI clock can run at 2358c2ecf20Sopenharmony_ci * 2368c2ecf20Sopenharmony_ci * This function calculates the prescale value that generates a clock rate 2378c2ecf20Sopenharmony_ci * less than or equal to the specified maximum. 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * Returns: calculated prescale value for easy programming into SPI registers 2408c2ecf20Sopenharmony_ci * or negative error number if valid prescalar cannot be updated. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_cistatic inline int davinci_spi_get_prescale(struct davinci_spi *dspi, 2438c2ecf20Sopenharmony_ci u32 max_speed_hz) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int ret; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Subtract 1 to match what will be programmed into SPI register. */ 2488c2ecf20Sopenharmony_ci ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz) - 1; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (ret < dspi->prescaler_limit || ret > 255) 2518c2ecf20Sopenharmony_ci return -EINVAL; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return ret; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/** 2578c2ecf20Sopenharmony_ci * davinci_spi_setup_transfer - This functions will determine transfer method 2588c2ecf20Sopenharmony_ci * @spi: spi device on which data transfer to be done 2598c2ecf20Sopenharmony_ci * @t: spi transfer in which transfer info is filled 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * This function determines data transfer method (8/16/32 bit transfer). 2628c2ecf20Sopenharmony_ci * It will also set the SPI Clock Control register according to 2638c2ecf20Sopenharmony_ci * SPI slave device freq. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cistatic int davinci_spi_setup_transfer(struct spi_device *spi, 2668c2ecf20Sopenharmony_ci struct spi_transfer *t) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci struct davinci_spi *dspi; 2708c2ecf20Sopenharmony_ci struct davinci_spi_config *spicfg; 2718c2ecf20Sopenharmony_ci u8 bits_per_word = 0; 2728c2ecf20Sopenharmony_ci u32 hz = 0, spifmt = 0; 2738c2ecf20Sopenharmony_ci int prescale; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci dspi = spi_master_get_devdata(spi->master); 2768c2ecf20Sopenharmony_ci spicfg = spi->controller_data; 2778c2ecf20Sopenharmony_ci if (!spicfg) 2788c2ecf20Sopenharmony_ci spicfg = &davinci_spi_default_cfg; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (t) { 2818c2ecf20Sopenharmony_ci bits_per_word = t->bits_per_word; 2828c2ecf20Sopenharmony_ci hz = t->speed_hz; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* if bits_per_word is not set then set it default */ 2868c2ecf20Sopenharmony_ci if (!bits_per_word) 2878c2ecf20Sopenharmony_ci bits_per_word = spi->bits_per_word; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* 2908c2ecf20Sopenharmony_ci * Assign function pointer to appropriate transfer method 2918c2ecf20Sopenharmony_ci * 8bit, 16bit or 32bit transfer 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (bits_per_word <= 8) { 2948c2ecf20Sopenharmony_ci dspi->get_rx = davinci_spi_rx_buf_u8; 2958c2ecf20Sopenharmony_ci dspi->get_tx = davinci_spi_tx_buf_u8; 2968c2ecf20Sopenharmony_ci dspi->bytes_per_word[spi->chip_select] = 1; 2978c2ecf20Sopenharmony_ci } else { 2988c2ecf20Sopenharmony_ci dspi->get_rx = davinci_spi_rx_buf_u16; 2998c2ecf20Sopenharmony_ci dspi->get_tx = davinci_spi_tx_buf_u16; 3008c2ecf20Sopenharmony_ci dspi->bytes_per_word[spi->chip_select] = 2; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (!hz) 3048c2ecf20Sopenharmony_ci hz = spi->max_speed_hz; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* Set up SPIFMTn register, unique to this chipselect. */ 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci prescale = davinci_spi_get_prescale(dspi, hz); 3098c2ecf20Sopenharmony_ci if (prescale < 0) 3108c2ecf20Sopenharmony_ci return prescale; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci spifmt = (prescale << SPIFMT_PRESCALE_SHIFT) | (bits_per_word & 0x1f); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (spi->mode & SPI_LSB_FIRST) 3158c2ecf20Sopenharmony_ci spifmt |= SPIFMT_SHIFTDIR_MASK; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPOL) 3188c2ecf20Sopenharmony_ci spifmt |= SPIFMT_POLARITY_MASK; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!(spi->mode & SPI_CPHA)) 3218c2ecf20Sopenharmony_ci spifmt |= SPIFMT_PHASE_MASK; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* 3248c2ecf20Sopenharmony_ci * Assume wdelay is used only on SPI peripherals that has this field 3258c2ecf20Sopenharmony_ci * in SPIFMTn register and when it's configured from board file or DT. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_ci if (spicfg->wdelay) 3288c2ecf20Sopenharmony_ci spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT) 3298c2ecf20Sopenharmony_ci & SPIFMT_WDELAY_MASK); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* 3328c2ecf20Sopenharmony_ci * Version 1 hardware supports two basic SPI modes: 3338c2ecf20Sopenharmony_ci * - Standard SPI mode uses 4 pins, with chipselect 3348c2ecf20Sopenharmony_ci * - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS) 3358c2ecf20Sopenharmony_ci * (distinct from SPI_3WIRE, with just one data wire; 3368c2ecf20Sopenharmony_ci * or similar variants without MOSI or without MISO) 3378c2ecf20Sopenharmony_ci * 3388c2ecf20Sopenharmony_ci * Version 2 hardware supports an optional handshaking signal, 3398c2ecf20Sopenharmony_ci * so it can support two more modes: 3408c2ecf20Sopenharmony_ci * - 5 pin SPI variant is standard SPI plus SPI_READY 3418c2ecf20Sopenharmony_ci * - 4 pin with enable is (SPI_READY | SPI_NO_CS) 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (dspi->version == SPI_VERSION_2) { 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci u32 delay = 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (spicfg->odd_parity) 3498c2ecf20Sopenharmony_ci spifmt |= SPIFMT_ODD_PARITY_MASK; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (spicfg->parity_enable) 3528c2ecf20Sopenharmony_ci spifmt |= SPIFMT_PARITYENA_MASK; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (spicfg->timer_disable) { 3558c2ecf20Sopenharmony_ci spifmt |= SPIFMT_DISTIMER_MASK; 3568c2ecf20Sopenharmony_ci } else { 3578c2ecf20Sopenharmony_ci delay |= (spicfg->c2tdelay << SPIDELAY_C2TDELAY_SHIFT) 3588c2ecf20Sopenharmony_ci & SPIDELAY_C2TDELAY_MASK; 3598c2ecf20Sopenharmony_ci delay |= (spicfg->t2cdelay << SPIDELAY_T2CDELAY_SHIFT) 3608c2ecf20Sopenharmony_ci & SPIDELAY_T2CDELAY_MASK; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (spi->mode & SPI_READY) { 3648c2ecf20Sopenharmony_ci spifmt |= SPIFMT_WAITENA_MASK; 3658c2ecf20Sopenharmony_ci delay |= (spicfg->t2edelay << SPIDELAY_T2EDELAY_SHIFT) 3668c2ecf20Sopenharmony_ci & SPIDELAY_T2EDELAY_MASK; 3678c2ecf20Sopenharmony_ci delay |= (spicfg->c2edelay << SPIDELAY_C2EDELAY_SHIFT) 3688c2ecf20Sopenharmony_ci & SPIDELAY_C2EDELAY_MASK; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci iowrite32(delay, dspi->base + SPIDELAY); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci iowrite32(spifmt, dspi->base + SPIFMT0); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int davinci_spi_of_setup(struct spi_device *spi) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct davinci_spi_config *spicfg = spi->controller_data; 3828c2ecf20Sopenharmony_ci struct device_node *np = spi->dev.of_node; 3838c2ecf20Sopenharmony_ci struct davinci_spi *dspi = spi_master_get_devdata(spi->master); 3848c2ecf20Sopenharmony_ci u32 prop; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (spicfg == NULL && np) { 3878c2ecf20Sopenharmony_ci spicfg = kzalloc(sizeof(*spicfg), GFP_KERNEL); 3888c2ecf20Sopenharmony_ci if (!spicfg) 3898c2ecf20Sopenharmony_ci return -ENOMEM; 3908c2ecf20Sopenharmony_ci *spicfg = davinci_spi_default_cfg; 3918c2ecf20Sopenharmony_ci /* override with dt configured values */ 3928c2ecf20Sopenharmony_ci if (!of_property_read_u32(np, "ti,spi-wdelay", &prop)) 3938c2ecf20Sopenharmony_ci spicfg->wdelay = (u8)prop; 3948c2ecf20Sopenharmony_ci spi->controller_data = spicfg; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (dspi->dma_rx && dspi->dma_tx) 3978c2ecf20Sopenharmony_ci spicfg->io_type = SPI_IO_TYPE_DMA; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/** 4048c2ecf20Sopenharmony_ci * davinci_spi_setup - This functions will set default transfer method 4058c2ecf20Sopenharmony_ci * @spi: spi device on which data transfer to be done 4068c2ecf20Sopenharmony_ci * 4078c2ecf20Sopenharmony_ci * This functions sets the default transfer method. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_cistatic int davinci_spi_setup(struct spi_device *spi) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct davinci_spi *dspi; 4128c2ecf20Sopenharmony_ci struct device_node *np = spi->dev.of_node; 4138c2ecf20Sopenharmony_ci bool internal_cs = true; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci dspi = spi_master_get_devdata(spi->master); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (!(spi->mode & SPI_NO_CS)) { 4188c2ecf20Sopenharmony_ci if (np && spi->cs_gpiod) 4198c2ecf20Sopenharmony_ci internal_cs = false; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (internal_cs) 4228c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select); 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (spi->mode & SPI_READY) 4268c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (spi->mode & SPI_LOOP) 4298c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK); 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return davinci_spi_of_setup(spi); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic void davinci_spi_cleanup(struct spi_device *spi) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct davinci_spi_config *spicfg = spi->controller_data; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci spi->controller_data = NULL; 4418c2ecf20Sopenharmony_ci if (spi->dev.of_node) 4428c2ecf20Sopenharmony_ci kfree(spicfg); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic bool davinci_spi_can_dma(struct spi_master *master, 4468c2ecf20Sopenharmony_ci struct spi_device *spi, 4478c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct davinci_spi_config *spicfg = spi->controller_data; 4508c2ecf20Sopenharmony_ci bool can_dma = false; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (spicfg) 4538c2ecf20Sopenharmony_ci can_dma = (spicfg->io_type == SPI_IO_TYPE_DMA) && 4548c2ecf20Sopenharmony_ci (xfer->len >= DMA_MIN_BYTES) && 4558c2ecf20Sopenharmony_ci !is_vmalloc_addr(xfer->rx_buf) && 4568c2ecf20Sopenharmony_ci !is_vmalloc_addr(xfer->tx_buf); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return can_dma; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int davinci_spi_check_error(struct davinci_spi *dspi, int int_status) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct device *sdev = dspi->bitbang.master->dev.parent; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (int_status & SPIFLG_TIMEOUT_MASK) { 4668c2ecf20Sopenharmony_ci dev_err(sdev, "SPI Time-out Error\n"); 4678c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci if (int_status & SPIFLG_DESYNC_MASK) { 4708c2ecf20Sopenharmony_ci dev_err(sdev, "SPI Desynchronization Error\n"); 4718c2ecf20Sopenharmony_ci return -EIO; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci if (int_status & SPIFLG_BITERR_MASK) { 4748c2ecf20Sopenharmony_ci dev_err(sdev, "SPI Bit error\n"); 4758c2ecf20Sopenharmony_ci return -EIO; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (dspi->version == SPI_VERSION_2) { 4798c2ecf20Sopenharmony_ci if (int_status & SPIFLG_DLEN_ERR_MASK) { 4808c2ecf20Sopenharmony_ci dev_err(sdev, "SPI Data Length Error\n"); 4818c2ecf20Sopenharmony_ci return -EIO; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci if (int_status & SPIFLG_PARERR_MASK) { 4848c2ecf20Sopenharmony_ci dev_err(sdev, "SPI Parity Error\n"); 4858c2ecf20Sopenharmony_ci return -EIO; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci if (int_status & SPIFLG_OVRRUN_MASK) { 4888c2ecf20Sopenharmony_ci dev_err(sdev, "SPI Data Overrun error\n"); 4898c2ecf20Sopenharmony_ci return -EIO; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) { 4928c2ecf20Sopenharmony_ci dev_err(sdev, "SPI Buffer Init Active\n"); 4938c2ecf20Sopenharmony_ci return -EBUSY; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci/** 5018c2ecf20Sopenharmony_ci * davinci_spi_process_events - check for and handle any SPI controller events 5028c2ecf20Sopenharmony_ci * @dspi: the controller data 5038c2ecf20Sopenharmony_ci * 5048c2ecf20Sopenharmony_ci * This function will check the SPIFLG register and handle any events that are 5058c2ecf20Sopenharmony_ci * detected there 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_cistatic int davinci_spi_process_events(struct davinci_spi *dspi) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci u32 buf, status, errors = 0, spidat1; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci buf = ioread32(dspi->base + SPIBUF); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (dspi->rcount > 0 && !(buf & SPIBUF_RXEMPTY_MASK)) { 5148c2ecf20Sopenharmony_ci dspi->get_rx(buf & 0xFFFF, dspi); 5158c2ecf20Sopenharmony_ci dspi->rcount--; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci status = ioread32(dspi->base + SPIFLG); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (unlikely(status & SPIFLG_ERROR_MASK)) { 5218c2ecf20Sopenharmony_ci errors = status & SPIFLG_ERROR_MASK; 5228c2ecf20Sopenharmony_ci goto out; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (dspi->wcount > 0 && !(buf & SPIBUF_TXFULL_MASK)) { 5268c2ecf20Sopenharmony_ci spidat1 = ioread32(dspi->base + SPIDAT1); 5278c2ecf20Sopenharmony_ci dspi->wcount--; 5288c2ecf20Sopenharmony_ci spidat1 &= ~0xFFFF; 5298c2ecf20Sopenharmony_ci spidat1 |= 0xFFFF & dspi->get_tx(dspi); 5308c2ecf20Sopenharmony_ci iowrite32(spidat1, dspi->base + SPIDAT1); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ciout: 5348c2ecf20Sopenharmony_ci return errors; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void davinci_spi_dma_rx_callback(void *data) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct davinci_spi *dspi = (struct davinci_spi *)data; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci dspi->rcount = 0; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (!dspi->wcount && !dspi->rcount) 5448c2ecf20Sopenharmony_ci complete(&dspi->done); 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic void davinci_spi_dma_tx_callback(void *data) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct davinci_spi *dspi = (struct davinci_spi *)data; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci dspi->wcount = 0; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (!dspi->wcount && !dspi->rcount) 5548c2ecf20Sopenharmony_ci complete(&dspi->done); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * davinci_spi_bufs - functions which will handle transfer data 5598c2ecf20Sopenharmony_ci * @spi: spi device on which data transfer to be done 5608c2ecf20Sopenharmony_ci * @t: spi transfer in which transfer info is filled 5618c2ecf20Sopenharmony_ci * 5628c2ecf20Sopenharmony_ci * This function will put data to be transferred into data register 5638c2ecf20Sopenharmony_ci * of SPI controller and then wait until the completion will be marked 5648c2ecf20Sopenharmony_ci * by the IRQ Handler. 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_cistatic int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct davinci_spi *dspi; 5698c2ecf20Sopenharmony_ci int data_type, ret = -ENOMEM; 5708c2ecf20Sopenharmony_ci u32 tx_data, spidat1; 5718c2ecf20Sopenharmony_ci u32 errors = 0; 5728c2ecf20Sopenharmony_ci struct davinci_spi_config *spicfg; 5738c2ecf20Sopenharmony_ci struct davinci_spi_platform_data *pdata; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci dspi = spi_master_get_devdata(spi->master); 5768c2ecf20Sopenharmony_ci pdata = &dspi->pdata; 5778c2ecf20Sopenharmony_ci spicfg = (struct davinci_spi_config *)spi->controller_data; 5788c2ecf20Sopenharmony_ci if (!spicfg) 5798c2ecf20Sopenharmony_ci spicfg = &davinci_spi_default_cfg; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* convert len to words based on bits_per_word */ 5828c2ecf20Sopenharmony_ci data_type = dspi->bytes_per_word[spi->chip_select]; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci dspi->tx = t->tx_buf; 5858c2ecf20Sopenharmony_ci dspi->rx = t->rx_buf; 5868c2ecf20Sopenharmony_ci dspi->wcount = t->len / data_type; 5878c2ecf20Sopenharmony_ci dspi->rcount = dspi->wcount; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci spidat1 = ioread32(dspi->base + SPIDAT1); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK); 5928c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci reinit_completion(&dspi->done); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (!davinci_spi_can_dma(spi->master, spi, t)) { 5978c2ecf20Sopenharmony_ci if (spicfg->io_type != SPI_IO_TYPE_POLL) 5988c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT); 5998c2ecf20Sopenharmony_ci /* start the transfer */ 6008c2ecf20Sopenharmony_ci dspi->wcount--; 6018c2ecf20Sopenharmony_ci tx_data = dspi->get_tx(dspi); 6028c2ecf20Sopenharmony_ci spidat1 &= 0xFFFF0000; 6038c2ecf20Sopenharmony_ci spidat1 |= tx_data & 0xFFFF; 6048c2ecf20Sopenharmony_ci iowrite32(spidat1, dspi->base + SPIDAT1); 6058c2ecf20Sopenharmony_ci } else { 6068c2ecf20Sopenharmony_ci struct dma_slave_config dma_rx_conf = { 6078c2ecf20Sopenharmony_ci .direction = DMA_DEV_TO_MEM, 6088c2ecf20Sopenharmony_ci .src_addr = (unsigned long)dspi->pbase + SPIBUF, 6098c2ecf20Sopenharmony_ci .src_addr_width = data_type, 6108c2ecf20Sopenharmony_ci .src_maxburst = 1, 6118c2ecf20Sopenharmony_ci }; 6128c2ecf20Sopenharmony_ci struct dma_slave_config dma_tx_conf = { 6138c2ecf20Sopenharmony_ci .direction = DMA_MEM_TO_DEV, 6148c2ecf20Sopenharmony_ci .dst_addr = (unsigned long)dspi->pbase + SPIDAT1, 6158c2ecf20Sopenharmony_ci .dst_addr_width = data_type, 6168c2ecf20Sopenharmony_ci .dst_maxburst = 1, 6178c2ecf20Sopenharmony_ci }; 6188c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc; 6198c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *txdesc; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci dmaengine_slave_config(dspi->dma_rx, &dma_rx_conf); 6228c2ecf20Sopenharmony_ci dmaengine_slave_config(dspi->dma_tx, &dma_tx_conf); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg(dspi->dma_rx, 6258c2ecf20Sopenharmony_ci t->rx_sg.sgl, t->rx_sg.nents, DMA_DEV_TO_MEM, 6268c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 6278c2ecf20Sopenharmony_ci if (!rxdesc) 6288c2ecf20Sopenharmony_ci goto err_desc; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (!t->tx_buf) { 6318c2ecf20Sopenharmony_ci /* To avoid errors when doing rx-only transfers with 6328c2ecf20Sopenharmony_ci * many SG entries (> 20), use the rx buffer as the 6338c2ecf20Sopenharmony_ci * dummy tx buffer so that dma reloads are done at the 6348c2ecf20Sopenharmony_ci * same time for rx and tx. 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci t->tx_sg.sgl = t->rx_sg.sgl; 6378c2ecf20Sopenharmony_ci t->tx_sg.nents = t->rx_sg.nents; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci txdesc = dmaengine_prep_slave_sg(dspi->dma_tx, 6418c2ecf20Sopenharmony_ci t->tx_sg.sgl, t->tx_sg.nents, DMA_MEM_TO_DEV, 6428c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 6438c2ecf20Sopenharmony_ci if (!txdesc) 6448c2ecf20Sopenharmony_ci goto err_desc; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci rxdesc->callback = davinci_spi_dma_rx_callback; 6478c2ecf20Sopenharmony_ci rxdesc->callback_param = (void *)dspi; 6488c2ecf20Sopenharmony_ci txdesc->callback = davinci_spi_dma_tx_callback; 6498c2ecf20Sopenharmony_ci txdesc->callback_param = (void *)dspi; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (pdata->cshold_bug) 6528c2ecf20Sopenharmony_ci iowrite16(spidat1 >> 16, dspi->base + SPIDAT1 + 2); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci dmaengine_submit(rxdesc); 6558c2ecf20Sopenharmony_ci dmaengine_submit(txdesc); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci dma_async_issue_pending(dspi->dma_rx); 6588c2ecf20Sopenharmony_ci dma_async_issue_pending(dspi->dma_tx); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Wait for the transfer to complete */ 6648c2ecf20Sopenharmony_ci if (spicfg->io_type != SPI_IO_TYPE_POLL) { 6658c2ecf20Sopenharmony_ci if (wait_for_completion_timeout(&dspi->done, HZ) == 0) 6668c2ecf20Sopenharmony_ci errors = SPIFLG_TIMEOUT_MASK; 6678c2ecf20Sopenharmony_ci } else { 6688c2ecf20Sopenharmony_ci while (dspi->rcount > 0 || dspi->wcount > 0) { 6698c2ecf20Sopenharmony_ci errors = davinci_spi_process_events(dspi); 6708c2ecf20Sopenharmony_ci if (errors) 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci cpu_relax(); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL); 6778c2ecf20Sopenharmony_ci if (davinci_spi_can_dma(spi->master, spi, t)) 6788c2ecf20Sopenharmony_ci clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK); 6818c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* 6848c2ecf20Sopenharmony_ci * Check for bit error, desync error,parity error,timeout error and 6858c2ecf20Sopenharmony_ci * receive overflow errors 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_ci if (errors) { 6888c2ecf20Sopenharmony_ci ret = davinci_spi_check_error(dspi, errors); 6898c2ecf20Sopenharmony_ci WARN(!ret, "%s: error reported but no error found!\n", 6908c2ecf20Sopenharmony_ci dev_name(&spi->dev)); 6918c2ecf20Sopenharmony_ci return ret; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (dspi->rcount != 0 || dspi->wcount != 0) { 6958c2ecf20Sopenharmony_ci dev_err(&spi->dev, "SPI data transfer error\n"); 6968c2ecf20Sopenharmony_ci return -EIO; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return t->len; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cierr_desc: 7028c2ecf20Sopenharmony_ci return ret; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/** 7068c2ecf20Sopenharmony_ci * dummy_thread_fn - dummy thread function 7078c2ecf20Sopenharmony_ci * @irq: IRQ number for this SPI Master 7088c2ecf20Sopenharmony_ci * @data: structure for SPI Master controller davinci_spi 7098c2ecf20Sopenharmony_ci * 7108c2ecf20Sopenharmony_ci * This is to satisfy the request_threaded_irq() API so that the irq 7118c2ecf20Sopenharmony_ci * handler is called in interrupt context. 7128c2ecf20Sopenharmony_ci */ 7138c2ecf20Sopenharmony_cistatic irqreturn_t dummy_thread_fn(s32 irq, void *data) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci/** 7198c2ecf20Sopenharmony_ci * davinci_spi_irq - Interrupt handler for SPI Master Controller 7208c2ecf20Sopenharmony_ci * @irq: IRQ number for this SPI Master 7218c2ecf20Sopenharmony_ci * @data: structure for SPI Master controller davinci_spi 7228c2ecf20Sopenharmony_ci * 7238c2ecf20Sopenharmony_ci * ISR will determine that interrupt arrives either for READ or WRITE command. 7248c2ecf20Sopenharmony_ci * According to command it will do the appropriate action. It will check 7258c2ecf20Sopenharmony_ci * transfer length and if it is not zero then dispatch transfer command again. 7268c2ecf20Sopenharmony_ci * If transfer length is zero then it will indicate the COMPLETION so that 7278c2ecf20Sopenharmony_ci * davinci_spi_bufs function can go ahead. 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_cistatic irqreturn_t davinci_spi_irq(s32 irq, void *data) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct davinci_spi *dspi = data; 7328c2ecf20Sopenharmony_ci int status; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci status = davinci_spi_process_events(dspi); 7358c2ecf20Sopenharmony_ci if (unlikely(status != 0)) 7368c2ecf20Sopenharmony_ci clear_io_bits(dspi->base + SPIINT, SPIINT_MASKINT); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if ((!dspi->rcount && !dspi->wcount) || status) 7398c2ecf20Sopenharmony_ci complete(&dspi->done); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic int davinci_spi_request_dma(struct davinci_spi *dspi) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct device *sdev = dspi->bitbang.master->dev.parent; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci dspi->dma_rx = dma_request_chan(sdev, "rx"); 7498c2ecf20Sopenharmony_ci if (IS_ERR(dspi->dma_rx)) 7508c2ecf20Sopenharmony_ci return PTR_ERR(dspi->dma_rx); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci dspi->dma_tx = dma_request_chan(sdev, "tx"); 7538c2ecf20Sopenharmony_ci if (IS_ERR(dspi->dma_tx)) { 7548c2ecf20Sopenharmony_ci dma_release_channel(dspi->dma_rx); 7558c2ecf20Sopenharmony_ci return PTR_ERR(dspi->dma_tx); 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci return 0; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci/* OF SPI data structure */ 7648c2ecf20Sopenharmony_cistruct davinci_spi_of_data { 7658c2ecf20Sopenharmony_ci u8 version; 7668c2ecf20Sopenharmony_ci u8 prescaler_limit; 7678c2ecf20Sopenharmony_ci}; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic const struct davinci_spi_of_data dm6441_spi_data = { 7708c2ecf20Sopenharmony_ci .version = SPI_VERSION_1, 7718c2ecf20Sopenharmony_ci .prescaler_limit = 2, 7728c2ecf20Sopenharmony_ci}; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic const struct davinci_spi_of_data da830_spi_data = { 7758c2ecf20Sopenharmony_ci .version = SPI_VERSION_2, 7768c2ecf20Sopenharmony_ci .prescaler_limit = 2, 7778c2ecf20Sopenharmony_ci}; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic const struct davinci_spi_of_data keystone_spi_data = { 7808c2ecf20Sopenharmony_ci .version = SPI_VERSION_1, 7818c2ecf20Sopenharmony_ci .prescaler_limit = 0, 7828c2ecf20Sopenharmony_ci}; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic const struct of_device_id davinci_spi_of_match[] = { 7858c2ecf20Sopenharmony_ci { 7868c2ecf20Sopenharmony_ci .compatible = "ti,dm6441-spi", 7878c2ecf20Sopenharmony_ci .data = &dm6441_spi_data, 7888c2ecf20Sopenharmony_ci }, 7898c2ecf20Sopenharmony_ci { 7908c2ecf20Sopenharmony_ci .compatible = "ti,da830-spi", 7918c2ecf20Sopenharmony_ci .data = &da830_spi_data, 7928c2ecf20Sopenharmony_ci }, 7938c2ecf20Sopenharmony_ci { 7948c2ecf20Sopenharmony_ci .compatible = "ti,keystone-spi", 7958c2ecf20Sopenharmony_ci .data = &keystone_spi_data, 7968c2ecf20Sopenharmony_ci }, 7978c2ecf20Sopenharmony_ci { }, 7988c2ecf20Sopenharmony_ci}; 7998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, davinci_spi_of_match); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci/** 8028c2ecf20Sopenharmony_ci * spi_davinci_get_pdata - Get platform data from DTS binding 8038c2ecf20Sopenharmony_ci * @pdev: ptr to platform data 8048c2ecf20Sopenharmony_ci * @dspi: ptr to driver data 8058c2ecf20Sopenharmony_ci * 8068c2ecf20Sopenharmony_ci * Parses and populates pdata in dspi from device tree bindings. 8078c2ecf20Sopenharmony_ci * 8088c2ecf20Sopenharmony_ci * NOTE: Not all platform data params are supported currently. 8098c2ecf20Sopenharmony_ci */ 8108c2ecf20Sopenharmony_cistatic int spi_davinci_get_pdata(struct platform_device *pdev, 8118c2ecf20Sopenharmony_ci struct davinci_spi *dspi) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 8148c2ecf20Sopenharmony_ci struct davinci_spi_of_data *spi_data; 8158c2ecf20Sopenharmony_ci struct davinci_spi_platform_data *pdata; 8168c2ecf20Sopenharmony_ci unsigned int num_cs, intr_line = 0; 8178c2ecf20Sopenharmony_ci const struct of_device_id *match; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci pdata = &dspi->pdata; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci match = of_match_device(davinci_spi_of_match, &pdev->dev); 8228c2ecf20Sopenharmony_ci if (!match) 8238c2ecf20Sopenharmony_ci return -ENODEV; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci spi_data = (struct davinci_spi_of_data *)match->data; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci pdata->version = spi_data->version; 8288c2ecf20Sopenharmony_ci pdata->prescaler_limit = spi_data->prescaler_limit; 8298c2ecf20Sopenharmony_ci /* 8308c2ecf20Sopenharmony_ci * default num_cs is 1 and all chipsel are internal to the chip 8318c2ecf20Sopenharmony_ci * indicated by chip_sel being NULL or cs_gpios being NULL or 8328c2ecf20Sopenharmony_ci * set to -ENOENT. num-cs includes internal as well as gpios. 8338c2ecf20Sopenharmony_ci * indicated by chip_sel being NULL. GPIO based CS is not 8348c2ecf20Sopenharmony_ci * supported yet in DT bindings. 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci num_cs = 1; 8378c2ecf20Sopenharmony_ci of_property_read_u32(node, "num-cs", &num_cs); 8388c2ecf20Sopenharmony_ci pdata->num_chipselect = num_cs; 8398c2ecf20Sopenharmony_ci of_property_read_u32(node, "ti,davinci-spi-intr-line", &intr_line); 8408c2ecf20Sopenharmony_ci pdata->intr_line = intr_line; 8418c2ecf20Sopenharmony_ci return 0; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci#else 8448c2ecf20Sopenharmony_cistatic int spi_davinci_get_pdata(struct platform_device *pdev, 8458c2ecf20Sopenharmony_ci struct davinci_spi *dspi) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci return -ENODEV; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci#endif 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci/** 8528c2ecf20Sopenharmony_ci * davinci_spi_probe - probe function for SPI Master Controller 8538c2ecf20Sopenharmony_ci * @pdev: platform_device structure which contains plateform specific data 8548c2ecf20Sopenharmony_ci * 8558c2ecf20Sopenharmony_ci * According to Linux Device Model this function will be invoked by Linux 8568c2ecf20Sopenharmony_ci * with platform_device struct which contains the device specific info. 8578c2ecf20Sopenharmony_ci * This function will map the SPI controller's memory, register IRQ, 8588c2ecf20Sopenharmony_ci * Reset SPI controller and setting its registers to default value. 8598c2ecf20Sopenharmony_ci * It will invoke spi_bitbang_start to create work queue so that client driver 8608c2ecf20Sopenharmony_ci * can register transfer method to work queue. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_cistatic int davinci_spi_probe(struct platform_device *pdev) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci struct spi_master *master; 8658c2ecf20Sopenharmony_ci struct davinci_spi *dspi; 8668c2ecf20Sopenharmony_ci struct davinci_spi_platform_data *pdata; 8678c2ecf20Sopenharmony_ci struct resource *r; 8688c2ecf20Sopenharmony_ci int ret = 0; 8698c2ecf20Sopenharmony_ci u32 spipc0; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi)); 8728c2ecf20Sopenharmony_ci if (master == NULL) { 8738c2ecf20Sopenharmony_ci ret = -ENOMEM; 8748c2ecf20Sopenharmony_ci goto err; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, master); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci dspi = spi_master_get_devdata(master); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (dev_get_platdata(&pdev->dev)) { 8828c2ecf20Sopenharmony_ci pdata = dev_get_platdata(&pdev->dev); 8838c2ecf20Sopenharmony_ci dspi->pdata = *pdata; 8848c2ecf20Sopenharmony_ci } else { 8858c2ecf20Sopenharmony_ci /* update dspi pdata with that from the DT */ 8868c2ecf20Sopenharmony_ci ret = spi_davinci_get_pdata(pdev, dspi); 8878c2ecf20Sopenharmony_ci if (ret < 0) 8888c2ecf20Sopenharmony_ci goto free_master; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* pdata in dspi is now updated and point pdata to that */ 8928c2ecf20Sopenharmony_ci pdata = &dspi->pdata; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci dspi->bytes_per_word = devm_kcalloc(&pdev->dev, 8958c2ecf20Sopenharmony_ci pdata->num_chipselect, 8968c2ecf20Sopenharmony_ci sizeof(*dspi->bytes_per_word), 8978c2ecf20Sopenharmony_ci GFP_KERNEL); 8988c2ecf20Sopenharmony_ci if (dspi->bytes_per_word == NULL) { 8998c2ecf20Sopenharmony_ci ret = -ENOMEM; 9008c2ecf20Sopenharmony_ci goto free_master; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9048c2ecf20Sopenharmony_ci if (r == NULL) { 9058c2ecf20Sopenharmony_ci ret = -ENOENT; 9068c2ecf20Sopenharmony_ci goto free_master; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci dspi->pbase = r->start; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci dspi->base = devm_ioremap_resource(&pdev->dev, r); 9128c2ecf20Sopenharmony_ci if (IS_ERR(dspi->base)) { 9138c2ecf20Sopenharmony_ci ret = PTR_ERR(dspi->base); 9148c2ecf20Sopenharmony_ci goto free_master; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci init_completion(&dspi->done); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci ret = platform_get_irq(pdev, 0); 9208c2ecf20Sopenharmony_ci if (ret == 0) 9218c2ecf20Sopenharmony_ci ret = -EINVAL; 9228c2ecf20Sopenharmony_ci if (ret < 0) 9238c2ecf20Sopenharmony_ci goto free_master; 9248c2ecf20Sopenharmony_ci dspi->irq = ret; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, dspi->irq, davinci_spi_irq, 9278c2ecf20Sopenharmony_ci dummy_thread_fn, 0, dev_name(&pdev->dev), dspi); 9288c2ecf20Sopenharmony_ci if (ret) 9298c2ecf20Sopenharmony_ci goto free_master; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci dspi->bitbang.master = master; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci dspi->clk = devm_clk_get(&pdev->dev, NULL); 9348c2ecf20Sopenharmony_ci if (IS_ERR(dspi->clk)) { 9358c2ecf20Sopenharmony_ci ret = -ENODEV; 9368c2ecf20Sopenharmony_ci goto free_master; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dspi->clk); 9398c2ecf20Sopenharmony_ci if (ret) 9408c2ecf20Sopenharmony_ci goto free_master; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci master->use_gpio_descriptors = true; 9438c2ecf20Sopenharmony_ci master->dev.of_node = pdev->dev.of_node; 9448c2ecf20Sopenharmony_ci master->bus_num = pdev->id; 9458c2ecf20Sopenharmony_ci master->num_chipselect = pdata->num_chipselect; 9468c2ecf20Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); 9478c2ecf20Sopenharmony_ci master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_GPIO_SS; 9488c2ecf20Sopenharmony_ci master->setup = davinci_spi_setup; 9498c2ecf20Sopenharmony_ci master->cleanup = davinci_spi_cleanup; 9508c2ecf20Sopenharmony_ci master->can_dma = davinci_spi_can_dma; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci dspi->bitbang.chipselect = davinci_spi_chipselect; 9538c2ecf20Sopenharmony_ci dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; 9548c2ecf20Sopenharmony_ci dspi->prescaler_limit = pdata->prescaler_limit; 9558c2ecf20Sopenharmony_ci dspi->version = pdata->version; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_WORD; 9588c2ecf20Sopenharmony_ci if (dspi->version == SPI_VERSION_2) 9598c2ecf20Sopenharmony_ci dspi->bitbang.flags |= SPI_READY; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci dspi->bitbang.txrx_bufs = davinci_spi_bufs; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci ret = davinci_spi_request_dma(dspi); 9648c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) { 9658c2ecf20Sopenharmony_ci goto free_clk; 9668c2ecf20Sopenharmony_ci } else if (ret) { 9678c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "DMA is not supported (%d)\n", ret); 9688c2ecf20Sopenharmony_ci dspi->dma_rx = NULL; 9698c2ecf20Sopenharmony_ci dspi->dma_tx = NULL; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci dspi->get_rx = davinci_spi_rx_buf_u8; 9738c2ecf20Sopenharmony_ci dspi->get_tx = davinci_spi_tx_buf_u8; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* Reset In/OUT SPI module */ 9768c2ecf20Sopenharmony_ci iowrite32(0, dspi->base + SPIGCR0); 9778c2ecf20Sopenharmony_ci udelay(100); 9788c2ecf20Sopenharmony_ci iowrite32(1, dspi->base + SPIGCR0); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* Set up SPIPC0. CS and ENA init is done in davinci_spi_setup */ 9818c2ecf20Sopenharmony_ci spipc0 = SPIPC0_DIFUN_MASK | SPIPC0_DOFUN_MASK | SPIPC0_CLKFUN_MASK; 9828c2ecf20Sopenharmony_ci iowrite32(spipc0, dspi->base + SPIPC0); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (pdata->intr_line) 9858c2ecf20Sopenharmony_ci iowrite32(SPI_INTLVL_1, dspi->base + SPILVL); 9868c2ecf20Sopenharmony_ci else 9878c2ecf20Sopenharmony_ci iowrite32(SPI_INTLVL_0, dspi->base + SPILVL); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci iowrite32(CS_DEFAULT, dspi->base + SPIDEF); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci /* master mode default */ 9928c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK); 9938c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIGCR1, SPIGCR1_MASTER_MASK); 9948c2ecf20Sopenharmony_ci set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci ret = spi_bitbang_start(&dspi->bitbang); 9978c2ecf20Sopenharmony_ci if (ret) 9988c2ecf20Sopenharmony_ci goto free_dma; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Controller at 0x%p\n", dspi->base); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return ret; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cifree_dma: 10058c2ecf20Sopenharmony_ci if (dspi->dma_rx) { 10068c2ecf20Sopenharmony_ci dma_release_channel(dspi->dma_rx); 10078c2ecf20Sopenharmony_ci dma_release_channel(dspi->dma_tx); 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_cifree_clk: 10108c2ecf20Sopenharmony_ci clk_disable_unprepare(dspi->clk); 10118c2ecf20Sopenharmony_cifree_master: 10128c2ecf20Sopenharmony_ci spi_master_put(master); 10138c2ecf20Sopenharmony_cierr: 10148c2ecf20Sopenharmony_ci return ret; 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci/** 10188c2ecf20Sopenharmony_ci * davinci_spi_remove - remove function for SPI Master Controller 10198c2ecf20Sopenharmony_ci * @pdev: platform_device structure which contains plateform specific data 10208c2ecf20Sopenharmony_ci * 10218c2ecf20Sopenharmony_ci * This function will do the reverse action of davinci_spi_probe function 10228c2ecf20Sopenharmony_ci * It will free the IRQ and SPI controller's memory region. 10238c2ecf20Sopenharmony_ci * It will also call spi_bitbang_stop to destroy the work queue which was 10248c2ecf20Sopenharmony_ci * created by spi_bitbang_start. 10258c2ecf20Sopenharmony_ci */ 10268c2ecf20Sopenharmony_cistatic int davinci_spi_remove(struct platform_device *pdev) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci struct davinci_spi *dspi; 10298c2ecf20Sopenharmony_ci struct spi_master *master; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci master = platform_get_drvdata(pdev); 10328c2ecf20Sopenharmony_ci dspi = spi_master_get_devdata(master); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci spi_bitbang_stop(&dspi->bitbang); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci clk_disable_unprepare(dspi->clk); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (dspi->dma_rx) { 10398c2ecf20Sopenharmony_ci dma_release_channel(dspi->dma_rx); 10408c2ecf20Sopenharmony_ci dma_release_channel(dspi->dma_tx); 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci spi_master_put(master); 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic struct platform_driver davinci_spi_driver = { 10488c2ecf20Sopenharmony_ci .driver = { 10498c2ecf20Sopenharmony_ci .name = "spi_davinci", 10508c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(davinci_spi_of_match), 10518c2ecf20Sopenharmony_ci }, 10528c2ecf20Sopenharmony_ci .probe = davinci_spi_probe, 10538c2ecf20Sopenharmony_ci .remove = davinci_spi_remove, 10548c2ecf20Sopenharmony_ci}; 10558c2ecf20Sopenharmony_cimodule_platform_driver(davinci_spi_driver); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI DaVinci SPI Master Controller Driver"); 10588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1059