18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs 48c2ecf20Sopenharmony_ci * Copyright (C) 2013, Intel Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/acpi.h> 88c2ecf20Sopenharmony_ci#include <linux/bitops.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 158c2ecf20Sopenharmony_ci#include <linux/gpio.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/ioport.h> 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/pci.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 258c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 268c2ecf20Sopenharmony_ci#include <linux/property.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/spi/pxa2xx_spi.h> 298c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "spi-pxa2xx.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Stephen Street"); 348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PXA2xx SSP SPI Controller"); 358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 368c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:pxa2xx-spi"); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define TIMOUT_DFLT 1000 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * for testing SSCR1 changes that require SSP restart, basically 428c2ecf20Sopenharmony_ci * everything except the service and interrupt enables, the pxa270 developer 438c2ecf20Sopenharmony_ci * manual says only SSCR1_SCFR, SSCR1_SPH, SSCR1_SPO need to be in this 448c2ecf20Sopenharmony_ci * list, but the PXA255 dev man says all bits without really meaning the 458c2ecf20Sopenharmony_ci * service and interrupt enables 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci#define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \ 488c2ecf20Sopenharmony_ci | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \ 498c2ecf20Sopenharmony_ci | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \ 508c2ecf20Sopenharmony_ci | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \ 518c2ecf20Sopenharmony_ci | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \ 528c2ecf20Sopenharmony_ci | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define QUARK_X1000_SSCR1_CHANGE_MASK (QUARK_X1000_SSCR1_STRF \ 558c2ecf20Sopenharmony_ci | QUARK_X1000_SSCR1_EFWR \ 568c2ecf20Sopenharmony_ci | QUARK_X1000_SSCR1_RFT \ 578c2ecf20Sopenharmony_ci | QUARK_X1000_SSCR1_TFT \ 588c2ecf20Sopenharmony_ci | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define CE4100_SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \ 618c2ecf20Sopenharmony_ci | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \ 628c2ecf20Sopenharmony_ci | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \ 638c2ecf20Sopenharmony_ci | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \ 648c2ecf20Sopenharmony_ci | CE4100_SSCR1_RFT | CE4100_SSCR1_TFT | SSCR1_MWDS \ 658c2ecf20Sopenharmony_ci | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) 688c2ecf20Sopenharmony_ci#define LPSS_CS_CONTROL_SW_MODE BIT(0) 698c2ecf20Sopenharmony_ci#define LPSS_CS_CONTROL_CS_HIGH BIT(1) 708c2ecf20Sopenharmony_ci#define LPSS_CAPS_CS_EN_SHIFT 9 718c2ecf20Sopenharmony_ci#define LPSS_CAPS_CS_EN_MASK (0xf << LPSS_CAPS_CS_EN_SHIFT) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define LPSS_PRIV_CLOCK_GATE 0x38 748c2ecf20Sopenharmony_ci#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3 758c2ecf20Sopenharmony_ci#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct lpss_config { 788c2ecf20Sopenharmony_ci /* LPSS offset from drv_data->ioaddr */ 798c2ecf20Sopenharmony_ci unsigned offset; 808c2ecf20Sopenharmony_ci /* Register offsets from drv_data->lpss_base or -1 */ 818c2ecf20Sopenharmony_ci int reg_general; 828c2ecf20Sopenharmony_ci int reg_ssp; 838c2ecf20Sopenharmony_ci int reg_cs_ctrl; 848c2ecf20Sopenharmony_ci int reg_capabilities; 858c2ecf20Sopenharmony_ci /* FIFO thresholds */ 868c2ecf20Sopenharmony_ci u32 rx_threshold; 878c2ecf20Sopenharmony_ci u32 tx_threshold_lo; 888c2ecf20Sopenharmony_ci u32 tx_threshold_hi; 898c2ecf20Sopenharmony_ci /* Chip select control */ 908c2ecf20Sopenharmony_ci unsigned cs_sel_shift; 918c2ecf20Sopenharmony_ci unsigned cs_sel_mask; 928c2ecf20Sopenharmony_ci unsigned cs_num; 938c2ecf20Sopenharmony_ci /* Quirks */ 948c2ecf20Sopenharmony_ci unsigned cs_clk_stays_gated : 1; 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* Keep these sorted with enum pxa_ssp_type */ 988c2ecf20Sopenharmony_cistatic const struct lpss_config lpss_platforms[] = { 998c2ecf20Sopenharmony_ci { /* LPSS_LPT_SSP */ 1008c2ecf20Sopenharmony_ci .offset = 0x800, 1018c2ecf20Sopenharmony_ci .reg_general = 0x08, 1028c2ecf20Sopenharmony_ci .reg_ssp = 0x0c, 1038c2ecf20Sopenharmony_ci .reg_cs_ctrl = 0x18, 1048c2ecf20Sopenharmony_ci .reg_capabilities = -1, 1058c2ecf20Sopenharmony_ci .rx_threshold = 64, 1068c2ecf20Sopenharmony_ci .tx_threshold_lo = 160, 1078c2ecf20Sopenharmony_ci .tx_threshold_hi = 224, 1088c2ecf20Sopenharmony_ci }, 1098c2ecf20Sopenharmony_ci { /* LPSS_BYT_SSP */ 1108c2ecf20Sopenharmony_ci .offset = 0x400, 1118c2ecf20Sopenharmony_ci .reg_general = 0x08, 1128c2ecf20Sopenharmony_ci .reg_ssp = 0x0c, 1138c2ecf20Sopenharmony_ci .reg_cs_ctrl = 0x18, 1148c2ecf20Sopenharmony_ci .reg_capabilities = -1, 1158c2ecf20Sopenharmony_ci .rx_threshold = 64, 1168c2ecf20Sopenharmony_ci .tx_threshold_lo = 160, 1178c2ecf20Sopenharmony_ci .tx_threshold_hi = 224, 1188c2ecf20Sopenharmony_ci }, 1198c2ecf20Sopenharmony_ci { /* LPSS_BSW_SSP */ 1208c2ecf20Sopenharmony_ci .offset = 0x400, 1218c2ecf20Sopenharmony_ci .reg_general = 0x08, 1228c2ecf20Sopenharmony_ci .reg_ssp = 0x0c, 1238c2ecf20Sopenharmony_ci .reg_cs_ctrl = 0x18, 1248c2ecf20Sopenharmony_ci .reg_capabilities = -1, 1258c2ecf20Sopenharmony_ci .rx_threshold = 64, 1268c2ecf20Sopenharmony_ci .tx_threshold_lo = 160, 1278c2ecf20Sopenharmony_ci .tx_threshold_hi = 224, 1288c2ecf20Sopenharmony_ci .cs_sel_shift = 2, 1298c2ecf20Sopenharmony_ci .cs_sel_mask = 1 << 2, 1308c2ecf20Sopenharmony_ci .cs_num = 2, 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci { /* LPSS_SPT_SSP */ 1338c2ecf20Sopenharmony_ci .offset = 0x200, 1348c2ecf20Sopenharmony_ci .reg_general = -1, 1358c2ecf20Sopenharmony_ci .reg_ssp = 0x20, 1368c2ecf20Sopenharmony_ci .reg_cs_ctrl = 0x24, 1378c2ecf20Sopenharmony_ci .reg_capabilities = -1, 1388c2ecf20Sopenharmony_ci .rx_threshold = 1, 1398c2ecf20Sopenharmony_ci .tx_threshold_lo = 32, 1408c2ecf20Sopenharmony_ci .tx_threshold_hi = 56, 1418c2ecf20Sopenharmony_ci }, 1428c2ecf20Sopenharmony_ci { /* LPSS_BXT_SSP */ 1438c2ecf20Sopenharmony_ci .offset = 0x200, 1448c2ecf20Sopenharmony_ci .reg_general = -1, 1458c2ecf20Sopenharmony_ci .reg_ssp = 0x20, 1468c2ecf20Sopenharmony_ci .reg_cs_ctrl = 0x24, 1478c2ecf20Sopenharmony_ci .reg_capabilities = 0xfc, 1488c2ecf20Sopenharmony_ci .rx_threshold = 1, 1498c2ecf20Sopenharmony_ci .tx_threshold_lo = 16, 1508c2ecf20Sopenharmony_ci .tx_threshold_hi = 48, 1518c2ecf20Sopenharmony_ci .cs_sel_shift = 8, 1528c2ecf20Sopenharmony_ci .cs_sel_mask = 3 << 8, 1538c2ecf20Sopenharmony_ci .cs_clk_stays_gated = true, 1548c2ecf20Sopenharmony_ci }, 1558c2ecf20Sopenharmony_ci { /* LPSS_CNL_SSP */ 1568c2ecf20Sopenharmony_ci .offset = 0x200, 1578c2ecf20Sopenharmony_ci .reg_general = -1, 1588c2ecf20Sopenharmony_ci .reg_ssp = 0x20, 1598c2ecf20Sopenharmony_ci .reg_cs_ctrl = 0x24, 1608c2ecf20Sopenharmony_ci .reg_capabilities = 0xfc, 1618c2ecf20Sopenharmony_ci .rx_threshold = 1, 1628c2ecf20Sopenharmony_ci .tx_threshold_lo = 32, 1638c2ecf20Sopenharmony_ci .tx_threshold_hi = 56, 1648c2ecf20Sopenharmony_ci .cs_sel_shift = 8, 1658c2ecf20Sopenharmony_ci .cs_sel_mask = 3 << 8, 1668c2ecf20Sopenharmony_ci .cs_clk_stays_gated = true, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline const struct lpss_config 1718c2ecf20Sopenharmony_ci*lpss_get_config(const struct driver_data *drv_data) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return &lpss_platforms[drv_data->ssp_type - LPSS_LPT_SSP]; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic bool is_lpss_ssp(const struct driver_data *drv_data) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 1798c2ecf20Sopenharmony_ci case LPSS_LPT_SSP: 1808c2ecf20Sopenharmony_ci case LPSS_BYT_SSP: 1818c2ecf20Sopenharmony_ci case LPSS_BSW_SSP: 1828c2ecf20Sopenharmony_ci case LPSS_SPT_SSP: 1838c2ecf20Sopenharmony_ci case LPSS_BXT_SSP: 1848c2ecf20Sopenharmony_ci case LPSS_CNL_SSP: 1858c2ecf20Sopenharmony_ci return true; 1868c2ecf20Sopenharmony_ci default: 1878c2ecf20Sopenharmony_ci return false; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic bool is_quark_x1000_ssp(const struct driver_data *drv_data) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci return drv_data->ssp_type == QUARK_X1000_SSP; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic bool is_mmp2_ssp(const struct driver_data *drv_data) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci return drv_data->ssp_type == MMP2_SSP; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 2048c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 2058c2ecf20Sopenharmony_ci return QUARK_X1000_SSCR1_CHANGE_MASK; 2068c2ecf20Sopenharmony_ci case CE4100_SSP: 2078c2ecf20Sopenharmony_ci return CE4100_SSCR1_CHANGE_MASK; 2088c2ecf20Sopenharmony_ci default: 2098c2ecf20Sopenharmony_ci return SSCR1_CHANGE_MASK; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic u32 2148c2ecf20Sopenharmony_cipxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 2178c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 2188c2ecf20Sopenharmony_ci return RX_THRESH_QUARK_X1000_DFLT; 2198c2ecf20Sopenharmony_ci case CE4100_SSP: 2208c2ecf20Sopenharmony_ci return RX_THRESH_CE4100_DFLT; 2218c2ecf20Sopenharmony_ci default: 2228c2ecf20Sopenharmony_ci return RX_THRESH_DFLT; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci u32 mask; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 2318c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 2328c2ecf20Sopenharmony_ci mask = QUARK_X1000_SSSR_TFL_MASK; 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci case CE4100_SSP: 2358c2ecf20Sopenharmony_ci mask = CE4100_SSSR_TFL_MASK; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci default: 2388c2ecf20Sopenharmony_ci mask = SSSR_TFL_MASK; 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data, 2468c2ecf20Sopenharmony_ci u32 *sccr1_reg) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci u32 mask; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 2518c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 2528c2ecf20Sopenharmony_ci mask = QUARK_X1000_SSCR1_RFT; 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci case CE4100_SSP: 2558c2ecf20Sopenharmony_ci mask = CE4100_SSCR1_RFT; 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci default: 2588c2ecf20Sopenharmony_ci mask = SSCR1_RFT; 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci *sccr1_reg &= ~mask; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void pxa2xx_spi_set_rx_thre(const struct driver_data *drv_data, 2658c2ecf20Sopenharmony_ci u32 *sccr1_reg, u32 threshold) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 2688c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 2698c2ecf20Sopenharmony_ci *sccr1_reg |= QUARK_X1000_SSCR1_RxTresh(threshold); 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci case CE4100_SSP: 2728c2ecf20Sopenharmony_ci *sccr1_reg |= CE4100_SSCR1_RxTresh(threshold); 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci default: 2758c2ecf20Sopenharmony_ci *sccr1_reg |= SSCR1_RxTresh(threshold); 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data, 2818c2ecf20Sopenharmony_ci u32 clk_div, u8 bits) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 2848c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 2858c2ecf20Sopenharmony_ci return clk_div 2868c2ecf20Sopenharmony_ci | QUARK_X1000_SSCR0_Motorola 2878c2ecf20Sopenharmony_ci | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits) 2888c2ecf20Sopenharmony_ci | SSCR0_SSE; 2898c2ecf20Sopenharmony_ci default: 2908c2ecf20Sopenharmony_ci return clk_div 2918c2ecf20Sopenharmony_ci | SSCR0_Motorola 2928c2ecf20Sopenharmony_ci | SSCR0_DataSize(bits > 16 ? bits - 16 : bits) 2938c2ecf20Sopenharmony_ci | SSCR0_SSE 2948c2ecf20Sopenharmony_ci | (bits > 16 ? SSCR0_EDSS : 0); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* 2998c2ecf20Sopenharmony_ci * Read and write LPSS SSP private registers. Caller must first check that 3008c2ecf20Sopenharmony_ci * is_lpss_ssp() returns true before these can be called. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic u32 __lpss_ssp_read_priv(struct driver_data *drv_data, unsigned offset) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci WARN_ON(!drv_data->lpss_base); 3058c2ecf20Sopenharmony_ci return readl(drv_data->lpss_base + offset); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic void __lpss_ssp_write_priv(struct driver_data *drv_data, 3098c2ecf20Sopenharmony_ci unsigned offset, u32 value) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci WARN_ON(!drv_data->lpss_base); 3128c2ecf20Sopenharmony_ci writel(value, drv_data->lpss_base + offset); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/* 3168c2ecf20Sopenharmony_ci * lpss_ssp_setup - perform LPSS SSP specific setup 3178c2ecf20Sopenharmony_ci * @drv_data: pointer to the driver private data 3188c2ecf20Sopenharmony_ci * 3198c2ecf20Sopenharmony_ci * Perform LPSS SSP specific setup. This function must be called first if 3208c2ecf20Sopenharmony_ci * one is going to use LPSS SSP private registers. 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_cistatic void lpss_ssp_setup(struct driver_data *drv_data) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci const struct lpss_config *config; 3258c2ecf20Sopenharmony_ci u32 value; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci config = lpss_get_config(drv_data); 3288c2ecf20Sopenharmony_ci drv_data->lpss_base = drv_data->ioaddr + config->offset; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Enable software chip select control */ 3318c2ecf20Sopenharmony_ci value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); 3328c2ecf20Sopenharmony_ci value &= ~(LPSS_CS_CONTROL_SW_MODE | LPSS_CS_CONTROL_CS_HIGH); 3338c2ecf20Sopenharmony_ci value |= LPSS_CS_CONTROL_SW_MODE | LPSS_CS_CONTROL_CS_HIGH; 3348c2ecf20Sopenharmony_ci __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Enable multiblock DMA transfers */ 3378c2ecf20Sopenharmony_ci if (drv_data->controller_info->enable_dma) { 3388c2ecf20Sopenharmony_ci __lpss_ssp_write_priv(drv_data, config->reg_ssp, 1); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (config->reg_general >= 0) { 3418c2ecf20Sopenharmony_ci value = __lpss_ssp_read_priv(drv_data, 3428c2ecf20Sopenharmony_ci config->reg_general); 3438c2ecf20Sopenharmony_ci value |= LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE; 3448c2ecf20Sopenharmony_ci __lpss_ssp_write_priv(drv_data, 3458c2ecf20Sopenharmony_ci config->reg_general, value); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic void lpss_ssp_select_cs(struct spi_device *spi, 3518c2ecf20Sopenharmony_ci const struct lpss_config *config) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct driver_data *drv_data = 3548c2ecf20Sopenharmony_ci spi_controller_get_devdata(spi->controller); 3558c2ecf20Sopenharmony_ci u32 value, cs; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (!config->cs_sel_mask) 3588c2ecf20Sopenharmony_ci return; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci cs = spi->chip_select; 3638c2ecf20Sopenharmony_ci cs <<= config->cs_sel_shift; 3648c2ecf20Sopenharmony_ci if (cs != (value & config->cs_sel_mask)) { 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * When switching another chip select output active the 3678c2ecf20Sopenharmony_ci * output must be selected first and wait 2 ssp_clk cycles 3688c2ecf20Sopenharmony_ci * before changing state to active. Otherwise a short 3698c2ecf20Sopenharmony_ci * glitch will occur on the previous chip select since 3708c2ecf20Sopenharmony_ci * output select is latched but state control is not. 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ci value &= ~config->cs_sel_mask; 3738c2ecf20Sopenharmony_ci value |= cs; 3748c2ecf20Sopenharmony_ci __lpss_ssp_write_priv(drv_data, 3758c2ecf20Sopenharmony_ci config->reg_cs_ctrl, value); 3768c2ecf20Sopenharmony_ci ndelay(1000000000 / 3778c2ecf20Sopenharmony_ci (drv_data->controller->max_speed_hz / 2)); 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void lpss_ssp_cs_control(struct spi_device *spi, bool enable) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct driver_data *drv_data = 3848c2ecf20Sopenharmony_ci spi_controller_get_devdata(spi->controller); 3858c2ecf20Sopenharmony_ci const struct lpss_config *config; 3868c2ecf20Sopenharmony_ci u32 value; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci config = lpss_get_config(drv_data); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (enable) 3918c2ecf20Sopenharmony_ci lpss_ssp_select_cs(spi, config); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl); 3948c2ecf20Sopenharmony_ci if (enable) 3958c2ecf20Sopenharmony_ci value &= ~LPSS_CS_CONTROL_CS_HIGH; 3968c2ecf20Sopenharmony_ci else 3978c2ecf20Sopenharmony_ci value |= LPSS_CS_CONTROL_CS_HIGH; 3988c2ecf20Sopenharmony_ci __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); 3998c2ecf20Sopenharmony_ci if (config->cs_clk_stays_gated) { 4008c2ecf20Sopenharmony_ci u32 clkgate; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* 4038c2ecf20Sopenharmony_ci * Changing CS alone when dynamic clock gating is on won't 4048c2ecf20Sopenharmony_ci * actually flip CS at that time. This ruins SPI transfers 4058c2ecf20Sopenharmony_ci * that specify delays, or have no data. Toggle the clock mode 4068c2ecf20Sopenharmony_ci * to force on briefly to poke the CS pin to move. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE); 4098c2ecf20Sopenharmony_ci value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) | 4108c2ecf20Sopenharmony_ci LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value); 4138c2ecf20Sopenharmony_ci __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate); 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void cs_assert(struct spi_device *spi) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct chip_data *chip = spi_get_ctldata(spi); 4208c2ecf20Sopenharmony_ci struct driver_data *drv_data = 4218c2ecf20Sopenharmony_ci spi_controller_get_devdata(spi->controller); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (drv_data->ssp_type == CE4100_SSP) { 4248c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSSR, chip->frm); 4258c2ecf20Sopenharmony_ci return; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (chip->cs_control) { 4298c2ecf20Sopenharmony_ci chip->cs_control(PXA2XX_CS_ASSERT); 4308c2ecf20Sopenharmony_ci return; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (chip->gpiod_cs) { 4348c2ecf20Sopenharmony_ci gpiod_set_value(chip->gpiod_cs, chip->gpio_cs_inverted); 4358c2ecf20Sopenharmony_ci return; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (is_lpss_ssp(drv_data)) 4398c2ecf20Sopenharmony_ci lpss_ssp_cs_control(spi, true); 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic void cs_deassert(struct spi_device *spi) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct chip_data *chip = spi_get_ctldata(spi); 4458c2ecf20Sopenharmony_ci struct driver_data *drv_data = 4468c2ecf20Sopenharmony_ci spi_controller_get_devdata(spi->controller); 4478c2ecf20Sopenharmony_ci unsigned long timeout; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (drv_data->ssp_type == CE4100_SSP) 4508c2ecf20Sopenharmony_ci return; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* Wait until SSP becomes idle before deasserting the CS */ 4538c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(10); 4548c2ecf20Sopenharmony_ci while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY && 4558c2ecf20Sopenharmony_ci !time_after(jiffies, timeout)) 4568c2ecf20Sopenharmony_ci cpu_relax(); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (chip->cs_control) { 4598c2ecf20Sopenharmony_ci chip->cs_control(PXA2XX_CS_DEASSERT); 4608c2ecf20Sopenharmony_ci return; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (chip->gpiod_cs) { 4648c2ecf20Sopenharmony_ci gpiod_set_value(chip->gpiod_cs, !chip->gpio_cs_inverted); 4658c2ecf20Sopenharmony_ci return; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (is_lpss_ssp(drv_data)) 4698c2ecf20Sopenharmony_ci lpss_ssp_cs_control(spi, false); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic void pxa2xx_spi_set_cs(struct spi_device *spi, bool level) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci if (level) 4758c2ecf20Sopenharmony_ci cs_deassert(spi); 4768c2ecf20Sopenharmony_ci else 4778c2ecf20Sopenharmony_ci cs_assert(spi); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ciint pxa2xx_spi_flush(struct driver_data *drv_data) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci unsigned long limit = loops_per_jiffy << 1; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci do { 4858c2ecf20Sopenharmony_ci while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) 4868c2ecf20Sopenharmony_ci pxa2xx_spi_read(drv_data, SSDR); 4878c2ecf20Sopenharmony_ci } while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit); 4888c2ecf20Sopenharmony_ci write_SSSR_CS(drv_data, SSSR_ROR); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return limit; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic void pxa2xx_spi_off(struct driver_data *drv_data) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci /* On MMP, disabling SSE seems to corrupt the Rx FIFO */ 4968c2ecf20Sopenharmony_ci if (is_mmp2_ssp(drv_data)) 4978c2ecf20Sopenharmony_ci return; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, 5008c2ecf20Sopenharmony_ci pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int null_writer(struct driver_data *drv_data) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci u8 n_bytes = drv_data->n_bytes; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (pxa2xx_spi_txfifo_full(drv_data) 5088c2ecf20Sopenharmony_ci || (drv_data->tx == drv_data->tx_end)) 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSDR, 0); 5128c2ecf20Sopenharmony_ci drv_data->tx += n_bytes; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 1; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int null_reader(struct driver_data *drv_data) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci u8 n_bytes = drv_data->n_bytes; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) 5228c2ecf20Sopenharmony_ci && (drv_data->rx < drv_data->rx_end)) { 5238c2ecf20Sopenharmony_ci pxa2xx_spi_read(drv_data, SSDR); 5248c2ecf20Sopenharmony_ci drv_data->rx += n_bytes; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return drv_data->rx == drv_data->rx_end; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int u8_writer(struct driver_data *drv_data) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci if (pxa2xx_spi_txfifo_full(drv_data) 5338c2ecf20Sopenharmony_ci || (drv_data->tx == drv_data->tx_end)) 5348c2ecf20Sopenharmony_ci return 0; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSDR, *(u8 *)(drv_data->tx)); 5378c2ecf20Sopenharmony_ci ++drv_data->tx; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return 1; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int u8_reader(struct driver_data *drv_data) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) 5458c2ecf20Sopenharmony_ci && (drv_data->rx < drv_data->rx_end)) { 5468c2ecf20Sopenharmony_ci *(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); 5478c2ecf20Sopenharmony_ci ++drv_data->rx; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return drv_data->rx == drv_data->rx_end; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int u16_writer(struct driver_data *drv_data) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci if (pxa2xx_spi_txfifo_full(drv_data) 5568c2ecf20Sopenharmony_ci || (drv_data->tx == drv_data->tx_end)) 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSDR, *(u16 *)(drv_data->tx)); 5608c2ecf20Sopenharmony_ci drv_data->tx += 2; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci return 1; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int u16_reader(struct driver_data *drv_data) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) 5688c2ecf20Sopenharmony_ci && (drv_data->rx < drv_data->rx_end)) { 5698c2ecf20Sopenharmony_ci *(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); 5708c2ecf20Sopenharmony_ci drv_data->rx += 2; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return drv_data->rx == drv_data->rx_end; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int u32_writer(struct driver_data *drv_data) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci if (pxa2xx_spi_txfifo_full(drv_data) 5798c2ecf20Sopenharmony_ci || (drv_data->tx == drv_data->tx_end)) 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSDR, *(u32 *)(drv_data->tx)); 5838c2ecf20Sopenharmony_ci drv_data->tx += 4; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return 1; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic int u32_reader(struct driver_data *drv_data) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE) 5918c2ecf20Sopenharmony_ci && (drv_data->rx < drv_data->rx_end)) { 5928c2ecf20Sopenharmony_ci *(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR); 5938c2ecf20Sopenharmony_ci drv_data->rx += 4; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return drv_data->rx == drv_data->rx_end; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void reset_sccr1(struct driver_data *drv_data) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct chip_data *chip = 6028c2ecf20Sopenharmony_ci spi_get_ctldata(drv_data->controller->cur_msg->spi); 6038c2ecf20Sopenharmony_ci u32 sccr1_reg; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1; 6068c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 6078c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 6088c2ecf20Sopenharmony_ci sccr1_reg &= ~QUARK_X1000_SSCR1_RFT; 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case CE4100_SSP: 6118c2ecf20Sopenharmony_ci sccr1_reg &= ~CE4100_SSCR1_RFT; 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci default: 6148c2ecf20Sopenharmony_ci sccr1_reg &= ~SSCR1_RFT; 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci sccr1_reg |= chip->threshold; 6188c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic void int_error_stop(struct driver_data *drv_data, const char* msg) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci /* Stop and reset SSP */ 6248c2ecf20Sopenharmony_ci write_SSSR_CS(drv_data, drv_data->clear_sr); 6258c2ecf20Sopenharmony_ci reset_sccr1(drv_data); 6268c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 6278c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, 0); 6288c2ecf20Sopenharmony_ci pxa2xx_spi_flush(drv_data); 6298c2ecf20Sopenharmony_ci pxa2xx_spi_off(drv_data); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci dev_err(&drv_data->pdev->dev, "%s\n", msg); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci drv_data->controller->cur_msg->status = -EIO; 6348c2ecf20Sopenharmony_ci spi_finalize_current_transfer(drv_data->controller); 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic void int_transfer_complete(struct driver_data *drv_data) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci /* Clear and disable interrupts */ 6408c2ecf20Sopenharmony_ci write_SSSR_CS(drv_data, drv_data->clear_sr); 6418c2ecf20Sopenharmony_ci reset_sccr1(drv_data); 6428c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 6438c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, 0); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci spi_finalize_current_transfer(drv_data->controller); 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic irqreturn_t interrupt_transfer(struct driver_data *drv_data) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ? 6518c2ecf20Sopenharmony_ci drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (irq_status & SSSR_ROR) { 6568c2ecf20Sopenharmony_ci int_error_stop(drv_data, "interrupt_transfer: fifo overrun"); 6578c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (irq_status & SSSR_TUR) { 6618c2ecf20Sopenharmony_ci int_error_stop(drv_data, "interrupt_transfer: fifo underrun"); 6628c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (irq_status & SSSR_TINT) { 6668c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT); 6678c2ecf20Sopenharmony_ci if (drv_data->read(drv_data)) { 6688c2ecf20Sopenharmony_ci int_transfer_complete(drv_data); 6698c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* Drain rx fifo, Fill tx fifo and prevent overruns */ 6748c2ecf20Sopenharmony_ci do { 6758c2ecf20Sopenharmony_ci if (drv_data->read(drv_data)) { 6768c2ecf20Sopenharmony_ci int_transfer_complete(drv_data); 6778c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci } while (drv_data->write(drv_data)); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (drv_data->read(drv_data)) { 6828c2ecf20Sopenharmony_ci int_transfer_complete(drv_data); 6838c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (drv_data->tx == drv_data->tx_end) { 6878c2ecf20Sopenharmony_ci u32 bytes_left; 6888c2ecf20Sopenharmony_ci u32 sccr1_reg; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1); 6918c2ecf20Sopenharmony_ci sccr1_reg &= ~SSCR1_TIE; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* 6948c2ecf20Sopenharmony_ci * PXA25x_SSP has no timeout, set up rx threshould for the 6958c2ecf20Sopenharmony_ci * remaining RX bytes. 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ci if (pxa25x_ssp_comp(drv_data)) { 6988c2ecf20Sopenharmony_ci u32 rx_thre; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci pxa2xx_spi_clear_rx_thre(drv_data, &sccr1_reg); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci bytes_left = drv_data->rx_end - drv_data->rx; 7038c2ecf20Sopenharmony_ci switch (drv_data->n_bytes) { 7048c2ecf20Sopenharmony_ci case 4: 7058c2ecf20Sopenharmony_ci bytes_left >>= 2; 7068c2ecf20Sopenharmony_ci break; 7078c2ecf20Sopenharmony_ci case 2: 7088c2ecf20Sopenharmony_ci bytes_left >>= 1; 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data); 7138c2ecf20Sopenharmony_ci if (rx_thre > bytes_left) 7148c2ecf20Sopenharmony_ci rx_thre = bytes_left; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre); 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* We did something */ 7228c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic void handle_bad_msg(struct driver_data *drv_data) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci pxa2xx_spi_off(drv_data); 7288c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, 7298c2ecf20Sopenharmony_ci pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1); 7308c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 7318c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, 0); 7328c2ecf20Sopenharmony_ci write_SSSR_CS(drv_data, drv_data->clear_sr); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci dev_err(&drv_data->pdev->dev, 7358c2ecf20Sopenharmony_ci "bad message state in interrupt handler\n"); 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic irqreturn_t ssp_int(int irq, void *dev_id) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci struct driver_data *drv_data = dev_id; 7418c2ecf20Sopenharmony_ci u32 sccr1_reg; 7428c2ecf20Sopenharmony_ci u32 mask = drv_data->mask_sr; 7438c2ecf20Sopenharmony_ci u32 status; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* 7468c2ecf20Sopenharmony_ci * The IRQ might be shared with other peripherals so we must first 7478c2ecf20Sopenharmony_ci * check that are we RPM suspended or not. If we are we assume that 7488c2ecf20Sopenharmony_ci * the IRQ was not for us (we shouldn't be RPM suspended when the 7498c2ecf20Sopenharmony_ci * interrupt is enabled). 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ci if (pm_runtime_suspended(&drv_data->pdev->dev)) 7528c2ecf20Sopenharmony_ci return IRQ_NONE; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* 7558c2ecf20Sopenharmony_ci * If the device is not yet in RPM suspended state and we get an 7568c2ecf20Sopenharmony_ci * interrupt that is meant for another device, check if status bits 7578c2ecf20Sopenharmony_ci * are all set to one. That means that the device is already 7588c2ecf20Sopenharmony_ci * powered off. 7598c2ecf20Sopenharmony_ci */ 7608c2ecf20Sopenharmony_ci status = pxa2xx_spi_read(drv_data, SSSR); 7618c2ecf20Sopenharmony_ci if (status == ~0) 7628c2ecf20Sopenharmony_ci return IRQ_NONE; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci /* Ignore possible writes if we don't need to write */ 7678c2ecf20Sopenharmony_ci if (!(sccr1_reg & SSCR1_TIE)) 7688c2ecf20Sopenharmony_ci mask &= ~SSSR_TFS; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Ignore RX timeout interrupt if it is disabled */ 7718c2ecf20Sopenharmony_ci if (!(sccr1_reg & SSCR1_TINTE)) 7728c2ecf20Sopenharmony_ci mask &= ~SSSR_TINT; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (!(status & mask)) 7758c2ecf20Sopenharmony_ci return IRQ_NONE; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg & ~drv_data->int_cr1); 7788c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (!drv_data->controller->cur_msg) { 7818c2ecf20Sopenharmony_ci handle_bad_msg(drv_data); 7828c2ecf20Sopenharmony_ci /* Never fail */ 7838c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci return drv_data->transfer_handler(drv_data); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci/* 7908c2ecf20Sopenharmony_ci * The Quark SPI has an additional 24 bit register (DDS_CLK_RATE) to multiply 7918c2ecf20Sopenharmony_ci * input frequency by fractions of 2^24. It also has a divider by 5. 7928c2ecf20Sopenharmony_ci * 7938c2ecf20Sopenharmony_ci * There are formulas to get baud rate value for given input frequency and 7948c2ecf20Sopenharmony_ci * divider parameters, such as DDS_CLK_RATE and SCR: 7958c2ecf20Sopenharmony_ci * 7968c2ecf20Sopenharmony_ci * Fsys = 200MHz 7978c2ecf20Sopenharmony_ci * 7988c2ecf20Sopenharmony_ci * Fssp = Fsys * DDS_CLK_RATE / 2^24 (1) 7998c2ecf20Sopenharmony_ci * Baud rate = Fsclk = Fssp / (2 * (SCR + 1)) (2) 8008c2ecf20Sopenharmony_ci * 8018c2ecf20Sopenharmony_ci * DDS_CLK_RATE either 2^n or 2^n / 5. 8028c2ecf20Sopenharmony_ci * SCR is in range 0 .. 255 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * Divisor = 5^i * 2^j * 2 * k 8058c2ecf20Sopenharmony_ci * i = [0, 1] i = 1 iff j = 0 or j > 3 8068c2ecf20Sopenharmony_ci * j = [0, 23] j = 0 iff i = 1 8078c2ecf20Sopenharmony_ci * k = [1, 256] 8088c2ecf20Sopenharmony_ci * Special case: j = 0, i = 1: Divisor = 2 / 5 8098c2ecf20Sopenharmony_ci * 8108c2ecf20Sopenharmony_ci * Accordingly to the specification the recommended values for DDS_CLK_RATE 8118c2ecf20Sopenharmony_ci * are: 8128c2ecf20Sopenharmony_ci * Case 1: 2^n, n = [0, 23] 8138c2ecf20Sopenharmony_ci * Case 2: 2^24 * 2 / 5 (0x666666) 8148c2ecf20Sopenharmony_ci * Case 3: less than or equal to 2^24 / 5 / 16 (0x33333) 8158c2ecf20Sopenharmony_ci * 8168c2ecf20Sopenharmony_ci * In all cases the lowest possible value is better. 8178c2ecf20Sopenharmony_ci * 8188c2ecf20Sopenharmony_ci * The function calculates parameters for all cases and chooses the one closest 8198c2ecf20Sopenharmony_ci * to the asked baud rate. 8208c2ecf20Sopenharmony_ci */ 8218c2ecf20Sopenharmony_cistatic unsigned int quark_x1000_get_clk_div(int rate, u32 *dds) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci unsigned long xtal = 200000000; 8248c2ecf20Sopenharmony_ci unsigned long fref = xtal / 2; /* mandatory division by 2, 8258c2ecf20Sopenharmony_ci see (2) */ 8268c2ecf20Sopenharmony_ci /* case 3 */ 8278c2ecf20Sopenharmony_ci unsigned long fref1 = fref / 2; /* case 1 */ 8288c2ecf20Sopenharmony_ci unsigned long fref2 = fref * 2 / 5; /* case 2 */ 8298c2ecf20Sopenharmony_ci unsigned long scale; 8308c2ecf20Sopenharmony_ci unsigned long q, q1, q2; 8318c2ecf20Sopenharmony_ci long r, r1, r2; 8328c2ecf20Sopenharmony_ci u32 mul; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Case 1 */ 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* Set initial value for DDS_CLK_RATE */ 8378c2ecf20Sopenharmony_ci mul = (1 << 24) >> 1; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* Calculate initial quot */ 8408c2ecf20Sopenharmony_ci q1 = DIV_ROUND_UP(fref1, rate); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci /* Scale q1 if it's too big */ 8438c2ecf20Sopenharmony_ci if (q1 > 256) { 8448c2ecf20Sopenharmony_ci /* Scale q1 to range [1, 512] */ 8458c2ecf20Sopenharmony_ci scale = fls_long(q1 - 1); 8468c2ecf20Sopenharmony_ci if (scale > 9) { 8478c2ecf20Sopenharmony_ci q1 >>= scale - 9; 8488c2ecf20Sopenharmony_ci mul >>= scale - 9; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* Round the result if we have a remainder */ 8528c2ecf20Sopenharmony_ci q1 += q1 & 1; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* Decrease DDS_CLK_RATE as much as we can without loss in precision */ 8568c2ecf20Sopenharmony_ci scale = __ffs(q1); 8578c2ecf20Sopenharmony_ci q1 >>= scale; 8588c2ecf20Sopenharmony_ci mul >>= scale; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci /* Get the remainder */ 8618c2ecf20Sopenharmony_ci r1 = abs(fref1 / (1 << (24 - fls_long(mul))) / q1 - rate); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* Case 2 */ 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci q2 = DIV_ROUND_UP(fref2, rate); 8668c2ecf20Sopenharmony_ci r2 = abs(fref2 / q2 - rate); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* 8698c2ecf20Sopenharmony_ci * Choose the best between two: less remainder we have the better. We 8708c2ecf20Sopenharmony_ci * can't go case 2 if q2 is greater than 256 since SCR register can 8718c2ecf20Sopenharmony_ci * hold only values 0 .. 255. 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_ci if (r2 >= r1 || q2 > 256) { 8748c2ecf20Sopenharmony_ci /* case 1 is better */ 8758c2ecf20Sopenharmony_ci r = r1; 8768c2ecf20Sopenharmony_ci q = q1; 8778c2ecf20Sopenharmony_ci } else { 8788c2ecf20Sopenharmony_ci /* case 2 is better */ 8798c2ecf20Sopenharmony_ci r = r2; 8808c2ecf20Sopenharmony_ci q = q2; 8818c2ecf20Sopenharmony_ci mul = (1 << 24) * 2 / 5; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* Check case 3 only if the divisor is big enough */ 8858c2ecf20Sopenharmony_ci if (fref / rate >= 80) { 8868c2ecf20Sopenharmony_ci u64 fssp; 8878c2ecf20Sopenharmony_ci u32 m; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* Calculate initial quot */ 8908c2ecf20Sopenharmony_ci q1 = DIV_ROUND_UP(fref, rate); 8918c2ecf20Sopenharmony_ci m = (1 << 24) / q1; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* Get the remainder */ 8948c2ecf20Sopenharmony_ci fssp = (u64)fref * m; 8958c2ecf20Sopenharmony_ci do_div(fssp, 1 << 24); 8968c2ecf20Sopenharmony_ci r1 = abs(fssp - rate); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* Choose this one if it suits better */ 8998c2ecf20Sopenharmony_ci if (r1 < r) { 9008c2ecf20Sopenharmony_ci /* case 3 is better */ 9018c2ecf20Sopenharmony_ci q = 1; 9028c2ecf20Sopenharmony_ci mul = m; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci *dds = mul; 9078c2ecf20Sopenharmony_ci return q - 1; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci unsigned long ssp_clk = drv_data->controller->max_speed_hz; 9138c2ecf20Sopenharmony_ci const struct ssp_device *ssp = drv_data->ssp; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci rate = min_t(int, ssp_clk, rate); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* 9188c2ecf20Sopenharmony_ci * Calculate the divisor for the SCR (Serial Clock Rate), avoiding 9198c2ecf20Sopenharmony_ci * that the SSP transmission rate can be greater than the device rate 9208c2ecf20Sopenharmony_ci */ 9218c2ecf20Sopenharmony_ci if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP) 9228c2ecf20Sopenharmony_ci return (DIV_ROUND_UP(ssp_clk, 2 * rate) - 1) & 0xff; 9238c2ecf20Sopenharmony_ci else 9248c2ecf20Sopenharmony_ci return (DIV_ROUND_UP(ssp_clk, rate) - 1) & 0xfff; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data, 9288c2ecf20Sopenharmony_ci int rate) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci struct chip_data *chip = 9318c2ecf20Sopenharmony_ci spi_get_ctldata(drv_data->controller->cur_msg->spi); 9328c2ecf20Sopenharmony_ci unsigned int clk_div; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 9358c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 9368c2ecf20Sopenharmony_ci clk_div = quark_x1000_get_clk_div(rate, &chip->dds_rate); 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci default: 9398c2ecf20Sopenharmony_ci clk_div = ssp_get_clk_div(drv_data, rate); 9408c2ecf20Sopenharmony_ci break; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci return clk_div << 8; 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic bool pxa2xx_spi_can_dma(struct spi_controller *controller, 9468c2ecf20Sopenharmony_ci struct spi_device *spi, 9478c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct chip_data *chip = spi_get_ctldata(spi); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci return chip->enable_dma && 9528c2ecf20Sopenharmony_ci xfer->len <= MAX_DMA_LEN && 9538c2ecf20Sopenharmony_ci xfer->len >= chip->dma_burst_size; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cistatic int pxa2xx_spi_transfer_one(struct spi_controller *controller, 9578c2ecf20Sopenharmony_ci struct spi_device *spi, 9588c2ecf20Sopenharmony_ci struct spi_transfer *transfer) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct driver_data *drv_data = spi_controller_get_devdata(controller); 9618c2ecf20Sopenharmony_ci struct spi_message *message = controller->cur_msg; 9628c2ecf20Sopenharmony_ci struct chip_data *chip = spi_get_ctldata(spi); 9638c2ecf20Sopenharmony_ci u32 dma_thresh = chip->dma_threshold; 9648c2ecf20Sopenharmony_ci u32 dma_burst = chip->dma_burst_size; 9658c2ecf20Sopenharmony_ci u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data); 9668c2ecf20Sopenharmony_ci u32 clk_div; 9678c2ecf20Sopenharmony_ci u8 bits; 9688c2ecf20Sopenharmony_ci u32 speed; 9698c2ecf20Sopenharmony_ci u32 cr0; 9708c2ecf20Sopenharmony_ci u32 cr1; 9718c2ecf20Sopenharmony_ci int err; 9728c2ecf20Sopenharmony_ci int dma_mapped; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* Check if we can DMA this transfer */ 9758c2ecf20Sopenharmony_ci if (transfer->len > MAX_DMA_LEN && chip->enable_dma) { 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* reject already-mapped transfers; PIO won't always work */ 9788c2ecf20Sopenharmony_ci if (message->is_dma_mapped 9798c2ecf20Sopenharmony_ci || transfer->rx_dma || transfer->tx_dma) { 9808c2ecf20Sopenharmony_ci dev_err(&spi->dev, 9818c2ecf20Sopenharmony_ci "Mapped transfer length of %u is greater than %d\n", 9828c2ecf20Sopenharmony_ci transfer->len, MAX_DMA_LEN); 9838c2ecf20Sopenharmony_ci return -EINVAL; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* warn ... we force this to PIO mode */ 9878c2ecf20Sopenharmony_ci dev_warn_ratelimited(&spi->dev, 9888c2ecf20Sopenharmony_ci "DMA disabled for transfer length %ld greater than %d\n", 9898c2ecf20Sopenharmony_ci (long)transfer->len, MAX_DMA_LEN); 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* Setup the transfer state based on the type of transfer */ 9938c2ecf20Sopenharmony_ci if (pxa2xx_spi_flush(drv_data) == 0) { 9948c2ecf20Sopenharmony_ci dev_err(&spi->dev, "Flush failed\n"); 9958c2ecf20Sopenharmony_ci return -EIO; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci drv_data->n_bytes = chip->n_bytes; 9988c2ecf20Sopenharmony_ci drv_data->tx = (void *)transfer->tx_buf; 9998c2ecf20Sopenharmony_ci drv_data->tx_end = drv_data->tx + transfer->len; 10008c2ecf20Sopenharmony_ci drv_data->rx = transfer->rx_buf; 10018c2ecf20Sopenharmony_ci drv_data->rx_end = drv_data->rx + transfer->len; 10028c2ecf20Sopenharmony_ci drv_data->write = drv_data->tx ? chip->write : null_writer; 10038c2ecf20Sopenharmony_ci drv_data->read = drv_data->rx ? chip->read : null_reader; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* Change speed and bit per word on a per transfer */ 10068c2ecf20Sopenharmony_ci bits = transfer->bits_per_word; 10078c2ecf20Sopenharmony_ci speed = transfer->speed_hz; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci clk_div = pxa2xx_ssp_get_clk_div(drv_data, speed); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (bits <= 8) { 10128c2ecf20Sopenharmony_ci drv_data->n_bytes = 1; 10138c2ecf20Sopenharmony_ci drv_data->read = drv_data->read != null_reader ? 10148c2ecf20Sopenharmony_ci u8_reader : null_reader; 10158c2ecf20Sopenharmony_ci drv_data->write = drv_data->write != null_writer ? 10168c2ecf20Sopenharmony_ci u8_writer : null_writer; 10178c2ecf20Sopenharmony_ci } else if (bits <= 16) { 10188c2ecf20Sopenharmony_ci drv_data->n_bytes = 2; 10198c2ecf20Sopenharmony_ci drv_data->read = drv_data->read != null_reader ? 10208c2ecf20Sopenharmony_ci u16_reader : null_reader; 10218c2ecf20Sopenharmony_ci drv_data->write = drv_data->write != null_writer ? 10228c2ecf20Sopenharmony_ci u16_writer : null_writer; 10238c2ecf20Sopenharmony_ci } else if (bits <= 32) { 10248c2ecf20Sopenharmony_ci drv_data->n_bytes = 4; 10258c2ecf20Sopenharmony_ci drv_data->read = drv_data->read != null_reader ? 10268c2ecf20Sopenharmony_ci u32_reader : null_reader; 10278c2ecf20Sopenharmony_ci drv_data->write = drv_data->write != null_writer ? 10288c2ecf20Sopenharmony_ci u32_writer : null_writer; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci /* 10318c2ecf20Sopenharmony_ci * if bits/word is changed in dma mode, then must check the 10328c2ecf20Sopenharmony_ci * thresholds and burst also 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_ci if (chip->enable_dma) { 10358c2ecf20Sopenharmony_ci if (pxa2xx_spi_set_dma_burst_and_threshold(chip, 10368c2ecf20Sopenharmony_ci spi, 10378c2ecf20Sopenharmony_ci bits, &dma_burst, 10388c2ecf20Sopenharmony_ci &dma_thresh)) 10398c2ecf20Sopenharmony_ci dev_warn_ratelimited(&spi->dev, 10408c2ecf20Sopenharmony_ci "DMA burst size reduced to match bits_per_word\n"); 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci dma_mapped = controller->can_dma && 10448c2ecf20Sopenharmony_ci controller->can_dma(controller, spi, transfer) && 10458c2ecf20Sopenharmony_ci controller->cur_msg_mapped; 10468c2ecf20Sopenharmony_ci if (dma_mapped) { 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci /* Ensure we have the correct interrupt handler */ 10498c2ecf20Sopenharmony_ci drv_data->transfer_handler = pxa2xx_spi_dma_transfer; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci err = pxa2xx_spi_dma_prepare(drv_data, transfer); 10528c2ecf20Sopenharmony_ci if (err) 10538c2ecf20Sopenharmony_ci return err; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci /* Clear status and start DMA engine */ 10568c2ecf20Sopenharmony_ci cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1; 10578c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSSR, drv_data->clear_sr); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci pxa2xx_spi_dma_start(drv_data); 10608c2ecf20Sopenharmony_ci } else { 10618c2ecf20Sopenharmony_ci /* Ensure we have the correct interrupt handler */ 10628c2ecf20Sopenharmony_ci drv_data->transfer_handler = interrupt_transfer; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* Clear status */ 10658c2ecf20Sopenharmony_ci cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1; 10668c2ecf20Sopenharmony_ci write_SSSR_CS(drv_data, drv_data->clear_sr); 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* NOTE: PXA25x_SSP _could_ use external clocking ... */ 10708c2ecf20Sopenharmony_ci cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits); 10718c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 10728c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "%u Hz actual, %s\n", 10738c2ecf20Sopenharmony_ci controller->max_speed_hz 10748c2ecf20Sopenharmony_ci / (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)), 10758c2ecf20Sopenharmony_ci dma_mapped ? "DMA" : "PIO"); 10768c2ecf20Sopenharmony_ci else 10778c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "%u Hz actual, %s\n", 10788c2ecf20Sopenharmony_ci controller->max_speed_hz / 2 10798c2ecf20Sopenharmony_ci / (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)), 10808c2ecf20Sopenharmony_ci dma_mapped ? "DMA" : "PIO"); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (is_lpss_ssp(drv_data)) { 10838c2ecf20Sopenharmony_ci if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff) 10848c2ecf20Sopenharmony_ci != chip->lpss_rx_threshold) 10858c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSIRF, 10868c2ecf20Sopenharmony_ci chip->lpss_rx_threshold); 10878c2ecf20Sopenharmony_ci if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff) 10888c2ecf20Sopenharmony_ci != chip->lpss_tx_threshold) 10898c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSITF, 10908c2ecf20Sopenharmony_ci chip->lpss_tx_threshold); 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (is_quark_x1000_ssp(drv_data) && 10948c2ecf20Sopenharmony_ci (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate)) 10958c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* see if we need to reload the config registers */ 10988c2ecf20Sopenharmony_ci if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0) 10998c2ecf20Sopenharmony_ci || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask) 11008c2ecf20Sopenharmony_ci != (cr1 & change_mask)) { 11018c2ecf20Sopenharmony_ci /* stop the SSP, and update the other bits */ 11028c2ecf20Sopenharmony_ci if (!is_mmp2_ssp(drv_data)) 11038c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE); 11048c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 11058c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, chip->timeout); 11068c2ecf20Sopenharmony_ci /* first set CR1 without interrupt and service enables */ 11078c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask); 11088c2ecf20Sopenharmony_ci /* restart the SSP */ 11098c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, cr0); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci } else { 11128c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 11138c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, chip->timeout); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci if (is_mmp2_ssp(drv_data)) { 11178c2ecf20Sopenharmony_ci u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR) 11188c2ecf20Sopenharmony_ci & SSSR_TFL_MASK) >> 8; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (tx_level) { 11218c2ecf20Sopenharmony_ci /* On MMP2, flipping SSE doesn't to empty TXFIFO. */ 11228c2ecf20Sopenharmony_ci dev_warn(&spi->dev, "%d bytes of garbage in TXFIFO!\n", 11238c2ecf20Sopenharmony_ci tx_level); 11248c2ecf20Sopenharmony_ci if (tx_level > transfer->len) 11258c2ecf20Sopenharmony_ci tx_level = transfer->len; 11268c2ecf20Sopenharmony_ci drv_data->tx += tx_level; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci if (spi_controller_is_slave(controller)) { 11318c2ecf20Sopenharmony_ci while (drv_data->write(drv_data)) 11328c2ecf20Sopenharmony_ci ; 11338c2ecf20Sopenharmony_ci if (drv_data->gpiod_ready) { 11348c2ecf20Sopenharmony_ci gpiod_set_value(drv_data->gpiod_ready, 1); 11358c2ecf20Sopenharmony_ci udelay(1); 11368c2ecf20Sopenharmony_ci gpiod_set_value(drv_data->gpiod_ready, 0); 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci /* 11418c2ecf20Sopenharmony_ci * Release the data by enabling service requests and interrupts, 11428c2ecf20Sopenharmony_ci * without changing any mode bits 11438c2ecf20Sopenharmony_ci */ 11448c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, cr1); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci return 1; 11478c2ecf20Sopenharmony_ci} 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic int pxa2xx_spi_slave_abort(struct spi_controller *controller) 11508c2ecf20Sopenharmony_ci{ 11518c2ecf20Sopenharmony_ci struct driver_data *drv_data = spi_controller_get_devdata(controller); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci /* Stop and reset SSP */ 11548c2ecf20Sopenharmony_ci write_SSSR_CS(drv_data, drv_data->clear_sr); 11558c2ecf20Sopenharmony_ci reset_sccr1(drv_data); 11568c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 11578c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, 0); 11588c2ecf20Sopenharmony_ci pxa2xx_spi_flush(drv_data); 11598c2ecf20Sopenharmony_ci pxa2xx_spi_off(drv_data); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci dev_dbg(&drv_data->pdev->dev, "transfer aborted\n"); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci drv_data->controller->cur_msg->status = -EINTR; 11648c2ecf20Sopenharmony_ci spi_finalize_current_transfer(drv_data->controller); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci return 0; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_cistatic void pxa2xx_spi_handle_err(struct spi_controller *controller, 11708c2ecf20Sopenharmony_ci struct spi_message *msg) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci struct driver_data *drv_data = spi_controller_get_devdata(controller); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* Disable the SSP */ 11758c2ecf20Sopenharmony_ci pxa2xx_spi_off(drv_data); 11768c2ecf20Sopenharmony_ci /* Clear and disable interrupts and service requests */ 11778c2ecf20Sopenharmony_ci write_SSSR_CS(drv_data, drv_data->clear_sr); 11788c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, 11798c2ecf20Sopenharmony_ci pxa2xx_spi_read(drv_data, SSCR1) 11808c2ecf20Sopenharmony_ci & ~(drv_data->int_cr1 | drv_data->dma_cr1)); 11818c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 11828c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, 0); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci /* 11858c2ecf20Sopenharmony_ci * Stop the DMA if running. Note DMA callback handler may have unset 11868c2ecf20Sopenharmony_ci * the dma_running already, which is fine as stopping is not needed 11878c2ecf20Sopenharmony_ci * then but we shouldn't rely this flag for anything else than 11888c2ecf20Sopenharmony_ci * stopping. For instance to differentiate between PIO and DMA 11898c2ecf20Sopenharmony_ci * transfers. 11908c2ecf20Sopenharmony_ci */ 11918c2ecf20Sopenharmony_ci if (atomic_read(&drv_data->dma_running)) 11928c2ecf20Sopenharmony_ci pxa2xx_spi_dma_stop(drv_data); 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci struct driver_data *drv_data = spi_controller_get_devdata(controller); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Disable the SSP now */ 12008c2ecf20Sopenharmony_ci pxa2xx_spi_off(drv_data); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci return 0; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_cistatic int setup_cs(struct spi_device *spi, struct chip_data *chip, 12068c2ecf20Sopenharmony_ci struct pxa2xx_spi_chip *chip_info) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci struct driver_data *drv_data = 12098c2ecf20Sopenharmony_ci spi_controller_get_devdata(spi->controller); 12108c2ecf20Sopenharmony_ci struct gpio_desc *gpiod; 12118c2ecf20Sopenharmony_ci int err = 0; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (chip == NULL) 12148c2ecf20Sopenharmony_ci return 0; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (drv_data->cs_gpiods) { 12178c2ecf20Sopenharmony_ci gpiod = drv_data->cs_gpiods[spi->chip_select]; 12188c2ecf20Sopenharmony_ci if (gpiod) { 12198c2ecf20Sopenharmony_ci chip->gpiod_cs = gpiod; 12208c2ecf20Sopenharmony_ci chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; 12218c2ecf20Sopenharmony_ci gpiod_set_value(gpiod, chip->gpio_cs_inverted); 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci return 0; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (chip_info == NULL) 12288c2ecf20Sopenharmony_ci return 0; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* NOTE: setup() can be called multiple times, possibly with 12318c2ecf20Sopenharmony_ci * different chip_info, release previously requested GPIO 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_ci if (chip->gpiod_cs) { 12348c2ecf20Sopenharmony_ci gpiod_put(chip->gpiod_cs); 12358c2ecf20Sopenharmony_ci chip->gpiod_cs = NULL; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* If (*cs_control) is provided, ignore GPIO chip select */ 12398c2ecf20Sopenharmony_ci if (chip_info->cs_control) { 12408c2ecf20Sopenharmony_ci chip->cs_control = chip_info->cs_control; 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci if (gpio_is_valid(chip_info->gpio_cs)) { 12458c2ecf20Sopenharmony_ci err = gpio_request(chip_info->gpio_cs, "SPI_CS"); 12468c2ecf20Sopenharmony_ci if (err) { 12478c2ecf20Sopenharmony_ci dev_err(&spi->dev, "failed to request chip select GPIO%d\n", 12488c2ecf20Sopenharmony_ci chip_info->gpio_cs); 12498c2ecf20Sopenharmony_ci return err; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci gpiod = gpio_to_desc(chip_info->gpio_cs); 12538c2ecf20Sopenharmony_ci chip->gpiod_cs = gpiod; 12548c2ecf20Sopenharmony_ci chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci err = gpiod_direction_output(gpiod, !chip->gpio_cs_inverted); 12578c2ecf20Sopenharmony_ci if (err) 12588c2ecf20Sopenharmony_ci gpiod_put(chip->gpiod_cs); 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci return err; 12628c2ecf20Sopenharmony_ci} 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_cistatic int setup(struct spi_device *spi) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci struct pxa2xx_spi_chip *chip_info; 12678c2ecf20Sopenharmony_ci struct chip_data *chip; 12688c2ecf20Sopenharmony_ci const struct lpss_config *config; 12698c2ecf20Sopenharmony_ci struct driver_data *drv_data = 12708c2ecf20Sopenharmony_ci spi_controller_get_devdata(spi->controller); 12718c2ecf20Sopenharmony_ci uint tx_thres, tx_hi_thres, rx_thres; 12728c2ecf20Sopenharmony_ci int err; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 12758c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 12768c2ecf20Sopenharmony_ci tx_thres = TX_THRESH_QUARK_X1000_DFLT; 12778c2ecf20Sopenharmony_ci tx_hi_thres = 0; 12788c2ecf20Sopenharmony_ci rx_thres = RX_THRESH_QUARK_X1000_DFLT; 12798c2ecf20Sopenharmony_ci break; 12808c2ecf20Sopenharmony_ci case CE4100_SSP: 12818c2ecf20Sopenharmony_ci tx_thres = TX_THRESH_CE4100_DFLT; 12828c2ecf20Sopenharmony_ci tx_hi_thres = 0; 12838c2ecf20Sopenharmony_ci rx_thres = RX_THRESH_CE4100_DFLT; 12848c2ecf20Sopenharmony_ci break; 12858c2ecf20Sopenharmony_ci case LPSS_LPT_SSP: 12868c2ecf20Sopenharmony_ci case LPSS_BYT_SSP: 12878c2ecf20Sopenharmony_ci case LPSS_BSW_SSP: 12888c2ecf20Sopenharmony_ci case LPSS_SPT_SSP: 12898c2ecf20Sopenharmony_ci case LPSS_BXT_SSP: 12908c2ecf20Sopenharmony_ci case LPSS_CNL_SSP: 12918c2ecf20Sopenharmony_ci config = lpss_get_config(drv_data); 12928c2ecf20Sopenharmony_ci tx_thres = config->tx_threshold_lo; 12938c2ecf20Sopenharmony_ci tx_hi_thres = config->tx_threshold_hi; 12948c2ecf20Sopenharmony_ci rx_thres = config->rx_threshold; 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci default: 12978c2ecf20Sopenharmony_ci tx_hi_thres = 0; 12988c2ecf20Sopenharmony_ci if (spi_controller_is_slave(drv_data->controller)) { 12998c2ecf20Sopenharmony_ci tx_thres = 1; 13008c2ecf20Sopenharmony_ci rx_thres = 2; 13018c2ecf20Sopenharmony_ci } else { 13028c2ecf20Sopenharmony_ci tx_thres = TX_THRESH_DFLT; 13038c2ecf20Sopenharmony_ci rx_thres = RX_THRESH_DFLT; 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci break; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* Only alloc on first setup */ 13098c2ecf20Sopenharmony_ci chip = spi_get_ctldata(spi); 13108c2ecf20Sopenharmony_ci if (!chip) { 13118c2ecf20Sopenharmony_ci chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); 13128c2ecf20Sopenharmony_ci if (!chip) 13138c2ecf20Sopenharmony_ci return -ENOMEM; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (drv_data->ssp_type == CE4100_SSP) { 13168c2ecf20Sopenharmony_ci if (spi->chip_select > 4) { 13178c2ecf20Sopenharmony_ci dev_err(&spi->dev, 13188c2ecf20Sopenharmony_ci "failed setup: cs number must not be > 4.\n"); 13198c2ecf20Sopenharmony_ci kfree(chip); 13208c2ecf20Sopenharmony_ci return -EINVAL; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci chip->frm = spi->chip_select; 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci chip->enable_dma = drv_data->controller_info->enable_dma; 13268c2ecf20Sopenharmony_ci chip->timeout = TIMOUT_DFLT; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci /* protocol drivers may change the chip settings, so... 13308c2ecf20Sopenharmony_ci * if chip_info exists, use it */ 13318c2ecf20Sopenharmony_ci chip_info = spi->controller_data; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci /* chip_info isn't always needed */ 13348c2ecf20Sopenharmony_ci chip->cr1 = 0; 13358c2ecf20Sopenharmony_ci if (chip_info) { 13368c2ecf20Sopenharmony_ci if (chip_info->timeout) 13378c2ecf20Sopenharmony_ci chip->timeout = chip_info->timeout; 13388c2ecf20Sopenharmony_ci if (chip_info->tx_threshold) 13398c2ecf20Sopenharmony_ci tx_thres = chip_info->tx_threshold; 13408c2ecf20Sopenharmony_ci if (chip_info->tx_hi_threshold) 13418c2ecf20Sopenharmony_ci tx_hi_thres = chip_info->tx_hi_threshold; 13428c2ecf20Sopenharmony_ci if (chip_info->rx_threshold) 13438c2ecf20Sopenharmony_ci rx_thres = chip_info->rx_threshold; 13448c2ecf20Sopenharmony_ci chip->dma_threshold = 0; 13458c2ecf20Sopenharmony_ci if (chip_info->enable_loopback) 13468c2ecf20Sopenharmony_ci chip->cr1 = SSCR1_LBM; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci if (spi_controller_is_slave(drv_data->controller)) { 13498c2ecf20Sopenharmony_ci chip->cr1 |= SSCR1_SCFR; 13508c2ecf20Sopenharmony_ci chip->cr1 |= SSCR1_SCLKDIR; 13518c2ecf20Sopenharmony_ci chip->cr1 |= SSCR1_SFRMDIR; 13528c2ecf20Sopenharmony_ci chip->cr1 |= SSCR1_SPH; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres); 13568c2ecf20Sopenharmony_ci chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres) 13578c2ecf20Sopenharmony_ci | SSITF_TxHiThresh(tx_hi_thres); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* set dma burst and threshold outside of chip_info path so that if 13608c2ecf20Sopenharmony_ci * chip_info goes away after setting chip->enable_dma, the 13618c2ecf20Sopenharmony_ci * burst and threshold can still respond to changes in bits_per_word */ 13628c2ecf20Sopenharmony_ci if (chip->enable_dma) { 13638c2ecf20Sopenharmony_ci /* set up legal burst and threshold for dma */ 13648c2ecf20Sopenharmony_ci if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi, 13658c2ecf20Sopenharmony_ci spi->bits_per_word, 13668c2ecf20Sopenharmony_ci &chip->dma_burst_size, 13678c2ecf20Sopenharmony_ci &chip->dma_threshold)) { 13688c2ecf20Sopenharmony_ci dev_warn(&spi->dev, 13698c2ecf20Sopenharmony_ci "in setup: DMA burst size reduced to match bits_per_word\n"); 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, 13728c2ecf20Sopenharmony_ci "in setup: DMA burst size set to %u\n", 13738c2ecf20Sopenharmony_ci chip->dma_burst_size); 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 13778c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 13788c2ecf20Sopenharmony_ci chip->threshold = (QUARK_X1000_SSCR1_RxTresh(rx_thres) 13798c2ecf20Sopenharmony_ci & QUARK_X1000_SSCR1_RFT) 13808c2ecf20Sopenharmony_ci | (QUARK_X1000_SSCR1_TxTresh(tx_thres) 13818c2ecf20Sopenharmony_ci & QUARK_X1000_SSCR1_TFT); 13828c2ecf20Sopenharmony_ci break; 13838c2ecf20Sopenharmony_ci case CE4100_SSP: 13848c2ecf20Sopenharmony_ci chip->threshold = (CE4100_SSCR1_RxTresh(rx_thres) & CE4100_SSCR1_RFT) | 13858c2ecf20Sopenharmony_ci (CE4100_SSCR1_TxTresh(tx_thres) & CE4100_SSCR1_TFT); 13868c2ecf20Sopenharmony_ci break; 13878c2ecf20Sopenharmony_ci default: 13888c2ecf20Sopenharmony_ci chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) | 13898c2ecf20Sopenharmony_ci (SSCR1_TxTresh(tx_thres) & SSCR1_TFT); 13908c2ecf20Sopenharmony_ci break; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH); 13948c2ecf20Sopenharmony_ci chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0) 13958c2ecf20Sopenharmony_ci | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (spi->mode & SPI_LOOP) 13988c2ecf20Sopenharmony_ci chip->cr1 |= SSCR1_LBM; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (spi->bits_per_word <= 8) { 14018c2ecf20Sopenharmony_ci chip->n_bytes = 1; 14028c2ecf20Sopenharmony_ci chip->read = u8_reader; 14038c2ecf20Sopenharmony_ci chip->write = u8_writer; 14048c2ecf20Sopenharmony_ci } else if (spi->bits_per_word <= 16) { 14058c2ecf20Sopenharmony_ci chip->n_bytes = 2; 14068c2ecf20Sopenharmony_ci chip->read = u16_reader; 14078c2ecf20Sopenharmony_ci chip->write = u16_writer; 14088c2ecf20Sopenharmony_ci } else if (spi->bits_per_word <= 32) { 14098c2ecf20Sopenharmony_ci chip->n_bytes = 4; 14108c2ecf20Sopenharmony_ci chip->read = u32_reader; 14118c2ecf20Sopenharmony_ci chip->write = u32_writer; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci spi_set_ctldata(spi, chip); 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci if (drv_data->ssp_type == CE4100_SSP) 14178c2ecf20Sopenharmony_ci return 0; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci err = setup_cs(spi, chip, chip_info); 14208c2ecf20Sopenharmony_ci if (err) 14218c2ecf20Sopenharmony_ci kfree(chip); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci return err; 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_cistatic void cleanup(struct spi_device *spi) 14278c2ecf20Sopenharmony_ci{ 14288c2ecf20Sopenharmony_ci struct chip_data *chip = spi_get_ctldata(spi); 14298c2ecf20Sopenharmony_ci struct driver_data *drv_data = 14308c2ecf20Sopenharmony_ci spi_controller_get_devdata(spi->controller); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (!chip) 14338c2ecf20Sopenharmony_ci return; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods && 14368c2ecf20Sopenharmony_ci chip->gpiod_cs) 14378c2ecf20Sopenharmony_ci gpiod_put(chip->gpiod_cs); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci kfree(chip); 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 14438c2ecf20Sopenharmony_cistatic const struct acpi_device_id pxa2xx_spi_acpi_match[] = { 14448c2ecf20Sopenharmony_ci { "INT33C0", LPSS_LPT_SSP }, 14458c2ecf20Sopenharmony_ci { "INT33C1", LPSS_LPT_SSP }, 14468c2ecf20Sopenharmony_ci { "INT3430", LPSS_LPT_SSP }, 14478c2ecf20Sopenharmony_ci { "INT3431", LPSS_LPT_SSP }, 14488c2ecf20Sopenharmony_ci { "80860F0E", LPSS_BYT_SSP }, 14498c2ecf20Sopenharmony_ci { "8086228E", LPSS_BSW_SSP }, 14508c2ecf20Sopenharmony_ci { }, 14518c2ecf20Sopenharmony_ci}; 14528c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); 14538c2ecf20Sopenharmony_ci#endif 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci/* 14568c2ecf20Sopenharmony_ci * PCI IDs of compound devices that integrate both host controller and private 14578c2ecf20Sopenharmony_ci * integrated DMA engine. Please note these are not used in module 14588c2ecf20Sopenharmony_ci * autoloading and probing in this module but matching the LPSS SSP type. 14598c2ecf20Sopenharmony_ci */ 14608c2ecf20Sopenharmony_cistatic const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { 14618c2ecf20Sopenharmony_ci /* SPT-LP */ 14628c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x9d29), LPSS_SPT_SSP }, 14638c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x9d2a), LPSS_SPT_SSP }, 14648c2ecf20Sopenharmony_ci /* SPT-H */ 14658c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP }, 14668c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP }, 14678c2ecf20Sopenharmony_ci /* KBL-H */ 14688c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa2a9), LPSS_SPT_SSP }, 14698c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa2aa), LPSS_SPT_SSP }, 14708c2ecf20Sopenharmony_ci /* CML-V */ 14718c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa3a9), LPSS_SPT_SSP }, 14728c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa3aa), LPSS_SPT_SSP }, 14738c2ecf20Sopenharmony_ci /* BXT A-Step */ 14748c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x0ac2), LPSS_BXT_SSP }, 14758c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x0ac4), LPSS_BXT_SSP }, 14768c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x0ac6), LPSS_BXT_SSP }, 14778c2ecf20Sopenharmony_ci /* BXT B-Step */ 14788c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x1ac2), LPSS_BXT_SSP }, 14798c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x1ac4), LPSS_BXT_SSP }, 14808c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x1ac6), LPSS_BXT_SSP }, 14818c2ecf20Sopenharmony_ci /* GLK */ 14828c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x31c2), LPSS_BXT_SSP }, 14838c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP }, 14848c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x31c6), LPSS_BXT_SSP }, 14858c2ecf20Sopenharmony_ci /* ICL-LP */ 14868c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x34aa), LPSS_CNL_SSP }, 14878c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x34ab), LPSS_CNL_SSP }, 14888c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x34fb), LPSS_CNL_SSP }, 14898c2ecf20Sopenharmony_ci /* EHL */ 14908c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x4b2a), LPSS_BXT_SSP }, 14918c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x4b2b), LPSS_BXT_SSP }, 14928c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x4b37), LPSS_BXT_SSP }, 14938c2ecf20Sopenharmony_ci /* JSL */ 14948c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x4daa), LPSS_CNL_SSP }, 14958c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x4dab), LPSS_CNL_SSP }, 14968c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x4dfb), LPSS_CNL_SSP }, 14978c2ecf20Sopenharmony_ci /* TGL-H */ 14988c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x43aa), LPSS_CNL_SSP }, 14998c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x43ab), LPSS_CNL_SSP }, 15008c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x43fb), LPSS_CNL_SSP }, 15018c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x43fd), LPSS_CNL_SSP }, 15028c2ecf20Sopenharmony_ci /* APL */ 15038c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, 15048c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, 15058c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x5ac6), LPSS_BXT_SSP }, 15068c2ecf20Sopenharmony_ci /* CNL-LP */ 15078c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP }, 15088c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP }, 15098c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x9dfb), LPSS_CNL_SSP }, 15108c2ecf20Sopenharmony_ci /* CNL-H */ 15118c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa32a), LPSS_CNL_SSP }, 15128c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa32b), LPSS_CNL_SSP }, 15138c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa37b), LPSS_CNL_SSP }, 15148c2ecf20Sopenharmony_ci /* CML-LP */ 15158c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x02aa), LPSS_CNL_SSP }, 15168c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x02ab), LPSS_CNL_SSP }, 15178c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x02fb), LPSS_CNL_SSP }, 15188c2ecf20Sopenharmony_ci /* CML-H */ 15198c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x06aa), LPSS_CNL_SSP }, 15208c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x06ab), LPSS_CNL_SSP }, 15218c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0x06fb), LPSS_CNL_SSP }, 15228c2ecf20Sopenharmony_ci /* TGL-LP */ 15238c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa0aa), LPSS_CNL_SSP }, 15248c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa0ab), LPSS_CNL_SSP }, 15258c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa0de), LPSS_CNL_SSP }, 15268c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa0df), LPSS_CNL_SSP }, 15278c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa0fb), LPSS_CNL_SSP }, 15288c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa0fd), LPSS_CNL_SSP }, 15298c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, 0xa0fe), LPSS_CNL_SSP }, 15308c2ecf20Sopenharmony_ci { }, 15318c2ecf20Sopenharmony_ci}; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic const struct of_device_id pxa2xx_spi_of_match[] = { 15348c2ecf20Sopenharmony_ci { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP }, 15358c2ecf20Sopenharmony_ci {}, 15368c2ecf20Sopenharmony_ci}; 15378c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_cistatic int pxa2xx_spi_get_port_id(struct device *dev) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci struct acpi_device *adev; 15448c2ecf20Sopenharmony_ci unsigned int devid; 15458c2ecf20Sopenharmony_ci int port_id = -1; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci adev = ACPI_COMPANION(dev); 15488c2ecf20Sopenharmony_ci if (adev && adev->pnp.unique_id && 15498c2ecf20Sopenharmony_ci !kstrtouint(adev->pnp.unique_id, 0, &devid)) 15508c2ecf20Sopenharmony_ci port_id = devid; 15518c2ecf20Sopenharmony_ci return port_id; 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci#else /* !CONFIG_ACPI */ 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_cistatic int pxa2xx_spi_get_port_id(struct device *dev) 15578c2ecf20Sopenharmony_ci{ 15588c2ecf20Sopenharmony_ci return -1; 15598c2ecf20Sopenharmony_ci} 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */ 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_cistatic bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) 15678c2ecf20Sopenharmony_ci{ 15688c2ecf20Sopenharmony_ci return param == chan->device->dev; 15698c2ecf20Sopenharmony_ci} 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_cistatic struct pxa2xx_spi_controller * 15748c2ecf20Sopenharmony_cipxa2xx_spi_init_pdata(struct platform_device *pdev) 15758c2ecf20Sopenharmony_ci{ 15768c2ecf20Sopenharmony_ci struct pxa2xx_spi_controller *pdata; 15778c2ecf20Sopenharmony_ci struct ssp_device *ssp; 15788c2ecf20Sopenharmony_ci struct resource *res; 15798c2ecf20Sopenharmony_ci struct device *parent = pdev->dev.parent; 15808c2ecf20Sopenharmony_ci struct pci_dev *pcidev = dev_is_pci(parent) ? to_pci_dev(parent) : NULL; 15818c2ecf20Sopenharmony_ci const struct pci_device_id *pcidev_id = NULL; 15828c2ecf20Sopenharmony_ci enum pxa_ssp_type type; 15838c2ecf20Sopenharmony_ci const void *match; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci if (pcidev) 15868c2ecf20Sopenharmony_ci pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, pcidev); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci match = device_get_match_data(&pdev->dev); 15898c2ecf20Sopenharmony_ci if (match) 15908c2ecf20Sopenharmony_ci type = (enum pxa_ssp_type)match; 15918c2ecf20Sopenharmony_ci else if (pcidev_id) 15928c2ecf20Sopenharmony_ci type = (enum pxa_ssp_type)pcidev_id->driver_data; 15938c2ecf20Sopenharmony_ci else 15948c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 15978c2ecf20Sopenharmony_ci if (!pdata) 15988c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci ssp = &pdata->ssp; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 16038c2ecf20Sopenharmony_ci ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res); 16048c2ecf20Sopenharmony_ci if (IS_ERR(ssp->mmio_base)) 16058c2ecf20Sopenharmony_ci return ERR_CAST(ssp->mmio_base); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci ssp->phys_base = res->start; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 16108c2ecf20Sopenharmony_ci if (pcidev_id) { 16118c2ecf20Sopenharmony_ci pdata->tx_param = parent; 16128c2ecf20Sopenharmony_ci pdata->rx_param = parent; 16138c2ecf20Sopenharmony_ci pdata->dma_filter = pxa2xx_spi_idma_filter; 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci#endif 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci ssp->clk = devm_clk_get(&pdev->dev, NULL); 16188c2ecf20Sopenharmony_ci if (IS_ERR(ssp->clk)) 16198c2ecf20Sopenharmony_ci return ERR_CAST(ssp->clk); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci ssp->irq = platform_get_irq(pdev, 0); 16228c2ecf20Sopenharmony_ci if (ssp->irq < 0) 16238c2ecf20Sopenharmony_ci return ERR_PTR(ssp->irq); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci ssp->type = type; 16268c2ecf20Sopenharmony_ci ssp->dev = &pdev->dev; 16278c2ecf20Sopenharmony_ci ssp->port_id = pxa2xx_spi_get_port_id(&pdev->dev); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci pdata->is_slave = device_property_read_bool(&pdev->dev, "spi-slave"); 16308c2ecf20Sopenharmony_ci pdata->num_chipselect = 1; 16318c2ecf20Sopenharmony_ci pdata->enable_dma = true; 16328c2ecf20Sopenharmony_ci pdata->dma_burst_size = 1; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci return pdata; 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_cistatic int pxa2xx_spi_fw_translate_cs(struct spi_controller *controller, 16388c2ecf20Sopenharmony_ci unsigned int cs) 16398c2ecf20Sopenharmony_ci{ 16408c2ecf20Sopenharmony_ci struct driver_data *drv_data = spi_controller_get_devdata(controller); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (has_acpi_companion(&drv_data->pdev->dev)) { 16438c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 16448c2ecf20Sopenharmony_ci /* 16458c2ecf20Sopenharmony_ci * For Atoms the ACPI DeviceSelection used by the Windows 16468c2ecf20Sopenharmony_ci * driver starts from 1 instead of 0 so translate it here 16478c2ecf20Sopenharmony_ci * to match what Linux expects. 16488c2ecf20Sopenharmony_ci */ 16498c2ecf20Sopenharmony_ci case LPSS_BYT_SSP: 16508c2ecf20Sopenharmony_ci case LPSS_BSW_SSP: 16518c2ecf20Sopenharmony_ci return cs - 1; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci default: 16548c2ecf20Sopenharmony_ci break; 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci return cs; 16598c2ecf20Sopenharmony_ci} 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_cistatic size_t pxa2xx_spi_max_dma_transfer_size(struct spi_device *spi) 16628c2ecf20Sopenharmony_ci{ 16638c2ecf20Sopenharmony_ci return MAX_DMA_LEN; 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_cistatic int pxa2xx_spi_probe(struct platform_device *pdev) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 16698c2ecf20Sopenharmony_ci struct pxa2xx_spi_controller *platform_info; 16708c2ecf20Sopenharmony_ci struct spi_controller *controller; 16718c2ecf20Sopenharmony_ci struct driver_data *drv_data; 16728c2ecf20Sopenharmony_ci struct ssp_device *ssp; 16738c2ecf20Sopenharmony_ci const struct lpss_config *config; 16748c2ecf20Sopenharmony_ci int status, count; 16758c2ecf20Sopenharmony_ci u32 tmp; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci platform_info = dev_get_platdata(dev); 16788c2ecf20Sopenharmony_ci if (!platform_info) { 16798c2ecf20Sopenharmony_ci platform_info = pxa2xx_spi_init_pdata(pdev); 16808c2ecf20Sopenharmony_ci if (IS_ERR(platform_info)) { 16818c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "missing platform data\n"); 16828c2ecf20Sopenharmony_ci return PTR_ERR(platform_info); 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci ssp = pxa_ssp_request(pdev->id, pdev->name); 16878c2ecf20Sopenharmony_ci if (!ssp) 16888c2ecf20Sopenharmony_ci ssp = &platform_info->ssp; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (!ssp->mmio_base) { 16918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get ssp\n"); 16928c2ecf20Sopenharmony_ci return -ENODEV; 16938c2ecf20Sopenharmony_ci } 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if (platform_info->is_slave) 16968c2ecf20Sopenharmony_ci controller = devm_spi_alloc_slave(dev, sizeof(*drv_data)); 16978c2ecf20Sopenharmony_ci else 16988c2ecf20Sopenharmony_ci controller = devm_spi_alloc_master(dev, sizeof(*drv_data)); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci if (!controller) { 17018c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot alloc spi_controller\n"); 17028c2ecf20Sopenharmony_ci pxa_ssp_free(ssp); 17038c2ecf20Sopenharmony_ci return -ENOMEM; 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci drv_data = spi_controller_get_devdata(controller); 17068c2ecf20Sopenharmony_ci drv_data->controller = controller; 17078c2ecf20Sopenharmony_ci drv_data->controller_info = platform_info; 17088c2ecf20Sopenharmony_ci drv_data->pdev = pdev; 17098c2ecf20Sopenharmony_ci drv_data->ssp = ssp; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci controller->dev.of_node = pdev->dev.of_node; 17128c2ecf20Sopenharmony_ci /* the spi->mode bits understood by this driver: */ 17138c2ecf20Sopenharmony_ci controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci controller->bus_num = ssp->port_id; 17168c2ecf20Sopenharmony_ci controller->dma_alignment = DMA_ALIGNMENT; 17178c2ecf20Sopenharmony_ci controller->cleanup = cleanup; 17188c2ecf20Sopenharmony_ci controller->setup = setup; 17198c2ecf20Sopenharmony_ci controller->set_cs = pxa2xx_spi_set_cs; 17208c2ecf20Sopenharmony_ci controller->transfer_one = pxa2xx_spi_transfer_one; 17218c2ecf20Sopenharmony_ci controller->slave_abort = pxa2xx_spi_slave_abort; 17228c2ecf20Sopenharmony_ci controller->handle_err = pxa2xx_spi_handle_err; 17238c2ecf20Sopenharmony_ci controller->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer; 17248c2ecf20Sopenharmony_ci controller->fw_translate_cs = pxa2xx_spi_fw_translate_cs; 17258c2ecf20Sopenharmony_ci controller->auto_runtime_pm = true; 17268c2ecf20Sopenharmony_ci controller->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci drv_data->ssp_type = ssp->type; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci drv_data->ioaddr = ssp->mmio_base; 17318c2ecf20Sopenharmony_ci drv_data->ssdr_physical = ssp->phys_base + SSDR; 17328c2ecf20Sopenharmony_ci if (pxa25x_ssp_comp(drv_data)) { 17338c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 17348c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 17358c2ecf20Sopenharmony_ci controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 17368c2ecf20Sopenharmony_ci break; 17378c2ecf20Sopenharmony_ci default: 17388c2ecf20Sopenharmony_ci controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); 17398c2ecf20Sopenharmony_ci break; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE; 17438c2ecf20Sopenharmony_ci drv_data->dma_cr1 = 0; 17448c2ecf20Sopenharmony_ci drv_data->clear_sr = SSSR_ROR; 17458c2ecf20Sopenharmony_ci drv_data->mask_sr = SSSR_RFS | SSSR_TFS | SSSR_ROR; 17468c2ecf20Sopenharmony_ci } else { 17478c2ecf20Sopenharmony_ci controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 17488c2ecf20Sopenharmony_ci drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE; 17498c2ecf20Sopenharmony_ci drv_data->dma_cr1 = DEFAULT_DMA_CR1; 17508c2ecf20Sopenharmony_ci drv_data->clear_sr = SSSR_ROR | SSSR_TINT; 17518c2ecf20Sopenharmony_ci drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS 17528c2ecf20Sopenharmony_ci | SSSR_ROR | SSSR_TUR; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev), 17568c2ecf20Sopenharmony_ci drv_data); 17578c2ecf20Sopenharmony_ci if (status < 0) { 17588c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq); 17598c2ecf20Sopenharmony_ci goto out_error_controller_alloc; 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci /* Setup DMA if requested */ 17638c2ecf20Sopenharmony_ci if (platform_info->enable_dma) { 17648c2ecf20Sopenharmony_ci status = pxa2xx_spi_dma_setup(drv_data); 17658c2ecf20Sopenharmony_ci if (status) { 17668c2ecf20Sopenharmony_ci dev_warn(dev, "no DMA channels available, using PIO\n"); 17678c2ecf20Sopenharmony_ci platform_info->enable_dma = false; 17688c2ecf20Sopenharmony_ci } else { 17698c2ecf20Sopenharmony_ci controller->can_dma = pxa2xx_spi_can_dma; 17708c2ecf20Sopenharmony_ci controller->max_dma_len = MAX_DMA_LEN; 17718c2ecf20Sopenharmony_ci controller->max_transfer_size = 17728c2ecf20Sopenharmony_ci pxa2xx_spi_max_dma_transfer_size; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci } 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci /* Enable SOC clock */ 17778c2ecf20Sopenharmony_ci status = clk_prepare_enable(ssp->clk); 17788c2ecf20Sopenharmony_ci if (status) 17798c2ecf20Sopenharmony_ci goto out_error_dma_irq_alloc; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci controller->max_speed_hz = clk_get_rate(ssp->clk); 17828c2ecf20Sopenharmony_ci /* 17838c2ecf20Sopenharmony_ci * Set minimum speed for all other platforms than Intel Quark which is 17848c2ecf20Sopenharmony_ci * able do under 1 Hz transfers. 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 17878c2ecf20Sopenharmony_ci controller->min_speed_hz = 17888c2ecf20Sopenharmony_ci DIV_ROUND_UP(controller->max_speed_hz, 4096); 17898c2ecf20Sopenharmony_ci else if (!is_quark_x1000_ssp(drv_data)) 17908c2ecf20Sopenharmony_ci controller->min_speed_hz = 17918c2ecf20Sopenharmony_ci DIV_ROUND_UP(controller->max_speed_hz, 512); 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci /* Load default SSP configuration */ 17948c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, 0); 17958c2ecf20Sopenharmony_ci switch (drv_data->ssp_type) { 17968c2ecf20Sopenharmony_ci case QUARK_X1000_SSP: 17978c2ecf20Sopenharmony_ci tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT) | 17988c2ecf20Sopenharmony_ci QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT); 17998c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, tmp); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci /* using the Motorola SPI protocol and use 8 bit frame */ 18028c2ecf20Sopenharmony_ci tmp = QUARK_X1000_SSCR0_Motorola | QUARK_X1000_SSCR0_DataSize(8); 18038c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, tmp); 18048c2ecf20Sopenharmony_ci break; 18058c2ecf20Sopenharmony_ci case CE4100_SSP: 18068c2ecf20Sopenharmony_ci tmp = CE4100_SSCR1_RxTresh(RX_THRESH_CE4100_DFLT) | 18078c2ecf20Sopenharmony_ci CE4100_SSCR1_TxTresh(TX_THRESH_CE4100_DFLT); 18088c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, tmp); 18098c2ecf20Sopenharmony_ci tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8); 18108c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, tmp); 18118c2ecf20Sopenharmony_ci break; 18128c2ecf20Sopenharmony_ci default: 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci if (spi_controller_is_slave(controller)) { 18158c2ecf20Sopenharmony_ci tmp = SSCR1_SCFR | 18168c2ecf20Sopenharmony_ci SSCR1_SCLKDIR | 18178c2ecf20Sopenharmony_ci SSCR1_SFRMDIR | 18188c2ecf20Sopenharmony_ci SSCR1_RxTresh(2) | 18198c2ecf20Sopenharmony_ci SSCR1_TxTresh(1) | 18208c2ecf20Sopenharmony_ci SSCR1_SPH; 18218c2ecf20Sopenharmony_ci } else { 18228c2ecf20Sopenharmony_ci tmp = SSCR1_RxTresh(RX_THRESH_DFLT) | 18238c2ecf20Sopenharmony_ci SSCR1_TxTresh(TX_THRESH_DFLT); 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR1, tmp); 18268c2ecf20Sopenharmony_ci tmp = SSCR0_Motorola | SSCR0_DataSize(8); 18278c2ecf20Sopenharmony_ci if (!spi_controller_is_slave(controller)) 18288c2ecf20Sopenharmony_ci tmp |= SSCR0_SCR(2); 18298c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, tmp); 18308c2ecf20Sopenharmony_ci break; 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci if (!pxa25x_ssp_comp(drv_data)) 18348c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSTO, 0); 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci if (!is_quark_x1000_ssp(drv_data)) 18378c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSPSP, 0); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (is_lpss_ssp(drv_data)) { 18408c2ecf20Sopenharmony_ci lpss_ssp_setup(drv_data); 18418c2ecf20Sopenharmony_ci config = lpss_get_config(drv_data); 18428c2ecf20Sopenharmony_ci if (config->reg_capabilities >= 0) { 18438c2ecf20Sopenharmony_ci tmp = __lpss_ssp_read_priv(drv_data, 18448c2ecf20Sopenharmony_ci config->reg_capabilities); 18458c2ecf20Sopenharmony_ci tmp &= LPSS_CAPS_CS_EN_MASK; 18468c2ecf20Sopenharmony_ci tmp >>= LPSS_CAPS_CS_EN_SHIFT; 18478c2ecf20Sopenharmony_ci platform_info->num_chipselect = ffz(tmp); 18488c2ecf20Sopenharmony_ci } else if (config->cs_num) { 18498c2ecf20Sopenharmony_ci platform_info->num_chipselect = config->cs_num; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci controller->num_chipselect = platform_info->num_chipselect; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci count = gpiod_count(&pdev->dev, "cs"); 18558c2ecf20Sopenharmony_ci if (count > 0) { 18568c2ecf20Sopenharmony_ci int i; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci controller->num_chipselect = max_t(int, count, 18598c2ecf20Sopenharmony_ci controller->num_chipselect); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci drv_data->cs_gpiods = devm_kcalloc(&pdev->dev, 18628c2ecf20Sopenharmony_ci controller->num_chipselect, sizeof(struct gpio_desc *), 18638c2ecf20Sopenharmony_ci GFP_KERNEL); 18648c2ecf20Sopenharmony_ci if (!drv_data->cs_gpiods) { 18658c2ecf20Sopenharmony_ci status = -ENOMEM; 18668c2ecf20Sopenharmony_ci goto out_error_clock_enabled; 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci for (i = 0; i < controller->num_chipselect; i++) { 18708c2ecf20Sopenharmony_ci struct gpio_desc *gpiod; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS); 18738c2ecf20Sopenharmony_ci if (IS_ERR(gpiod)) { 18748c2ecf20Sopenharmony_ci /* Means use native chip select */ 18758c2ecf20Sopenharmony_ci if (PTR_ERR(gpiod) == -ENOENT) 18768c2ecf20Sopenharmony_ci continue; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci status = PTR_ERR(gpiod); 18798c2ecf20Sopenharmony_ci goto out_error_clock_enabled; 18808c2ecf20Sopenharmony_ci } else { 18818c2ecf20Sopenharmony_ci drv_data->cs_gpiods[i] = gpiod; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci if (platform_info->is_slave) { 18878c2ecf20Sopenharmony_ci drv_data->gpiod_ready = devm_gpiod_get_optional(dev, 18888c2ecf20Sopenharmony_ci "ready", GPIOD_OUT_LOW); 18898c2ecf20Sopenharmony_ci if (IS_ERR(drv_data->gpiod_ready)) { 18908c2ecf20Sopenharmony_ci status = PTR_ERR(drv_data->gpiod_ready); 18918c2ecf20Sopenharmony_ci goto out_error_clock_enabled; 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, 50); 18968c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 18978c2ecf20Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 18988c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci /* Register with the SPI framework */ 19018c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, drv_data); 19028c2ecf20Sopenharmony_ci status = spi_register_controller(controller); 19038c2ecf20Sopenharmony_ci if (status != 0) { 19048c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "problem registering spi controller\n"); 19058c2ecf20Sopenharmony_ci goto out_error_pm_runtime_enabled; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci return status; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ciout_error_pm_runtime_enabled: 19118c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ciout_error_clock_enabled: 19148c2ecf20Sopenharmony_ci clk_disable_unprepare(ssp->clk); 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ciout_error_dma_irq_alloc: 19178c2ecf20Sopenharmony_ci pxa2xx_spi_dma_release(drv_data); 19188c2ecf20Sopenharmony_ci free_irq(ssp->irq, drv_data); 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ciout_error_controller_alloc: 19218c2ecf20Sopenharmony_ci pxa_ssp_free(ssp); 19228c2ecf20Sopenharmony_ci return status; 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_cistatic int pxa2xx_spi_remove(struct platform_device *pdev) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci struct driver_data *drv_data = platform_get_drvdata(pdev); 19288c2ecf20Sopenharmony_ci struct ssp_device *ssp = drv_data->ssp; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci spi_unregister_controller(drv_data->controller); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci /* Disable the SSP at the peripheral and SOC level */ 19358c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, 0); 19368c2ecf20Sopenharmony_ci clk_disable_unprepare(ssp->clk); 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci /* Release DMA */ 19398c2ecf20Sopenharmony_ci if (drv_data->controller_info->enable_dma) 19408c2ecf20Sopenharmony_ci pxa2xx_spi_dma_release(drv_data); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 19438c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci /* Release IRQ */ 19468c2ecf20Sopenharmony_ci free_irq(ssp->irq, drv_data); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci /* Release SSP */ 19498c2ecf20Sopenharmony_ci pxa_ssp_free(ssp); 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci return 0; 19528c2ecf20Sopenharmony_ci} 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 19558c2ecf20Sopenharmony_cistatic int pxa2xx_spi_suspend(struct device *dev) 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci struct driver_data *drv_data = dev_get_drvdata(dev); 19588c2ecf20Sopenharmony_ci struct ssp_device *ssp = drv_data->ssp; 19598c2ecf20Sopenharmony_ci int status; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci status = spi_controller_suspend(drv_data->controller); 19628c2ecf20Sopenharmony_ci if (status != 0) 19638c2ecf20Sopenharmony_ci return status; 19648c2ecf20Sopenharmony_ci pxa2xx_spi_write(drv_data, SSCR0, 0); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(dev)) 19678c2ecf20Sopenharmony_ci clk_disable_unprepare(ssp->clk); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci return 0; 19708c2ecf20Sopenharmony_ci} 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_cistatic int pxa2xx_spi_resume(struct device *dev) 19738c2ecf20Sopenharmony_ci{ 19748c2ecf20Sopenharmony_ci struct driver_data *drv_data = dev_get_drvdata(dev); 19758c2ecf20Sopenharmony_ci struct ssp_device *ssp = drv_data->ssp; 19768c2ecf20Sopenharmony_ci int status; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci /* Enable the SSP clock */ 19798c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(dev)) { 19808c2ecf20Sopenharmony_ci status = clk_prepare_enable(ssp->clk); 19818c2ecf20Sopenharmony_ci if (status) 19828c2ecf20Sopenharmony_ci return status; 19838c2ecf20Sopenharmony_ci } 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci /* Start the queue running */ 19868c2ecf20Sopenharmony_ci return spi_controller_resume(drv_data->controller); 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci#endif 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 19918c2ecf20Sopenharmony_cistatic int pxa2xx_spi_runtime_suspend(struct device *dev) 19928c2ecf20Sopenharmony_ci{ 19938c2ecf20Sopenharmony_ci struct driver_data *drv_data = dev_get_drvdata(dev); 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci clk_disable_unprepare(drv_data->ssp->clk); 19968c2ecf20Sopenharmony_ci return 0; 19978c2ecf20Sopenharmony_ci} 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_cistatic int pxa2xx_spi_runtime_resume(struct device *dev) 20008c2ecf20Sopenharmony_ci{ 20018c2ecf20Sopenharmony_ci struct driver_data *drv_data = dev_get_drvdata(dev); 20028c2ecf20Sopenharmony_ci int status; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci status = clk_prepare_enable(drv_data->ssp->clk); 20058c2ecf20Sopenharmony_ci return status; 20068c2ecf20Sopenharmony_ci} 20078c2ecf20Sopenharmony_ci#endif 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_cistatic const struct dev_pm_ops pxa2xx_spi_pm_ops = { 20108c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pxa2xx_spi_suspend, pxa2xx_spi_resume) 20118c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend, 20128c2ecf20Sopenharmony_ci pxa2xx_spi_runtime_resume, NULL) 20138c2ecf20Sopenharmony_ci}; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_cistatic struct platform_driver driver = { 20168c2ecf20Sopenharmony_ci .driver = { 20178c2ecf20Sopenharmony_ci .name = "pxa2xx-spi", 20188c2ecf20Sopenharmony_ci .pm = &pxa2xx_spi_pm_ops, 20198c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match), 20208c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(pxa2xx_spi_of_match), 20218c2ecf20Sopenharmony_ci }, 20228c2ecf20Sopenharmony_ci .probe = pxa2xx_spi_probe, 20238c2ecf20Sopenharmony_ci .remove = pxa2xx_spi_remove, 20248c2ecf20Sopenharmony_ci}; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_cistatic int __init pxa2xx_spi_init(void) 20278c2ecf20Sopenharmony_ci{ 20288c2ecf20Sopenharmony_ci return platform_driver_register(&driver); 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_cisubsys_initcall(pxa2xx_spi_init); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_cistatic void __exit pxa2xx_spi_exit(void) 20338c2ecf20Sopenharmony_ci{ 20348c2ecf20Sopenharmony_ci platform_driver_unregister(&driver); 20358c2ecf20Sopenharmony_ci} 20368c2ecf20Sopenharmony_cimodule_exit(pxa2xx_spi_exit); 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ciMODULE_SOFTDEP("pre: dw_dmac"); 2039