18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/clk.h> 58c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 68c2ecf20Sopenharmony_ci#include <linux/io.h> 78c2ecf20Sopenharmony_ci#include <linux/log2.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 108c2ecf20Sopenharmony_ci#include <linux/pm_opp.h> 118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 128c2ecf20Sopenharmony_ci#include <linux/qcom-geni-se.h> 138c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 148c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* SPI SE specific registers and respective register fields */ 178c2ecf20Sopenharmony_ci#define SE_SPI_CPHA 0x224 188c2ecf20Sopenharmony_ci#define CPHA BIT(0) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define SE_SPI_LOOPBACK 0x22c 218c2ecf20Sopenharmony_ci#define LOOPBACK_ENABLE 0x1 228c2ecf20Sopenharmony_ci#define NORMAL_MODE 0x0 238c2ecf20Sopenharmony_ci#define LOOPBACK_MSK GENMASK(1, 0) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define SE_SPI_CPOL 0x230 268c2ecf20Sopenharmony_ci#define CPOL BIT(2) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SE_SPI_DEMUX_OUTPUT_INV 0x24c 298c2ecf20Sopenharmony_ci#define CS_DEMUX_OUTPUT_INV_MSK GENMASK(3, 0) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define SE_SPI_DEMUX_SEL 0x250 328c2ecf20Sopenharmony_ci#define CS_DEMUX_OUTPUT_SEL GENMASK(3, 0) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define SE_SPI_TRANS_CFG 0x25c 358c2ecf20Sopenharmony_ci#define CS_TOGGLE BIT(1) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define SE_SPI_WORD_LEN 0x268 388c2ecf20Sopenharmony_ci#define WORD_LEN_MSK GENMASK(9, 0) 398c2ecf20Sopenharmony_ci#define MIN_WORD_LEN 4 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define SE_SPI_TX_TRANS_LEN 0x26c 428c2ecf20Sopenharmony_ci#define SE_SPI_RX_TRANS_LEN 0x270 438c2ecf20Sopenharmony_ci#define TRANS_LEN_MSK GENMASK(23, 0) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define SE_SPI_PRE_POST_CMD_DLY 0x274 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define SE_SPI_DELAY_COUNTERS 0x278 488c2ecf20Sopenharmony_ci#define SPI_INTER_WORDS_DELAY_MSK GENMASK(9, 0) 498c2ecf20Sopenharmony_ci#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10) 508c2ecf20Sopenharmony_ci#define SPI_CS_CLK_DELAY_SHFT 10 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* M_CMD OP codes for SPI */ 538c2ecf20Sopenharmony_ci#define SPI_TX_ONLY 1 548c2ecf20Sopenharmony_ci#define SPI_RX_ONLY 2 558c2ecf20Sopenharmony_ci#define SPI_TX_RX 7 568c2ecf20Sopenharmony_ci#define SPI_CS_ASSERT 8 578c2ecf20Sopenharmony_ci#define SPI_CS_DEASSERT 9 588c2ecf20Sopenharmony_ci#define SPI_SCK_ONLY 10 598c2ecf20Sopenharmony_ci/* M_CMD params for SPI */ 608c2ecf20Sopenharmony_ci#define SPI_PRE_CMD_DELAY BIT(0) 618c2ecf20Sopenharmony_ci#define TIMESTAMP_BEFORE BIT(1) 628c2ecf20Sopenharmony_ci#define FRAGMENTATION BIT(2) 638c2ecf20Sopenharmony_ci#define TIMESTAMP_AFTER BIT(3) 648c2ecf20Sopenharmony_ci#define POST_CMD_DELAY BIT(4) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct spi_geni_master { 678c2ecf20Sopenharmony_ci struct geni_se se; 688c2ecf20Sopenharmony_ci struct device *dev; 698c2ecf20Sopenharmony_ci u32 tx_fifo_depth; 708c2ecf20Sopenharmony_ci u32 fifo_width_bits; 718c2ecf20Sopenharmony_ci u32 tx_wm; 728c2ecf20Sopenharmony_ci u32 last_mode; 738c2ecf20Sopenharmony_ci unsigned long cur_speed_hz; 748c2ecf20Sopenharmony_ci unsigned long cur_sclk_hz; 758c2ecf20Sopenharmony_ci unsigned int cur_bits_per_word; 768c2ecf20Sopenharmony_ci unsigned int tx_rem_bytes; 778c2ecf20Sopenharmony_ci unsigned int rx_rem_bytes; 788c2ecf20Sopenharmony_ci const struct spi_transfer *cur_xfer; 798c2ecf20Sopenharmony_ci struct completion cs_done; 808c2ecf20Sopenharmony_ci struct completion cancel_done; 818c2ecf20Sopenharmony_ci struct completion abort_done; 828c2ecf20Sopenharmony_ci unsigned int oversampling; 838c2ecf20Sopenharmony_ci spinlock_t lock; 848c2ecf20Sopenharmony_ci int irq; 858c2ecf20Sopenharmony_ci bool cs_flag; 868c2ecf20Sopenharmony_ci bool abort_failed; 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int get_spi_clk_cfg(unsigned int speed_hz, 908c2ecf20Sopenharmony_ci struct spi_geni_master *mas, 918c2ecf20Sopenharmony_ci unsigned int *clk_idx, 928c2ecf20Sopenharmony_ci unsigned int *clk_div) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci unsigned long sclk_freq; 958c2ecf20Sopenharmony_ci unsigned int actual_hz; 968c2ecf20Sopenharmony_ci int ret; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci ret = geni_se_clk_freq_match(&mas->se, 998c2ecf20Sopenharmony_ci speed_hz * mas->oversampling, 1008c2ecf20Sopenharmony_ci clk_idx, &sclk_freq, false); 1018c2ecf20Sopenharmony_ci if (ret) { 1028c2ecf20Sopenharmony_ci dev_err(mas->dev, "Failed(%d) to find src clk for %dHz\n", 1038c2ecf20Sopenharmony_ci ret, speed_hz); 1048c2ecf20Sopenharmony_ci return ret; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci *clk_div = DIV_ROUND_UP(sclk_freq, mas->oversampling * speed_hz); 1088c2ecf20Sopenharmony_ci actual_hz = sclk_freq / (mas->oversampling * *clk_div); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci dev_dbg(mas->dev, "req %u=>%u sclk %lu, idx %d, div %d\n", speed_hz, 1118c2ecf20Sopenharmony_ci actual_hz, sclk_freq, *clk_idx, *clk_div); 1128c2ecf20Sopenharmony_ci ret = dev_pm_opp_set_rate(mas->dev, sclk_freq); 1138c2ecf20Sopenharmony_ci if (ret) 1148c2ecf20Sopenharmony_ci dev_err(mas->dev, "dev_pm_opp_set_rate failed %d\n", ret); 1158c2ecf20Sopenharmony_ci else 1168c2ecf20Sopenharmony_ci mas->cur_sclk_hz = sclk_freq; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return ret; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void handle_fifo_timeout(struct spi_master *spi, 1228c2ecf20Sopenharmony_ci struct spi_message *msg) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 1258c2ecf20Sopenharmony_ci unsigned long time_left; 1268c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci spin_lock_irq(&mas->lock); 1298c2ecf20Sopenharmony_ci reinit_completion(&mas->cancel_done); 1308c2ecf20Sopenharmony_ci writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 1318c2ecf20Sopenharmony_ci mas->cur_xfer = NULL; 1328c2ecf20Sopenharmony_ci geni_se_cancel_m_cmd(se); 1338c2ecf20Sopenharmony_ci spin_unlock_irq(&mas->lock); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&mas->cancel_done, HZ); 1368c2ecf20Sopenharmony_ci if (time_left) 1378c2ecf20Sopenharmony_ci return; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci spin_lock_irq(&mas->lock); 1408c2ecf20Sopenharmony_ci reinit_completion(&mas->abort_done); 1418c2ecf20Sopenharmony_ci geni_se_abort_m_cmd(se); 1428c2ecf20Sopenharmony_ci spin_unlock_irq(&mas->lock); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&mas->abort_done, HZ); 1458c2ecf20Sopenharmony_ci if (!time_left) { 1468c2ecf20Sopenharmony_ci dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * No need for a lock since SPI core has a lock and we never 1508c2ecf20Sopenharmony_ci * access this from an interrupt. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci mas->abort_failed = true; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 1598c2ecf20Sopenharmony_ci u32 m_irq, m_irq_en; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (!mas->abort_failed) 1628c2ecf20Sopenharmony_ci return false; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* 1658c2ecf20Sopenharmony_ci * The only known case where a transfer times out and then a cancel 1668c2ecf20Sopenharmony_ci * times out then an abort times out is if something is blocking our 1678c2ecf20Sopenharmony_ci * interrupt handler from running. Avoid starting any new transfers 1688c2ecf20Sopenharmony_ci * until that sorts itself out. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci spin_lock_irq(&mas->lock); 1718c2ecf20Sopenharmony_ci m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); 1728c2ecf20Sopenharmony_ci m_irq_en = readl(se->base + SE_GENI_M_IRQ_EN); 1738c2ecf20Sopenharmony_ci spin_unlock_irq(&mas->lock); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (m_irq & m_irq_en) { 1768c2ecf20Sopenharmony_ci dev_err(mas->dev, "Interrupts pending after abort: %#010x\n", 1778c2ecf20Sopenharmony_ci m_irq & m_irq_en); 1788c2ecf20Sopenharmony_ci return true; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * If we're here the problem resolved itself so no need to check more 1838c2ecf20Sopenharmony_ci * on future transfers. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci mas->abort_failed = false; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return false; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void spi_geni_set_cs(struct spi_device *slv, bool set_flag) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(slv->master); 1938c2ecf20Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(mas->dev); 1948c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 1958c2ecf20Sopenharmony_ci unsigned long time_left; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (!(slv->mode & SPI_CS_HIGH)) 1988c2ecf20Sopenharmony_ci set_flag = !set_flag; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (set_flag == mas->cs_flag) 2018c2ecf20Sopenharmony_ci return; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci pm_runtime_get_sync(mas->dev); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (spi_geni_is_abort_still_pending(mas)) { 2068c2ecf20Sopenharmony_ci dev_err(mas->dev, "Can't set chip select\n"); 2078c2ecf20Sopenharmony_ci goto exit; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci mas->cs_flag = set_flag; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci spin_lock_irq(&mas->lock); 2138c2ecf20Sopenharmony_ci reinit_completion(&mas->cs_done); 2148c2ecf20Sopenharmony_ci if (set_flag) 2158c2ecf20Sopenharmony_ci geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); 2168c2ecf20Sopenharmony_ci else 2178c2ecf20Sopenharmony_ci geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); 2188c2ecf20Sopenharmony_ci spin_unlock_irq(&mas->lock); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&mas->cs_done, HZ); 2218c2ecf20Sopenharmony_ci if (!time_left) 2228c2ecf20Sopenharmony_ci handle_fifo_timeout(spi, NULL); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciexit: 2258c2ecf20Sopenharmony_ci pm_runtime_put(mas->dev); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void spi_setup_word_len(struct spi_geni_master *mas, u16 mode, 2298c2ecf20Sopenharmony_ci unsigned int bits_per_word) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci unsigned int pack_words; 2328c2ecf20Sopenharmony_ci bool msb_first = (mode & SPI_LSB_FIRST) ? false : true; 2338c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 2348c2ecf20Sopenharmony_ci u32 word_len; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* 2378c2ecf20Sopenharmony_ci * If bits_per_word isn't a byte aligned value, set the packing to be 2388c2ecf20Sopenharmony_ci * 1 SPI word per FIFO word. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci if (!(mas->fifo_width_bits % bits_per_word)) 2418c2ecf20Sopenharmony_ci pack_words = mas->fifo_width_bits / bits_per_word; 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci pack_words = 1; 2448c2ecf20Sopenharmony_ci geni_se_config_packing(&mas->se, bits_per_word, pack_words, msb_first, 2458c2ecf20Sopenharmony_ci true, true); 2468c2ecf20Sopenharmony_ci word_len = (bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK; 2478c2ecf20Sopenharmony_ci writel(word_len, se->base + SE_SPI_WORD_LEN); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int geni_spi_set_clock_and_bw(struct spi_geni_master *mas, 2518c2ecf20Sopenharmony_ci unsigned long clk_hz) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci u32 clk_sel, m_clk_cfg, idx, div; 2548c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 2558c2ecf20Sopenharmony_ci int ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (clk_hz == mas->cur_speed_hz) 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci ret = get_spi_clk_cfg(clk_hz, mas, &idx, &div); 2618c2ecf20Sopenharmony_ci if (ret) { 2628c2ecf20Sopenharmony_ci dev_err(mas->dev, "Err setting clk to %lu: %d\n", clk_hz, ret); 2638c2ecf20Sopenharmony_ci return ret; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* 2678c2ecf20Sopenharmony_ci * SPI core clock gets configured with the requested frequency 2688c2ecf20Sopenharmony_ci * or the frequency closer to the requested frequency. 2698c2ecf20Sopenharmony_ci * For that reason requested frequency is stored in the 2708c2ecf20Sopenharmony_ci * cur_speed_hz and referred in the consecutive transfer instead 2718c2ecf20Sopenharmony_ci * of calling clk_get_rate() API. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci mas->cur_speed_hz = clk_hz; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci clk_sel = idx & CLK_SEL_MSK; 2768c2ecf20Sopenharmony_ci m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN; 2778c2ecf20Sopenharmony_ci writel(clk_sel, se->base + SE_GENI_CLK_SEL); 2788c2ecf20Sopenharmony_ci writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* Set BW quota for CPU as driver supports FIFO mode only. */ 2818c2ecf20Sopenharmony_ci se->icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(mas->cur_speed_hz); 2828c2ecf20Sopenharmony_ci ret = geni_icc_set_bw(se); 2838c2ecf20Sopenharmony_ci if (ret) 2848c2ecf20Sopenharmony_ci return ret; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int setup_fifo_params(struct spi_device *spi_slv, 2908c2ecf20Sopenharmony_ci struct spi_master *spi) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 2938c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 2948c2ecf20Sopenharmony_ci u32 loopback_cfg = 0, cpol = 0, cpha = 0, demux_output_inv = 0; 2958c2ecf20Sopenharmony_ci u32 demux_sel; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (mas->last_mode != spi_slv->mode) { 2988c2ecf20Sopenharmony_ci if (spi_slv->mode & SPI_LOOP) 2998c2ecf20Sopenharmony_ci loopback_cfg = LOOPBACK_ENABLE; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (spi_slv->mode & SPI_CPOL) 3028c2ecf20Sopenharmony_ci cpol = CPOL; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (spi_slv->mode & SPI_CPHA) 3058c2ecf20Sopenharmony_ci cpha = CPHA; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (spi_slv->mode & SPI_CS_HIGH) 3088c2ecf20Sopenharmony_ci demux_output_inv = BIT(spi_slv->chip_select); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci demux_sel = spi_slv->chip_select; 3118c2ecf20Sopenharmony_ci mas->cur_bits_per_word = spi_slv->bits_per_word; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word); 3148c2ecf20Sopenharmony_ci writel(loopback_cfg, se->base + SE_SPI_LOOPBACK); 3158c2ecf20Sopenharmony_ci writel(demux_sel, se->base + SE_SPI_DEMUX_SEL); 3168c2ecf20Sopenharmony_ci writel(cpha, se->base + SE_SPI_CPHA); 3178c2ecf20Sopenharmony_ci writel(cpol, se->base + SE_SPI_CPOL); 3188c2ecf20Sopenharmony_ci writel(demux_output_inv, se->base + SE_SPI_DEMUX_OUTPUT_INV); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci mas->last_mode = spi_slv->mode; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return geni_spi_set_clock_and_bw(mas, spi_slv->max_speed_hz); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int spi_geni_prepare_message(struct spi_master *spi, 3278c2ecf20Sopenharmony_ci struct spi_message *spi_msg) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci int ret; 3308c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (spi_geni_is_abort_still_pending(mas)) 3338c2ecf20Sopenharmony_ci return -EBUSY; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci ret = setup_fifo_params(spi_msg->spi, spi); 3368c2ecf20Sopenharmony_ci if (ret) 3378c2ecf20Sopenharmony_ci dev_err(mas->dev, "Couldn't select mode %d\n", ret); 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int spi_geni_init(struct spi_geni_master *mas) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 3448c2ecf20Sopenharmony_ci unsigned int proto, major, minor, ver; 3458c2ecf20Sopenharmony_ci u32 spi_tx_cfg; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci pm_runtime_get_sync(mas->dev); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci proto = geni_se_read_proto(se); 3508c2ecf20Sopenharmony_ci if (proto != GENI_SE_SPI) { 3518c2ecf20Sopenharmony_ci dev_err(mas->dev, "Invalid proto %d\n", proto); 3528c2ecf20Sopenharmony_ci pm_runtime_put(mas->dev); 3538c2ecf20Sopenharmony_ci return -ENXIO; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Width of Tx and Rx FIFO is same */ 3588c2ecf20Sopenharmony_ci mas->fifo_width_bits = geni_se_get_tx_fifo_width(se); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* 3618c2ecf20Sopenharmony_ci * Hardware programming guide suggests to configure 3628c2ecf20Sopenharmony_ci * RX FIFO RFR level to fifo_depth-2. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci geni_se_init(se, mas->tx_fifo_depth - 3, mas->tx_fifo_depth - 2); 3658c2ecf20Sopenharmony_ci /* Transmit an entire FIFO worth of data per IRQ */ 3668c2ecf20Sopenharmony_ci mas->tx_wm = 1; 3678c2ecf20Sopenharmony_ci ver = geni_se_get_qup_hw_version(se); 3688c2ecf20Sopenharmony_ci major = GENI_SE_VERSION_MAJOR(ver); 3698c2ecf20Sopenharmony_ci minor = GENI_SE_VERSION_MINOR(ver); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (major == 1 && minor == 0) 3728c2ecf20Sopenharmony_ci mas->oversampling = 2; 3738c2ecf20Sopenharmony_ci else 3748c2ecf20Sopenharmony_ci mas->oversampling = 1; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci geni_se_select_mode(se, GENI_SE_FIFO); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* We always control CS manually */ 3798c2ecf20Sopenharmony_ci spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); 3808c2ecf20Sopenharmony_ci spi_tx_cfg &= ~CS_TOGGLE; 3818c2ecf20Sopenharmony_ci writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci pm_runtime_put(mas->dev); 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic unsigned int geni_byte_per_fifo_word(struct spi_geni_master *mas) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci /* 3908c2ecf20Sopenharmony_ci * Calculate how many bytes we'll put in each FIFO word. If the 3918c2ecf20Sopenharmony_ci * transfer words don't pack cleanly into a FIFO word we'll just put 3928c2ecf20Sopenharmony_ci * one transfer word in each FIFO word. If they do pack we'll pack 'em. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci if (mas->fifo_width_bits % mas->cur_bits_per_word) 3958c2ecf20Sopenharmony_ci return roundup_pow_of_two(DIV_ROUND_UP(mas->cur_bits_per_word, 3968c2ecf20Sopenharmony_ci BITS_PER_BYTE)); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return mas->fifo_width_bits / BITS_PER_BYTE; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic bool geni_spi_handle_tx(struct spi_geni_master *mas) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 4048c2ecf20Sopenharmony_ci unsigned int max_bytes; 4058c2ecf20Sopenharmony_ci const u8 *tx_buf; 4068c2ecf20Sopenharmony_ci unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); 4078c2ecf20Sopenharmony_ci unsigned int i = 0; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Stop the watermark IRQ if nothing to send */ 4108c2ecf20Sopenharmony_ci if (!mas->cur_xfer) { 4118c2ecf20Sopenharmony_ci writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 4128c2ecf20Sopenharmony_ci return false; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * bytes_per_fifo_word; 4168c2ecf20Sopenharmony_ci if (mas->tx_rem_bytes < max_bytes) 4178c2ecf20Sopenharmony_ci max_bytes = mas->tx_rem_bytes; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci tx_buf = mas->cur_xfer->tx_buf + mas->cur_xfer->len - mas->tx_rem_bytes; 4208c2ecf20Sopenharmony_ci while (i < max_bytes) { 4218c2ecf20Sopenharmony_ci unsigned int j; 4228c2ecf20Sopenharmony_ci unsigned int bytes_to_write; 4238c2ecf20Sopenharmony_ci u32 fifo_word = 0; 4248c2ecf20Sopenharmony_ci u8 *fifo_byte = (u8 *)&fifo_word; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci bytes_to_write = min(bytes_per_fifo_word, max_bytes - i); 4278c2ecf20Sopenharmony_ci for (j = 0; j < bytes_to_write; j++) 4288c2ecf20Sopenharmony_ci fifo_byte[j] = tx_buf[i++]; 4298c2ecf20Sopenharmony_ci iowrite32_rep(se->base + SE_GENI_TX_FIFOn, &fifo_word, 1); 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci mas->tx_rem_bytes -= max_bytes; 4328c2ecf20Sopenharmony_ci if (!mas->tx_rem_bytes) { 4338c2ecf20Sopenharmony_ci writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 4348c2ecf20Sopenharmony_ci return false; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci return true; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void geni_spi_handle_rx(struct spi_geni_master *mas) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 4428c2ecf20Sopenharmony_ci u32 rx_fifo_status; 4438c2ecf20Sopenharmony_ci unsigned int rx_bytes; 4448c2ecf20Sopenharmony_ci unsigned int rx_last_byte_valid; 4458c2ecf20Sopenharmony_ci u8 *rx_buf; 4468c2ecf20Sopenharmony_ci unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); 4478c2ecf20Sopenharmony_ci unsigned int i = 0; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci rx_fifo_status = readl(se->base + SE_GENI_RX_FIFO_STATUS); 4508c2ecf20Sopenharmony_ci rx_bytes = (rx_fifo_status & RX_FIFO_WC_MSK) * bytes_per_fifo_word; 4518c2ecf20Sopenharmony_ci if (rx_fifo_status & RX_LAST) { 4528c2ecf20Sopenharmony_ci rx_last_byte_valid = rx_fifo_status & RX_LAST_BYTE_VALID_MSK; 4538c2ecf20Sopenharmony_ci rx_last_byte_valid >>= RX_LAST_BYTE_VALID_SHFT; 4548c2ecf20Sopenharmony_ci if (rx_last_byte_valid && rx_last_byte_valid < 4) 4558c2ecf20Sopenharmony_ci rx_bytes -= bytes_per_fifo_word - rx_last_byte_valid; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Clear out the FIFO and bail if nowhere to put it */ 4598c2ecf20Sopenharmony_ci if (!mas->cur_xfer) { 4608c2ecf20Sopenharmony_ci for (i = 0; i < DIV_ROUND_UP(rx_bytes, bytes_per_fifo_word); i++) 4618c2ecf20Sopenharmony_ci readl(se->base + SE_GENI_RX_FIFOn); 4628c2ecf20Sopenharmony_ci return; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (mas->rx_rem_bytes < rx_bytes) 4668c2ecf20Sopenharmony_ci rx_bytes = mas->rx_rem_bytes; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci rx_buf = mas->cur_xfer->rx_buf + mas->cur_xfer->len - mas->rx_rem_bytes; 4698c2ecf20Sopenharmony_ci while (i < rx_bytes) { 4708c2ecf20Sopenharmony_ci u32 fifo_word = 0; 4718c2ecf20Sopenharmony_ci u8 *fifo_byte = (u8 *)&fifo_word; 4728c2ecf20Sopenharmony_ci unsigned int bytes_to_read; 4738c2ecf20Sopenharmony_ci unsigned int j; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci bytes_to_read = min(bytes_per_fifo_word, rx_bytes - i); 4768c2ecf20Sopenharmony_ci ioread32_rep(se->base + SE_GENI_RX_FIFOn, &fifo_word, 1); 4778c2ecf20Sopenharmony_ci for (j = 0; j < bytes_to_read; j++) 4788c2ecf20Sopenharmony_ci rx_buf[i++] = fifo_byte[j]; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci mas->rx_rem_bytes -= rx_bytes; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic void setup_fifo_xfer(struct spi_transfer *xfer, 4848c2ecf20Sopenharmony_ci struct spi_geni_master *mas, 4858c2ecf20Sopenharmony_ci u16 mode, struct spi_master *spi) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci u32 m_cmd = 0; 4888c2ecf20Sopenharmony_ci u32 len; 4898c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 4908c2ecf20Sopenharmony_ci int ret; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* 4938c2ecf20Sopenharmony_ci * Ensure that our interrupt handler isn't still running from some 4948c2ecf20Sopenharmony_ci * prior command before we start messing with the hardware behind 4958c2ecf20Sopenharmony_ci * its back. We don't need to _keep_ the lock here since we're only 4968c2ecf20Sopenharmony_ci * worried about racing with out interrupt handler. The SPI core 4978c2ecf20Sopenharmony_ci * already handles making sure that we're not trying to do two 4988c2ecf20Sopenharmony_ci * transfers at once or setting a chip select and doing a transfer 4998c2ecf20Sopenharmony_ci * concurrently. 5008c2ecf20Sopenharmony_ci * 5018c2ecf20Sopenharmony_ci * NOTE: we actually _can't_ hold the lock here because possibly we 5028c2ecf20Sopenharmony_ci * might call clk_set_rate() which needs to be able to sleep. 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_ci spin_lock_irq(&mas->lock); 5058c2ecf20Sopenharmony_ci spin_unlock_irq(&mas->lock); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (xfer->bits_per_word != mas->cur_bits_per_word) { 5088c2ecf20Sopenharmony_ci spi_setup_word_len(mas, mode, xfer->bits_per_word); 5098c2ecf20Sopenharmony_ci mas->cur_bits_per_word = xfer->bits_per_word; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Speed and bits per word can be overridden per transfer */ 5138c2ecf20Sopenharmony_ci ret = geni_spi_set_clock_and_bw(mas, xfer->speed_hz); 5148c2ecf20Sopenharmony_ci if (ret) 5158c2ecf20Sopenharmony_ci return; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci mas->tx_rem_bytes = 0; 5188c2ecf20Sopenharmony_ci mas->rx_rem_bytes = 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (!(mas->cur_bits_per_word % MIN_WORD_LEN)) 5218c2ecf20Sopenharmony_ci len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word; 5228c2ecf20Sopenharmony_ci else 5238c2ecf20Sopenharmony_ci len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1); 5248c2ecf20Sopenharmony_ci len &= TRANS_LEN_MSK; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci mas->cur_xfer = xfer; 5278c2ecf20Sopenharmony_ci if (xfer->tx_buf) { 5288c2ecf20Sopenharmony_ci m_cmd |= SPI_TX_ONLY; 5298c2ecf20Sopenharmony_ci mas->tx_rem_bytes = xfer->len; 5308c2ecf20Sopenharmony_ci writel(len, se->base + SE_SPI_TX_TRANS_LEN); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (xfer->rx_buf) { 5348c2ecf20Sopenharmony_ci m_cmd |= SPI_RX_ONLY; 5358c2ecf20Sopenharmony_ci writel(len, se->base + SE_SPI_RX_TRANS_LEN); 5368c2ecf20Sopenharmony_ci mas->rx_rem_bytes = xfer->len; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * Lock around right before we start the transfer since our 5418c2ecf20Sopenharmony_ci * interrupt could come in at any time now. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ci spin_lock_irq(&mas->lock); 5448c2ecf20Sopenharmony_ci geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* 5478c2ecf20Sopenharmony_ci * TX_WATERMARK_REG should be set after SPI configuration and 5488c2ecf20Sopenharmony_ci * setting up GENI SE engine, as driver starts data transfer 5498c2ecf20Sopenharmony_ci * for the watermark interrupt. 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci if (m_cmd & SPI_TX_ONLY) { 5528c2ecf20Sopenharmony_ci if (geni_spi_handle_tx(mas)) 5538c2ecf20Sopenharmony_ci writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci spin_unlock_irq(&mas->lock); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic int spi_geni_transfer_one(struct spi_master *spi, 5598c2ecf20Sopenharmony_ci struct spi_device *slv, 5608c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (spi_geni_is_abort_still_pending(mas)) 5658c2ecf20Sopenharmony_ci return -EBUSY; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* Terminate and return success for 0 byte length transfer */ 5688c2ecf20Sopenharmony_ci if (!xfer->len) 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci setup_fifo_xfer(xfer, mas, slv->mode, spi); 5728c2ecf20Sopenharmony_ci return 1; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic irqreturn_t geni_spi_isr(int irq, void *data) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct spi_master *spi = data; 5788c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 5798c2ecf20Sopenharmony_ci struct geni_se *se = &mas->se; 5808c2ecf20Sopenharmony_ci u32 m_irq; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); 5838c2ecf20Sopenharmony_ci if (!m_irq) 5848c2ecf20Sopenharmony_ci return IRQ_NONE; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN | 5878c2ecf20Sopenharmony_ci M_RX_FIFO_RD_ERR_EN | M_RX_FIFO_WR_ERR_EN | 5888c2ecf20Sopenharmony_ci M_TX_FIFO_RD_ERR_EN | M_TX_FIFO_WR_ERR_EN)) 5898c2ecf20Sopenharmony_ci dev_warn(mas->dev, "Unexpected IRQ err status %#010x\n", m_irq); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci spin_lock(&mas->lock); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN)) 5948c2ecf20Sopenharmony_ci geni_spi_handle_rx(mas); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (m_irq & M_TX_FIFO_WATERMARK_EN) 5978c2ecf20Sopenharmony_ci geni_spi_handle_tx(mas); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (m_irq & M_CMD_DONE_EN) { 6008c2ecf20Sopenharmony_ci if (mas->cur_xfer) { 6018c2ecf20Sopenharmony_ci spi_finalize_current_transfer(spi); 6028c2ecf20Sopenharmony_ci mas->cur_xfer = NULL; 6038c2ecf20Sopenharmony_ci /* 6048c2ecf20Sopenharmony_ci * If this happens, then a CMD_DONE came before all the 6058c2ecf20Sopenharmony_ci * Tx buffer bytes were sent out. This is unusual, log 6068c2ecf20Sopenharmony_ci * this condition and disable the WM interrupt to 6078c2ecf20Sopenharmony_ci * prevent the system from stalling due an interrupt 6088c2ecf20Sopenharmony_ci * storm. 6098c2ecf20Sopenharmony_ci * 6108c2ecf20Sopenharmony_ci * If this happens when all Rx bytes haven't been 6118c2ecf20Sopenharmony_ci * received, log the condition. The only known time 6128c2ecf20Sopenharmony_ci * this can happen is if bits_per_word != 8 and some 6138c2ecf20Sopenharmony_ci * registers that expect xfer lengths in num spi_words 6148c2ecf20Sopenharmony_ci * weren't written correctly. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_ci if (mas->tx_rem_bytes) { 6178c2ecf20Sopenharmony_ci writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 6188c2ecf20Sopenharmony_ci dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", 6198c2ecf20Sopenharmony_ci mas->tx_rem_bytes, mas->cur_bits_per_word); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci if (mas->rx_rem_bytes) 6228c2ecf20Sopenharmony_ci dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", 6238c2ecf20Sopenharmony_ci mas->rx_rem_bytes, mas->cur_bits_per_word); 6248c2ecf20Sopenharmony_ci } else { 6258c2ecf20Sopenharmony_ci complete(&mas->cs_done); 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (m_irq & M_CMD_CANCEL_EN) 6308c2ecf20Sopenharmony_ci complete(&mas->cancel_done); 6318c2ecf20Sopenharmony_ci if (m_irq & M_CMD_ABORT_EN) 6328c2ecf20Sopenharmony_ci complete(&mas->abort_done); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* 6358c2ecf20Sopenharmony_ci * It's safe or a good idea to Ack all of our our interrupts at the 6368c2ecf20Sopenharmony_ci * end of the function. Specifically: 6378c2ecf20Sopenharmony_ci * - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and 6388c2ecf20Sopenharmony_ci * clearing Acks. Clearing at the end relies on nobody else having 6398c2ecf20Sopenharmony_ci * started a new transfer yet or else we could be clearing _their_ 6408c2ecf20Sopenharmony_ci * done bit, but everyone grabs the spinlock before starting a new 6418c2ecf20Sopenharmony_ci * transfer. 6428c2ecf20Sopenharmony_ci * - M_RX_FIFO_WATERMARK_EN / M_TX_FIFO_WATERMARK_EN: These appear 6438c2ecf20Sopenharmony_ci * to be "latched level" interrupts so it's important to clear them 6448c2ecf20Sopenharmony_ci * _after_ you've handled the condition and always safe to do so 6458c2ecf20Sopenharmony_ci * since they'll re-assert if they're still happening. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_ci writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci spin_unlock(&mas->lock); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic int spi_geni_probe(struct platform_device *pdev) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci int ret, irq; 6578c2ecf20Sopenharmony_ci struct spi_master *spi; 6588c2ecf20Sopenharmony_ci struct spi_geni_master *mas; 6598c2ecf20Sopenharmony_ci void __iomem *base; 6608c2ecf20Sopenharmony_ci struct clk *clk; 6618c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 6648c2ecf20Sopenharmony_ci if (irq < 0) 6658c2ecf20Sopenharmony_ci return irq; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 6688c2ecf20Sopenharmony_ci if (IS_ERR(base)) 6698c2ecf20Sopenharmony_ci return PTR_ERR(base); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, "se"); 6728c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 6738c2ecf20Sopenharmony_ci return PTR_ERR(clk); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci spi = devm_spi_alloc_master(dev, sizeof(*mas)); 6768c2ecf20Sopenharmony_ci if (!spi) 6778c2ecf20Sopenharmony_ci return -ENOMEM; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, spi); 6808c2ecf20Sopenharmony_ci mas = spi_master_get_devdata(spi); 6818c2ecf20Sopenharmony_ci mas->irq = irq; 6828c2ecf20Sopenharmony_ci mas->dev = dev; 6838c2ecf20Sopenharmony_ci mas->se.dev = dev; 6848c2ecf20Sopenharmony_ci mas->se.wrapper = dev_get_drvdata(dev->parent); 6858c2ecf20Sopenharmony_ci mas->se.base = base; 6868c2ecf20Sopenharmony_ci mas->se.clk = clk; 6878c2ecf20Sopenharmony_ci mas->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se"); 6888c2ecf20Sopenharmony_ci if (IS_ERR(mas->se.opp_table)) 6898c2ecf20Sopenharmony_ci return PTR_ERR(mas->se.opp_table); 6908c2ecf20Sopenharmony_ci /* OPP table is optional */ 6918c2ecf20Sopenharmony_ci ret = dev_pm_opp_of_add_table(&pdev->dev); 6928c2ecf20Sopenharmony_ci if (ret && ret != -ENODEV) { 6938c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid OPP table in device tree\n"); 6948c2ecf20Sopenharmony_ci goto put_clkname; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci spi->bus_num = -1; 6988c2ecf20Sopenharmony_ci spi->dev.of_node = dev->of_node; 6998c2ecf20Sopenharmony_ci spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; 7008c2ecf20Sopenharmony_ci spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 7018c2ecf20Sopenharmony_ci spi->num_chipselect = 4; 7028c2ecf20Sopenharmony_ci spi->max_speed_hz = 50000000; 7038c2ecf20Sopenharmony_ci spi->prepare_message = spi_geni_prepare_message; 7048c2ecf20Sopenharmony_ci spi->transfer_one = spi_geni_transfer_one; 7058c2ecf20Sopenharmony_ci spi->auto_runtime_pm = true; 7068c2ecf20Sopenharmony_ci spi->handle_err = handle_fifo_timeout; 7078c2ecf20Sopenharmony_ci spi->set_cs = spi_geni_set_cs; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci init_completion(&mas->cs_done); 7108c2ecf20Sopenharmony_ci init_completion(&mas->cancel_done); 7118c2ecf20Sopenharmony_ci init_completion(&mas->abort_done); 7128c2ecf20Sopenharmony_ci spin_lock_init(&mas->lock); 7138c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 7148c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, 250); 7158c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci ret = geni_icc_get(&mas->se, NULL); 7188c2ecf20Sopenharmony_ci if (ret) 7198c2ecf20Sopenharmony_ci goto spi_geni_probe_runtime_disable; 7208c2ecf20Sopenharmony_ci /* Set the bus quota to a reasonable value for register access */ 7218c2ecf20Sopenharmony_ci mas->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(CORE_2X_50_MHZ); 7228c2ecf20Sopenharmony_ci mas->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci ret = geni_icc_set_bw(&mas->se); 7258c2ecf20Sopenharmony_ci if (ret) 7268c2ecf20Sopenharmony_ci goto spi_geni_probe_runtime_disable; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci ret = spi_geni_init(mas); 7298c2ecf20Sopenharmony_ci if (ret) 7308c2ecf20Sopenharmony_ci goto spi_geni_probe_runtime_disable; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci ret = request_irq(mas->irq, geni_spi_isr, 0, dev_name(dev), spi); 7338c2ecf20Sopenharmony_ci if (ret) 7348c2ecf20Sopenharmony_ci goto spi_geni_probe_runtime_disable; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci ret = spi_register_master(spi); 7378c2ecf20Sopenharmony_ci if (ret) 7388c2ecf20Sopenharmony_ci goto spi_geni_probe_free_irq; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci return 0; 7418c2ecf20Sopenharmony_cispi_geni_probe_free_irq: 7428c2ecf20Sopenharmony_ci free_irq(mas->irq, spi); 7438c2ecf20Sopenharmony_cispi_geni_probe_runtime_disable: 7448c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 7458c2ecf20Sopenharmony_ci dev_pm_opp_of_remove_table(&pdev->dev); 7468c2ecf20Sopenharmony_ciput_clkname: 7478c2ecf20Sopenharmony_ci dev_pm_opp_put_clkname(mas->se.opp_table); 7488c2ecf20Sopenharmony_ci return ret; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int spi_geni_remove(struct platform_device *pdev) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct spi_master *spi = platform_get_drvdata(pdev); 7548c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* Unregister _before_ disabling pm_runtime() so we stop transfers */ 7578c2ecf20Sopenharmony_ci spi_unregister_master(spi); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci free_irq(mas->irq, spi); 7608c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 7618c2ecf20Sopenharmony_ci dev_pm_opp_of_remove_table(&pdev->dev); 7628c2ecf20Sopenharmony_ci dev_pm_opp_put_clkname(mas->se.opp_table); 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int __maybe_unused spi_geni_runtime_suspend(struct device *dev) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(dev); 7698c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 7708c2ecf20Sopenharmony_ci int ret; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* Drop the performance state vote */ 7738c2ecf20Sopenharmony_ci dev_pm_opp_set_rate(dev, 0); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci ret = geni_se_resources_off(&mas->se); 7768c2ecf20Sopenharmony_ci if (ret) 7778c2ecf20Sopenharmony_ci return ret; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return geni_icc_disable(&mas->se); 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int __maybe_unused spi_geni_runtime_resume(struct device *dev) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(dev); 7858c2ecf20Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 7868c2ecf20Sopenharmony_ci int ret; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ret = geni_icc_enable(&mas->se); 7898c2ecf20Sopenharmony_ci if (ret) 7908c2ecf20Sopenharmony_ci return ret; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci ret = geni_se_resources_on(&mas->se); 7938c2ecf20Sopenharmony_ci if (ret) 7948c2ecf20Sopenharmony_ci return ret; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return dev_pm_opp_set_rate(mas->dev, mas->cur_sclk_hz); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int __maybe_unused spi_geni_suspend(struct device *dev) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(dev); 8028c2ecf20Sopenharmony_ci int ret; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci ret = spi_master_suspend(spi); 8058c2ecf20Sopenharmony_ci if (ret) 8068c2ecf20Sopenharmony_ci return ret; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci ret = pm_runtime_force_suspend(dev); 8098c2ecf20Sopenharmony_ci if (ret) 8108c2ecf20Sopenharmony_ci spi_master_resume(spi); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return ret; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int __maybe_unused spi_geni_resume(struct device *dev) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(dev); 8188c2ecf20Sopenharmony_ci int ret; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci ret = pm_runtime_force_resume(dev); 8218c2ecf20Sopenharmony_ci if (ret) 8228c2ecf20Sopenharmony_ci return ret; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci ret = spi_master_resume(spi); 8258c2ecf20Sopenharmony_ci if (ret) 8268c2ecf20Sopenharmony_ci pm_runtime_force_suspend(dev); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci return ret; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic const struct dev_pm_ops spi_geni_pm_ops = { 8328c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(spi_geni_runtime_suspend, 8338c2ecf20Sopenharmony_ci spi_geni_runtime_resume, NULL) 8348c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(spi_geni_suspend, spi_geni_resume) 8358c2ecf20Sopenharmony_ci}; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic const struct of_device_id spi_geni_dt_match[] = { 8388c2ecf20Sopenharmony_ci { .compatible = "qcom,geni-spi" }, 8398c2ecf20Sopenharmony_ci {} 8408c2ecf20Sopenharmony_ci}; 8418c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, spi_geni_dt_match); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic struct platform_driver spi_geni_driver = { 8448c2ecf20Sopenharmony_ci .probe = spi_geni_probe, 8458c2ecf20Sopenharmony_ci .remove = spi_geni_remove, 8468c2ecf20Sopenharmony_ci .driver = { 8478c2ecf20Sopenharmony_ci .name = "geni_spi", 8488c2ecf20Sopenharmony_ci .pm = &spi_geni_pm_ops, 8498c2ecf20Sopenharmony_ci .of_match_table = spi_geni_dt_match, 8508c2ecf20Sopenharmony_ci }, 8518c2ecf20Sopenharmony_ci}; 8528c2ecf20Sopenharmony_cimodule_platform_driver(spi_geni_driver); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SPI driver for GENI based QUP cores"); 8558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 856