18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Driver for AT91 USART Controllers as SPI 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2018 Microchip Technology Inc. 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Author: Radu Pirea <radu.pirea@microchip.com> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 128c2ecf20Sopenharmony_ci#include <linux/dma-direction.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 178c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 188c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define US_CR 0x00 258c2ecf20Sopenharmony_ci#define US_MR 0x04 268c2ecf20Sopenharmony_ci#define US_IER 0x08 278c2ecf20Sopenharmony_ci#define US_IDR 0x0C 288c2ecf20Sopenharmony_ci#define US_CSR 0x14 298c2ecf20Sopenharmony_ci#define US_RHR 0x18 308c2ecf20Sopenharmony_ci#define US_THR 0x1C 318c2ecf20Sopenharmony_ci#define US_BRGR 0x20 328c2ecf20Sopenharmony_ci#define US_VERSION 0xFC 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define US_CR_RSTRX BIT(2) 358c2ecf20Sopenharmony_ci#define US_CR_RSTTX BIT(3) 368c2ecf20Sopenharmony_ci#define US_CR_RXEN BIT(4) 378c2ecf20Sopenharmony_ci#define US_CR_RXDIS BIT(5) 388c2ecf20Sopenharmony_ci#define US_CR_TXEN BIT(6) 398c2ecf20Sopenharmony_ci#define US_CR_TXDIS BIT(7) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define US_MR_SPI_MASTER 0x0E 428c2ecf20Sopenharmony_ci#define US_MR_CHRL GENMASK(7, 6) 438c2ecf20Sopenharmony_ci#define US_MR_CPHA BIT(8) 448c2ecf20Sopenharmony_ci#define US_MR_CPOL BIT(16) 458c2ecf20Sopenharmony_ci#define US_MR_CLKO BIT(18) 468c2ecf20Sopenharmony_ci#define US_MR_WRDBT BIT(20) 478c2ecf20Sopenharmony_ci#define US_MR_LOOP BIT(15) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define US_IR_RXRDY BIT(0) 508c2ecf20Sopenharmony_ci#define US_IR_TXRDY BIT(1) 518c2ecf20Sopenharmony_ci#define US_IR_OVRE BIT(5) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define US_BRGR_SIZE BIT(16) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define US_MIN_CLK_DIV 0x06 568c2ecf20Sopenharmony_ci#define US_MAX_CLK_DIV BIT(16) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define US_RESET (US_CR_RSTRX | US_CR_RSTTX) 598c2ecf20Sopenharmony_ci#define US_DISABLE (US_CR_RXDIS | US_CR_TXDIS) 608c2ecf20Sopenharmony_ci#define US_ENABLE (US_CR_RXEN | US_CR_TXEN) 618c2ecf20Sopenharmony_ci#define US_OVRE_RXRDY_IRQS (US_IR_OVRE | US_IR_RXRDY) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define US_INIT \ 648c2ecf20Sopenharmony_ci (US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT) 658c2ecf20Sopenharmony_ci#define US_DMA_MIN_BYTES 16 668c2ecf20Sopenharmony_ci#define US_DMA_TIMEOUT (msecs_to_jiffies(1000)) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Register access macros */ 698c2ecf20Sopenharmony_ci#define at91_usart_spi_readl(port, reg) \ 708c2ecf20Sopenharmony_ci readl_relaxed((port)->regs + US_##reg) 718c2ecf20Sopenharmony_ci#define at91_usart_spi_writel(port, reg, value) \ 728c2ecf20Sopenharmony_ci writel_relaxed((value), (port)->regs + US_##reg) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define at91_usart_spi_readb(port, reg) \ 758c2ecf20Sopenharmony_ci readb_relaxed((port)->regs + US_##reg) 768c2ecf20Sopenharmony_ci#define at91_usart_spi_writeb(port, reg, value) \ 778c2ecf20Sopenharmony_ci writeb_relaxed((value), (port)->regs + US_##reg) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct at91_usart_spi { 808c2ecf20Sopenharmony_ci struct platform_device *mpdev; 818c2ecf20Sopenharmony_ci struct spi_transfer *current_transfer; 828c2ecf20Sopenharmony_ci void __iomem *regs; 838c2ecf20Sopenharmony_ci struct device *dev; 848c2ecf20Sopenharmony_ci struct clk *clk; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci struct completion xfer_completion; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /*used in interrupt to protect data reading*/ 898c2ecf20Sopenharmony_ci spinlock_t lock; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci phys_addr_t phybase; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci int irq; 948c2ecf20Sopenharmony_ci unsigned int current_tx_remaining_bytes; 958c2ecf20Sopenharmony_ci unsigned int current_rx_remaining_bytes; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci u32 spi_clk; 988c2ecf20Sopenharmony_ci u32 status; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci bool xfer_failed; 1018c2ecf20Sopenharmony_ci bool use_dma; 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void dma_callback(void *data) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct spi_controller *ctlr = data; 1078c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, IER, US_IR_RXRDY); 1108c2ecf20Sopenharmony_ci aus->current_rx_remaining_bytes = 0; 1118c2ecf20Sopenharmony_ci complete(&aus->xfer_completion); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic bool at91_usart_spi_can_dma(struct spi_controller *ctrl, 1158c2ecf20Sopenharmony_ci struct spi_device *spi, 1168c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctrl); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return aus->use_dma && xfer->len >= US_DMA_MIN_BYTES; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int at91_usart_spi_configure_dma(struct spi_controller *ctlr, 1248c2ecf20Sopenharmony_ci struct at91_usart_spi *aus) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct dma_slave_config slave_config; 1278c2ecf20Sopenharmony_ci struct device *dev = &aus->mpdev->dev; 1288c2ecf20Sopenharmony_ci phys_addr_t phybase = aus->phybase; 1298c2ecf20Sopenharmony_ci dma_cap_mask_t mask; 1308c2ecf20Sopenharmony_ci int err = 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci dma_cap_zero(mask); 1338c2ecf20Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci ctlr->dma_tx = dma_request_chan(dev, "tx"); 1368c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(ctlr->dma_tx)) { 1378c2ecf20Sopenharmony_ci if (IS_ERR(ctlr->dma_tx)) { 1388c2ecf20Sopenharmony_ci err = PTR_ERR(ctlr->dma_tx); 1398c2ecf20Sopenharmony_ci goto at91_usart_spi_error_clear; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci dev_dbg(dev, 1438c2ecf20Sopenharmony_ci "DMA TX channel not available, SPI unable to use DMA\n"); 1448c2ecf20Sopenharmony_ci err = -EBUSY; 1458c2ecf20Sopenharmony_ci goto at91_usart_spi_error_clear; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci ctlr->dma_rx = dma_request_chan(dev, "rx"); 1498c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(ctlr->dma_rx)) { 1508c2ecf20Sopenharmony_ci if (IS_ERR(ctlr->dma_rx)) { 1518c2ecf20Sopenharmony_ci err = PTR_ERR(ctlr->dma_rx); 1528c2ecf20Sopenharmony_ci goto at91_usart_spi_error; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci dev_dbg(dev, 1568c2ecf20Sopenharmony_ci "DMA RX channel not available, SPI unable to use DMA\n"); 1578c2ecf20Sopenharmony_ci err = -EBUSY; 1588c2ecf20Sopenharmony_ci goto at91_usart_spi_error; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 1628c2ecf20Sopenharmony_ci slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 1638c2ecf20Sopenharmony_ci slave_config.dst_addr = (dma_addr_t)phybase + US_THR; 1648c2ecf20Sopenharmony_ci slave_config.src_addr = (dma_addr_t)phybase + US_RHR; 1658c2ecf20Sopenharmony_ci slave_config.src_maxburst = 1; 1668c2ecf20Sopenharmony_ci slave_config.dst_maxburst = 1; 1678c2ecf20Sopenharmony_ci slave_config.device_fc = false; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci slave_config.direction = DMA_DEV_TO_MEM; 1708c2ecf20Sopenharmony_ci if (dmaengine_slave_config(ctlr->dma_rx, &slave_config)) { 1718c2ecf20Sopenharmony_ci dev_err(&ctlr->dev, 1728c2ecf20Sopenharmony_ci "failed to configure rx dma channel\n"); 1738c2ecf20Sopenharmony_ci err = -EINVAL; 1748c2ecf20Sopenharmony_ci goto at91_usart_spi_error; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci slave_config.direction = DMA_MEM_TO_DEV; 1788c2ecf20Sopenharmony_ci if (dmaengine_slave_config(ctlr->dma_tx, &slave_config)) { 1798c2ecf20Sopenharmony_ci dev_err(&ctlr->dev, 1808c2ecf20Sopenharmony_ci "failed to configure tx dma channel\n"); 1818c2ecf20Sopenharmony_ci err = -EINVAL; 1828c2ecf20Sopenharmony_ci goto at91_usart_spi_error; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci aus->use_dma = true; 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ciat91_usart_spi_error: 1898c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(ctlr->dma_tx)) 1908c2ecf20Sopenharmony_ci dma_release_channel(ctlr->dma_tx); 1918c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(ctlr->dma_rx)) 1928c2ecf20Sopenharmony_ci dma_release_channel(ctlr->dma_rx); 1938c2ecf20Sopenharmony_ci ctlr->dma_tx = NULL; 1948c2ecf20Sopenharmony_ci ctlr->dma_rx = NULL; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ciat91_usart_spi_error_clear: 1978c2ecf20Sopenharmony_ci return err; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void at91_usart_spi_release_dma(struct spi_controller *ctlr) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci if (ctlr->dma_rx) 2038c2ecf20Sopenharmony_ci dma_release_channel(ctlr->dma_rx); 2048c2ecf20Sopenharmony_ci if (ctlr->dma_tx) 2058c2ecf20Sopenharmony_ci dma_release_channel(ctlr->dma_tx); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void at91_usart_spi_stop_dma(struct spi_controller *ctlr) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci if (ctlr->dma_rx) 2118c2ecf20Sopenharmony_ci dmaengine_terminate_all(ctlr->dma_rx); 2128c2ecf20Sopenharmony_ci if (ctlr->dma_tx) 2138c2ecf20Sopenharmony_ci dmaengine_terminate_all(ctlr->dma_tx); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int at91_usart_spi_dma_transfer(struct spi_controller *ctlr, 2178c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); 2208c2ecf20Sopenharmony_ci struct dma_chan *rxchan = ctlr->dma_rx; 2218c2ecf20Sopenharmony_ci struct dma_chan *txchan = ctlr->dma_tx; 2228c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc; 2238c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *txdesc; 2248c2ecf20Sopenharmony_ci dma_cookie_t cookie; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Disable RX interrupt */ 2278c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, IDR, US_IR_RXRDY); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg(rxchan, 2308c2ecf20Sopenharmony_ci xfer->rx_sg.sgl, 2318c2ecf20Sopenharmony_ci xfer->rx_sg.nents, 2328c2ecf20Sopenharmony_ci DMA_DEV_TO_MEM, 2338c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | 2348c2ecf20Sopenharmony_ci DMA_CTRL_ACK); 2358c2ecf20Sopenharmony_ci if (!rxdesc) 2368c2ecf20Sopenharmony_ci goto at91_usart_spi_err_dma; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci txdesc = dmaengine_prep_slave_sg(txchan, 2398c2ecf20Sopenharmony_ci xfer->tx_sg.sgl, 2408c2ecf20Sopenharmony_ci xfer->tx_sg.nents, 2418c2ecf20Sopenharmony_ci DMA_MEM_TO_DEV, 2428c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | 2438c2ecf20Sopenharmony_ci DMA_CTRL_ACK); 2448c2ecf20Sopenharmony_ci if (!txdesc) 2458c2ecf20Sopenharmony_ci goto at91_usart_spi_err_dma; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci rxdesc->callback = dma_callback; 2488c2ecf20Sopenharmony_ci rxdesc->callback_param = ctlr; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci cookie = rxdesc->tx_submit(rxdesc); 2518c2ecf20Sopenharmony_ci if (dma_submit_error(cookie)) 2528c2ecf20Sopenharmony_ci goto at91_usart_spi_err_dma; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci cookie = txdesc->tx_submit(txdesc); 2558c2ecf20Sopenharmony_ci if (dma_submit_error(cookie)) 2568c2ecf20Sopenharmony_ci goto at91_usart_spi_err_dma; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci rxchan->device->device_issue_pending(rxchan); 2598c2ecf20Sopenharmony_ci txchan->device->device_issue_pending(txchan); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ciat91_usart_spi_err_dma: 2648c2ecf20Sopenharmony_ci /* Enable RX interrupt if something fails and fallback to PIO */ 2658c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, IER, US_IR_RXRDY); 2668c2ecf20Sopenharmony_ci at91_usart_spi_stop_dma(ctlr); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return -ENOMEM; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic unsigned long at91_usart_spi_dma_timeout(struct at91_usart_spi *aus) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci return wait_for_completion_timeout(&aus->xfer_completion, 2748c2ecf20Sopenharmony_ci US_DMA_TIMEOUT); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic inline u32 at91_usart_spi_tx_ready(struct at91_usart_spi *aus) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci return aus->status & US_IR_TXRDY; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic inline u32 at91_usart_spi_rx_ready(struct at91_usart_spi *aus) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci return aus->status & US_IR_RXRDY; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic inline u32 at91_usart_spi_check_overrun(struct at91_usart_spi *aus) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci return aus->status & US_IR_OVRE; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic inline u32 at91_usart_spi_read_status(struct at91_usart_spi *aus) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci aus->status = at91_usart_spi_readl(aus, CSR); 2958c2ecf20Sopenharmony_ci return aus->status; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic inline void at91_usart_spi_tx(struct at91_usart_spi *aus) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci unsigned int len = aus->current_transfer->len; 3018c2ecf20Sopenharmony_ci unsigned int remaining = aus->current_tx_remaining_bytes; 3028c2ecf20Sopenharmony_ci const u8 *tx_buf = aus->current_transfer->tx_buf; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (!remaining) 3058c2ecf20Sopenharmony_ci return; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (at91_usart_spi_tx_ready(aus)) { 3088c2ecf20Sopenharmony_ci at91_usart_spi_writeb(aus, THR, tx_buf[len - remaining]); 3098c2ecf20Sopenharmony_ci aus->current_tx_remaining_bytes--; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic inline void at91_usart_spi_rx(struct at91_usart_spi *aus) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci int len = aus->current_transfer->len; 3168c2ecf20Sopenharmony_ci int remaining = aus->current_rx_remaining_bytes; 3178c2ecf20Sopenharmony_ci u8 *rx_buf = aus->current_transfer->rx_buf; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!remaining) 3208c2ecf20Sopenharmony_ci return; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci rx_buf[len - remaining] = at91_usart_spi_readb(aus, RHR); 3238c2ecf20Sopenharmony_ci aus->current_rx_remaining_bytes--; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic inline void 3278c2ecf20Sopenharmony_ciat91_usart_spi_set_xfer_speed(struct at91_usart_spi *aus, 3288c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, BRGR, 3318c2ecf20Sopenharmony_ci DIV_ROUND_UP(aus->spi_clk, xfer->speed_hz)); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct spi_controller *controller = dev_id; 3378c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(controller); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci spin_lock(&aus->lock); 3408c2ecf20Sopenharmony_ci at91_usart_spi_read_status(aus); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (at91_usart_spi_check_overrun(aus)) { 3438c2ecf20Sopenharmony_ci aus->xfer_failed = true; 3448c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, IDR, US_IR_OVRE | US_IR_RXRDY); 3458c2ecf20Sopenharmony_ci spin_unlock(&aus->lock); 3468c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (at91_usart_spi_rx_ready(aus)) { 3508c2ecf20Sopenharmony_ci at91_usart_spi_rx(aus); 3518c2ecf20Sopenharmony_ci spin_unlock(&aus->lock); 3528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci spin_unlock(&aus->lock); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return IRQ_NONE; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int at91_usart_spi_setup(struct spi_device *spi) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(spi->controller); 3638c2ecf20Sopenharmony_ci u32 *ausd = spi->controller_state; 3648c2ecf20Sopenharmony_ci unsigned int mr = at91_usart_spi_readl(aus, MR); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPOL) 3678c2ecf20Sopenharmony_ci mr |= US_MR_CPOL; 3688c2ecf20Sopenharmony_ci else 3698c2ecf20Sopenharmony_ci mr &= ~US_MR_CPOL; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPHA) 3728c2ecf20Sopenharmony_ci mr |= US_MR_CPHA; 3738c2ecf20Sopenharmony_ci else 3748c2ecf20Sopenharmony_ci mr &= ~US_MR_CPHA; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (spi->mode & SPI_LOOP) 3778c2ecf20Sopenharmony_ci mr |= US_MR_LOOP; 3788c2ecf20Sopenharmony_ci else 3798c2ecf20Sopenharmony_ci mr &= ~US_MR_LOOP; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (!ausd) { 3828c2ecf20Sopenharmony_ci ausd = kzalloc(sizeof(*ausd), GFP_KERNEL); 3838c2ecf20Sopenharmony_ci if (!ausd) 3848c2ecf20Sopenharmony_ci return -ENOMEM; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci spi->controller_state = ausd; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci *ausd = mr; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, 3928c2ecf20Sopenharmony_ci "setup: bpw %u mode 0x%x -> mr %d %08x\n", 3938c2ecf20Sopenharmony_ci spi->bits_per_word, spi->mode, spi->chip_select, mr); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int at91_usart_spi_transfer_one(struct spi_controller *ctlr, 3998c2ecf20Sopenharmony_ci struct spi_device *spi, 4008c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); 4038c2ecf20Sopenharmony_ci unsigned long dma_timeout = 0; 4048c2ecf20Sopenharmony_ci int ret = 0; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci at91_usart_spi_set_xfer_speed(aus, xfer); 4078c2ecf20Sopenharmony_ci aus->xfer_failed = false; 4088c2ecf20Sopenharmony_ci aus->current_transfer = xfer; 4098c2ecf20Sopenharmony_ci aus->current_tx_remaining_bytes = xfer->len; 4108c2ecf20Sopenharmony_ci aus->current_rx_remaining_bytes = xfer->len; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci while ((aus->current_tx_remaining_bytes || 4138c2ecf20Sopenharmony_ci aus->current_rx_remaining_bytes) && !aus->xfer_failed) { 4148c2ecf20Sopenharmony_ci reinit_completion(&aus->xfer_completion); 4158c2ecf20Sopenharmony_ci if (at91_usart_spi_can_dma(ctlr, spi, xfer) && 4168c2ecf20Sopenharmony_ci !ret) { 4178c2ecf20Sopenharmony_ci ret = at91_usart_spi_dma_transfer(ctlr, xfer); 4188c2ecf20Sopenharmony_ci if (ret) 4198c2ecf20Sopenharmony_ci continue; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci dma_timeout = at91_usart_spi_dma_timeout(aus); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (WARN_ON(dma_timeout == 0)) { 4248c2ecf20Sopenharmony_ci dev_err(&spi->dev, "DMA transfer timeout\n"); 4258c2ecf20Sopenharmony_ci return -EIO; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci aus->current_tx_remaining_bytes = 0; 4288c2ecf20Sopenharmony_ci } else { 4298c2ecf20Sopenharmony_ci at91_usart_spi_read_status(aus); 4308c2ecf20Sopenharmony_ci at91_usart_spi_tx(aus); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci cpu_relax(); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (aus->xfer_failed) { 4378c2ecf20Sopenharmony_ci dev_err(aus->dev, "Overrun!\n"); 4388c2ecf20Sopenharmony_ci return -EIO; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int at91_usart_spi_prepare_message(struct spi_controller *ctlr, 4458c2ecf20Sopenharmony_ci struct spi_message *message) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); 4488c2ecf20Sopenharmony_ci struct spi_device *spi = message->spi; 4498c2ecf20Sopenharmony_ci u32 *ausd = spi->controller_state; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, CR, US_ENABLE); 4528c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, IER, US_OVRE_RXRDY_IRQS); 4538c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, MR, *ausd); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int at91_usart_spi_unprepare_message(struct spi_controller *ctlr, 4598c2ecf20Sopenharmony_ci struct spi_message *message) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE); 4648c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, IDR, US_OVRE_RXRDY_IRQS); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic void at91_usart_spi_cleanup(struct spi_device *spi) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct at91_usart_spi_device *ausd = spi->controller_state; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci spi->controller_state = NULL; 4748c2ecf20Sopenharmony_ci kfree(ausd); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic void at91_usart_spi_init(struct at91_usart_spi *aus) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, MR, US_INIT); 4808c2ecf20Sopenharmony_ci at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int at91_usart_gpio_setup(struct platform_device *pdev) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.parent->of_node; 4868c2ecf20Sopenharmony_ci int i; 4878c2ecf20Sopenharmony_ci int ret; 4888c2ecf20Sopenharmony_ci int nb; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!np) 4918c2ecf20Sopenharmony_ci return -EINVAL; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci nb = of_gpio_named_count(np, "cs-gpios"); 4948c2ecf20Sopenharmony_ci for (i = 0; i < nb; i++) { 4958c2ecf20Sopenharmony_ci int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (cs_gpio < 0) 4988c2ecf20Sopenharmony_ci return cs_gpio; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (gpio_is_valid(cs_gpio)) { 5018c2ecf20Sopenharmony_ci ret = devm_gpio_request_one(&pdev->dev, cs_gpio, 5028c2ecf20Sopenharmony_ci GPIOF_DIR_OUT, 5038c2ecf20Sopenharmony_ci dev_name(&pdev->dev)); 5048c2ecf20Sopenharmony_ci if (ret) 5058c2ecf20Sopenharmony_ci return ret; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int at91_usart_spi_probe(struct platform_device *pdev) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct resource *regs; 5158c2ecf20Sopenharmony_ci struct spi_controller *controller; 5168c2ecf20Sopenharmony_ci struct at91_usart_spi *aus; 5178c2ecf20Sopenharmony_ci struct clk *clk; 5188c2ecf20Sopenharmony_ci int irq; 5198c2ecf20Sopenharmony_ci int ret; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci regs = platform_get_resource(to_platform_device(pdev->dev.parent), 5228c2ecf20Sopenharmony_ci IORESOURCE_MEM, 0); 5238c2ecf20Sopenharmony_ci if (!regs) 5248c2ecf20Sopenharmony_ci return -EINVAL; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0); 5278c2ecf20Sopenharmony_ci if (irq < 0) 5288c2ecf20Sopenharmony_ci return irq; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci clk = devm_clk_get(pdev->dev.parent, "usart"); 5318c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 5328c2ecf20Sopenharmony_ci return PTR_ERR(clk); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci ret = -ENOMEM; 5358c2ecf20Sopenharmony_ci controller = spi_alloc_master(&pdev->dev, sizeof(*aus)); 5368c2ecf20Sopenharmony_ci if (!controller) 5378c2ecf20Sopenharmony_ci goto at91_usart_spi_probe_fail; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci ret = at91_usart_gpio_setup(pdev); 5408c2ecf20Sopenharmony_ci if (ret) 5418c2ecf20Sopenharmony_ci goto at91_usart_spi_probe_fail; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; 5448c2ecf20Sopenharmony_ci controller->dev.of_node = pdev->dev.parent->of_node; 5458c2ecf20Sopenharmony_ci controller->bits_per_word_mask = SPI_BPW_MASK(8); 5468c2ecf20Sopenharmony_ci controller->setup = at91_usart_spi_setup; 5478c2ecf20Sopenharmony_ci controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; 5488c2ecf20Sopenharmony_ci controller->transfer_one = at91_usart_spi_transfer_one; 5498c2ecf20Sopenharmony_ci controller->prepare_message = at91_usart_spi_prepare_message; 5508c2ecf20Sopenharmony_ci controller->unprepare_message = at91_usart_spi_unprepare_message; 5518c2ecf20Sopenharmony_ci controller->can_dma = at91_usart_spi_can_dma; 5528c2ecf20Sopenharmony_ci controller->cleanup = at91_usart_spi_cleanup; 5538c2ecf20Sopenharmony_ci controller->max_speed_hz = DIV_ROUND_UP(clk_get_rate(clk), 5548c2ecf20Sopenharmony_ci US_MIN_CLK_DIV); 5558c2ecf20Sopenharmony_ci controller->min_speed_hz = DIV_ROUND_UP(clk_get_rate(clk), 5568c2ecf20Sopenharmony_ci US_MAX_CLK_DIV); 5578c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, controller); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci aus = spi_master_get_devdata(controller); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci aus->dev = &pdev->dev; 5628c2ecf20Sopenharmony_ci aus->regs = devm_ioremap_resource(&pdev->dev, regs); 5638c2ecf20Sopenharmony_ci if (IS_ERR(aus->regs)) { 5648c2ecf20Sopenharmony_ci ret = PTR_ERR(aus->regs); 5658c2ecf20Sopenharmony_ci goto at91_usart_spi_probe_fail; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci aus->irq = irq; 5698c2ecf20Sopenharmony_ci aus->clk = clk; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, at91_usart_spi_interrupt, 0, 5728c2ecf20Sopenharmony_ci dev_name(&pdev->dev), controller); 5738c2ecf20Sopenharmony_ci if (ret) 5748c2ecf20Sopenharmony_ci goto at91_usart_spi_probe_fail; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci ret = clk_prepare_enable(clk); 5778c2ecf20Sopenharmony_ci if (ret) 5788c2ecf20Sopenharmony_ci goto at91_usart_spi_probe_fail; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci aus->spi_clk = clk_get_rate(clk); 5818c2ecf20Sopenharmony_ci at91_usart_spi_init(aus); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci aus->phybase = regs->start; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci aus->mpdev = to_platform_device(pdev->dev.parent); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci ret = at91_usart_spi_configure_dma(controller, aus); 5888c2ecf20Sopenharmony_ci if (ret) 5898c2ecf20Sopenharmony_ci goto at91_usart_fail_dma; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci spin_lock_init(&aus->lock); 5928c2ecf20Sopenharmony_ci init_completion(&aus->xfer_completion); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci ret = devm_spi_register_master(&pdev->dev, controller); 5958c2ecf20Sopenharmony_ci if (ret) 5968c2ecf20Sopenharmony_ci goto at91_usart_fail_register_master; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci dev_info(&pdev->dev, 5998c2ecf20Sopenharmony_ci "AT91 USART SPI Controller version 0x%x at %pa (irq %d)\n", 6008c2ecf20Sopenharmony_ci at91_usart_spi_readl(aus, VERSION), 6018c2ecf20Sopenharmony_ci ®s->start, irq); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return 0; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ciat91_usart_fail_register_master: 6068c2ecf20Sopenharmony_ci at91_usart_spi_release_dma(controller); 6078c2ecf20Sopenharmony_ciat91_usart_fail_dma: 6088c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 6098c2ecf20Sopenharmony_ciat91_usart_spi_probe_fail: 6108c2ecf20Sopenharmony_ci spi_master_put(controller); 6118c2ecf20Sopenharmony_ci return ret; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci__maybe_unused static int at91_usart_spi_runtime_suspend(struct device *dev) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct spi_controller *ctlr = dev_get_drvdata(dev); 6178c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci clk_disable_unprepare(aus->clk); 6208c2ecf20Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci__maybe_unused static int at91_usart_spi_runtime_resume(struct device *dev) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct spi_controller *ctrl = dev_get_drvdata(dev); 6288c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctrl); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(dev); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return clk_prepare_enable(aus->clk); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci__maybe_unused static int at91_usart_spi_suspend(struct device *dev) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci struct spi_controller *ctrl = dev_get_drvdata(dev); 6388c2ecf20Sopenharmony_ci int ret; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ret = spi_controller_suspend(ctrl); 6418c2ecf20Sopenharmony_ci if (ret) 6428c2ecf20Sopenharmony_ci return ret; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(dev)) 6458c2ecf20Sopenharmony_ci at91_usart_spi_runtime_suspend(dev); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return 0; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci__maybe_unused static int at91_usart_spi_resume(struct device *dev) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct spi_controller *ctrl = dev_get_drvdata(dev); 6538c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctrl); 6548c2ecf20Sopenharmony_ci int ret; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(dev)) { 6578c2ecf20Sopenharmony_ci ret = at91_usart_spi_runtime_resume(dev); 6588c2ecf20Sopenharmony_ci if (ret) 6598c2ecf20Sopenharmony_ci return ret; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci at91_usart_spi_init(aus); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci return spi_controller_resume(ctrl); 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic int at91_usart_spi_remove(struct platform_device *pdev) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct spi_controller *ctlr = platform_get_drvdata(pdev); 6708c2ecf20Sopenharmony_ci struct at91_usart_spi *aus = spi_master_get_devdata(ctlr); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci at91_usart_spi_release_dma(ctlr); 6738c2ecf20Sopenharmony_ci clk_disable_unprepare(aus->clk); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return 0; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic const struct dev_pm_ops at91_usart_spi_pm_ops = { 6798c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(at91_usart_spi_suspend, at91_usart_spi_resume) 6808c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(at91_usart_spi_runtime_suspend, 6818c2ecf20Sopenharmony_ci at91_usart_spi_runtime_resume, NULL) 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic struct platform_driver at91_usart_spi_driver = { 6858c2ecf20Sopenharmony_ci .driver = { 6868c2ecf20Sopenharmony_ci .name = "at91_usart_spi", 6878c2ecf20Sopenharmony_ci .pm = &at91_usart_spi_pm_ops, 6888c2ecf20Sopenharmony_ci }, 6898c2ecf20Sopenharmony_ci .probe = at91_usart_spi_probe, 6908c2ecf20Sopenharmony_ci .remove = at91_usart_spi_remove, 6918c2ecf20Sopenharmony_ci}; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cimodule_platform_driver(at91_usart_spi_driver); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microchip AT91 USART SPI Controller driver"); 6968c2ecf20Sopenharmony_ciMODULE_AUTHOR("Radu Pirea <radu.pirea@microchip.com>"); 6978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 6988c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:at91_usart_spi"); 699