18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2010 - Maxim Levitsky 48c2ecf20Sopenharmony_ci * driver for Ricoh memstick readers 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/freezer.h> 108c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/pci.h> 138c2ecf20Sopenharmony_ci#include <linux/pci_ids.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/kthread.h> 178c2ecf20Sopenharmony_ci#include <linux/sched.h> 188c2ecf20Sopenharmony_ci#include <linux/highmem.h> 198c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 208c2ecf20Sopenharmony_ci#include <linux/swab.h> 218c2ecf20Sopenharmony_ci#include "r592.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic bool r592_enable_dma = 1; 248c2ecf20Sopenharmony_cistatic int debug; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic const char *tpc_names[] = { 278c2ecf20Sopenharmony_ci "MS_TPC_READ_MG_STATUS", 288c2ecf20Sopenharmony_ci "MS_TPC_READ_LONG_DATA", 298c2ecf20Sopenharmony_ci "MS_TPC_READ_SHORT_DATA", 308c2ecf20Sopenharmony_ci "MS_TPC_READ_REG", 318c2ecf20Sopenharmony_ci "MS_TPC_READ_QUAD_DATA", 328c2ecf20Sopenharmony_ci "INVALID", 338c2ecf20Sopenharmony_ci "MS_TPC_GET_INT", 348c2ecf20Sopenharmony_ci "MS_TPC_SET_RW_REG_ADRS", 358c2ecf20Sopenharmony_ci "MS_TPC_EX_SET_CMD", 368c2ecf20Sopenharmony_ci "MS_TPC_WRITE_QUAD_DATA", 378c2ecf20Sopenharmony_ci "MS_TPC_WRITE_REG", 388c2ecf20Sopenharmony_ci "MS_TPC_WRITE_SHORT_DATA", 398c2ecf20Sopenharmony_ci "MS_TPC_WRITE_LONG_DATA", 408c2ecf20Sopenharmony_ci "MS_TPC_SET_CMD", 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * memstick_debug_get_tpc_name - debug helper that returns string for 458c2ecf20Sopenharmony_ci * a TPC number 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cistatic __maybe_unused const char *memstick_debug_get_tpc_name(int tpc) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci return tpc_names[tpc-1]; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Read a register*/ 538c2ecf20Sopenharmony_cistatic inline u32 r592_read_reg(struct r592_device *dev, int address) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci u32 value = readl(dev->mmio + address); 568c2ecf20Sopenharmony_ci dbg_reg("reg #%02d == 0x%08x", address, value); 578c2ecf20Sopenharmony_ci return value; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* Write a register */ 618c2ecf20Sopenharmony_cistatic inline void r592_write_reg(struct r592_device *dev, 628c2ecf20Sopenharmony_ci int address, u32 value) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci dbg_reg("reg #%02d <- 0x%08x", address, value); 658c2ecf20Sopenharmony_ci writel(value, dev->mmio + address); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Reads a big endian DWORD register */ 698c2ecf20Sopenharmony_cistatic inline u32 r592_read_reg_raw_be(struct r592_device *dev, int address) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci u32 value = __raw_readl(dev->mmio + address); 728c2ecf20Sopenharmony_ci dbg_reg("reg #%02d == 0x%08x", address, value); 738c2ecf20Sopenharmony_ci return be32_to_cpu(value); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Writes a big endian DWORD register */ 778c2ecf20Sopenharmony_cistatic inline void r592_write_reg_raw_be(struct r592_device *dev, 788c2ecf20Sopenharmony_ci int address, u32 value) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci dbg_reg("reg #%02d <- 0x%08x", address, value); 818c2ecf20Sopenharmony_ci __raw_writel(cpu_to_be32(value), dev->mmio + address); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Set specific bits in a register (little endian) */ 858c2ecf20Sopenharmony_cistatic inline void r592_set_reg_mask(struct r592_device *dev, 868c2ecf20Sopenharmony_ci int address, u32 mask) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci u32 reg = readl(dev->mmio + address); 898c2ecf20Sopenharmony_ci dbg_reg("reg #%02d |= 0x%08x (old =0x%08x)", address, mask, reg); 908c2ecf20Sopenharmony_ci writel(reg | mask , dev->mmio + address); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Clear specific bits in a register (little endian) */ 948c2ecf20Sopenharmony_cistatic inline void r592_clear_reg_mask(struct r592_device *dev, 958c2ecf20Sopenharmony_ci int address, u32 mask) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci u32 reg = readl(dev->mmio + address); 988c2ecf20Sopenharmony_ci dbg_reg("reg #%02d &= 0x%08x (old = 0x%08x, mask = 0x%08x)", 998c2ecf20Sopenharmony_ci address, ~mask, reg, mask); 1008c2ecf20Sopenharmony_ci writel(reg & ~mask, dev->mmio + address); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Wait for status bits while checking for errors */ 1058c2ecf20Sopenharmony_cistatic int r592_wait_status(struct r592_device *dev, u32 mask, u32 wanted_mask) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(1000); 1088c2ecf20Sopenharmony_ci u32 reg = r592_read_reg(dev, R592_STATUS); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if ((reg & mask) == wanted_mask) 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci while (time_before(jiffies, timeout)) { 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci reg = r592_read_reg(dev, R592_STATUS); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if ((reg & mask) == wanted_mask) 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (reg & (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR)) 1218c2ecf20Sopenharmony_ci return -EIO; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci cpu_relax(); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci return -ETIME; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* Enable/disable device */ 1308c2ecf20Sopenharmony_cistatic int r592_enable_device(struct r592_device *dev, bool enable) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci dbg("%sabling the device", enable ? "en" : "dis"); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (enable) { 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* Power up the card */ 1378c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_POWER, R592_POWER_0 | R592_POWER_1); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Perform a reset */ 1408c2ecf20Sopenharmony_ci r592_set_reg_mask(dev, R592_IO, R592_IO_RESET); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci msleep(100); 1438c2ecf20Sopenharmony_ci } else 1448c2ecf20Sopenharmony_ci /* Power down the card */ 1458c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_POWER, 0); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return 0; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* Set serial/parallel mode */ 1518c2ecf20Sopenharmony_cistatic int r592_set_mode(struct r592_device *dev, bool parallel_mode) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci if (!parallel_mode) { 1548c2ecf20Sopenharmony_ci dbg("switching to serial mode"); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* Set serial mode */ 1578c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_SERIAL); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_POWER, R592_POWER_20); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci } else { 1628c2ecf20Sopenharmony_ci dbg("switching to parallel mode"); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* This setting should be set _before_ switch TPC */ 1658c2ecf20Sopenharmony_ci r592_set_reg_mask(dev, R592_POWER, R592_POWER_20); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_IO, 1688c2ecf20Sopenharmony_ci R592_IO_SERIAL1 | R592_IO_SERIAL2); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Set the parallel mode now */ 1718c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_PARALLEL); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci dev->parallel_mode = parallel_mode; 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* Perform a controller reset without powering down the card */ 1798c2ecf20Sopenharmony_cistatic void r592_host_reset(struct r592_device *dev) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci r592_set_reg_mask(dev, R592_IO, R592_IO_RESET); 1828c2ecf20Sopenharmony_ci msleep(100); 1838c2ecf20Sopenharmony_ci r592_set_mode(dev, dev->parallel_mode); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 1878c2ecf20Sopenharmony_ci/* Disable all hardware interrupts */ 1888c2ecf20Sopenharmony_cistatic void r592_clear_interrupts(struct r592_device *dev) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci /* Disable & ACK all interrupts */ 1918c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK); 1928c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci#endif 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* Tests if there is an CRC error */ 1978c2ecf20Sopenharmony_cistatic int r592_test_io_error(struct r592_device *dev) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci if (!(r592_read_reg(dev, R592_STATUS) & 2008c2ecf20Sopenharmony_ci (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR))) 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return -EIO; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* Ensure that FIFO is ready for use */ 2078c2ecf20Sopenharmony_cistatic int r592_test_fifo_empty(struct r592_device *dev) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY) 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci dbg("FIFO not ready, trying to reset the device"); 2138c2ecf20Sopenharmony_ci r592_host_reset(dev); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY) 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci message("FIFO still not ready, giving up"); 2198c2ecf20Sopenharmony_ci return -EIO; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* Activates the DMA transfer from to FIFO */ 2238c2ecf20Sopenharmony_cistatic void r592_start_dma(struct r592_device *dev, bool is_write) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci unsigned long flags; 2268c2ecf20Sopenharmony_ci u32 reg; 2278c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->irq_lock, flags); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Ack interrupts (just in case) + enable them */ 2308c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK); 2318c2ecf20Sopenharmony_ci r592_set_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* Set DMA address */ 2348c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_FIFO_DMA, sg_dma_address(&dev->req->sg)); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Enable the DMA */ 2378c2ecf20Sopenharmony_ci reg = r592_read_reg(dev, R592_FIFO_DMA_SETTINGS); 2388c2ecf20Sopenharmony_ci reg |= R592_FIFO_DMA_SETTINGS_EN; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (!is_write) 2418c2ecf20Sopenharmony_ci reg |= R592_FIFO_DMA_SETTINGS_DIR; 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci reg &= ~R592_FIFO_DMA_SETTINGS_DIR; 2448c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_FIFO_DMA_SETTINGS, reg); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->irq_lock, flags); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* Cleanups DMA related settings */ 2508c2ecf20Sopenharmony_cistatic void r592_stop_dma(struct r592_device *dev, int error) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_FIFO_DMA_SETTINGS, 2538c2ecf20Sopenharmony_ci R592_FIFO_DMA_SETTINGS_EN); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* This is only a precation */ 2568c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_FIFO_DMA, 2578c2ecf20Sopenharmony_ci dev->dummy_dma_page_physical_address); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK); 2608c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK); 2618c2ecf20Sopenharmony_ci dev->dma_error = error; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/* Test if hardware supports DMA */ 2658c2ecf20Sopenharmony_cistatic void r592_check_dma(struct r592_device *dev) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci dev->dma_capable = r592_enable_dma && 2688c2ecf20Sopenharmony_ci (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & 2698c2ecf20Sopenharmony_ci R592_FIFO_DMA_SETTINGS_CAP); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci/* Transfers fifo contents in/out using DMA */ 2738c2ecf20Sopenharmony_cistatic int r592_transfer_fifo_dma(struct r592_device *dev) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci int len, sg_count; 2768c2ecf20Sopenharmony_ci bool is_write; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!dev->dma_capable || !dev->req->long_data) 2798c2ecf20Sopenharmony_ci return -EINVAL; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci len = dev->req->sg.length; 2828c2ecf20Sopenharmony_ci is_write = dev->req->data_dir == WRITE; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (len != R592_LFIFO_SIZE) 2858c2ecf20Sopenharmony_ci return -EINVAL; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci dbg_verbose("doing dma transfer"); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci dev->dma_error = 0; 2908c2ecf20Sopenharmony_ci reinit_completion(&dev->dma_done); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* TODO: hidden assumption about nenth beeing always 1 */ 2938c2ecf20Sopenharmony_ci sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? 2948c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (sg_count != 1 || sg_dma_len(&dev->req->sg) < R592_LFIFO_SIZE) { 2978c2ecf20Sopenharmony_ci message("problem in dma_map_sg"); 2988c2ecf20Sopenharmony_ci return -EIO; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci r592_start_dma(dev, is_write); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Wait for DMA completion */ 3048c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout( 3058c2ecf20Sopenharmony_ci &dev->dma_done, msecs_to_jiffies(1000))) { 3068c2ecf20Sopenharmony_ci message("DMA timeout"); 3078c2ecf20Sopenharmony_ci r592_stop_dma(dev, -ETIMEDOUT); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci dma_unmap_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? 3118c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return dev->dma_error; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* 3188c2ecf20Sopenharmony_ci * Writes the FIFO in 4 byte chunks. 3198c2ecf20Sopenharmony_ci * If length isn't 4 byte aligned, rest of the data if put to a fifo 3208c2ecf20Sopenharmony_ci * to be written later 3218c2ecf20Sopenharmony_ci * Use r592_flush_fifo_write to flush that fifo when writing for the 3228c2ecf20Sopenharmony_ci * last time 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_cistatic void r592_write_fifo_pio(struct r592_device *dev, 3258c2ecf20Sopenharmony_ci unsigned char *buffer, int len) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci /* flush spill from former write */ 3288c2ecf20Sopenharmony_ci if (!kfifo_is_empty(&dev->pio_fifo)) { 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci u8 tmp[4] = {0}; 3318c2ecf20Sopenharmony_ci int copy_len = kfifo_in(&dev->pio_fifo, buffer, len); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (!kfifo_is_full(&dev->pio_fifo)) 3348c2ecf20Sopenharmony_ci return; 3358c2ecf20Sopenharmony_ci len -= copy_len; 3368c2ecf20Sopenharmony_ci buffer += copy_len; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci copy_len = kfifo_out(&dev->pio_fifo, tmp, 4); 3398c2ecf20Sopenharmony_ci WARN_ON(copy_len != 4); 3408c2ecf20Sopenharmony_ci r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)tmp); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci WARN_ON(!kfifo_is_empty(&dev->pio_fifo)); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* write full dwords */ 3468c2ecf20Sopenharmony_ci while (len >= 4) { 3478c2ecf20Sopenharmony_ci r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer); 3488c2ecf20Sopenharmony_ci buffer += 4; 3498c2ecf20Sopenharmony_ci len -= 4; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* put remaining bytes to the spill */ 3538c2ecf20Sopenharmony_ci if (len) 3548c2ecf20Sopenharmony_ci kfifo_in(&dev->pio_fifo, buffer, len); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/* Flushes the temporary FIFO used to make aligned DWORD writes */ 3588c2ecf20Sopenharmony_cistatic void r592_flush_fifo_write(struct r592_device *dev) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci u8 buffer[4] = { 0 }; 3618c2ecf20Sopenharmony_ci int len; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (kfifo_is_empty(&dev->pio_fifo)) 3648c2ecf20Sopenharmony_ci return; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci len = kfifo_out(&dev->pio_fifo, buffer, 4); 3678c2ecf20Sopenharmony_ci r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/* 3718c2ecf20Sopenharmony_ci * Read a fifo in 4 bytes chunks. 3728c2ecf20Sopenharmony_ci * If input doesn't fit the buffer, it places bytes of last dword in spill 3738c2ecf20Sopenharmony_ci * buffer, so that they don't get lost on last read, just throw these away. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_cistatic void r592_read_fifo_pio(struct r592_device *dev, 3768c2ecf20Sopenharmony_ci unsigned char *buffer, int len) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci u8 tmp[4]; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* Read from last spill */ 3818c2ecf20Sopenharmony_ci if (!kfifo_is_empty(&dev->pio_fifo)) { 3828c2ecf20Sopenharmony_ci int bytes_copied = 3838c2ecf20Sopenharmony_ci kfifo_out(&dev->pio_fifo, buffer, min(4, len)); 3848c2ecf20Sopenharmony_ci buffer += bytes_copied; 3858c2ecf20Sopenharmony_ci len -= bytes_copied; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (!kfifo_is_empty(&dev->pio_fifo)) 3888c2ecf20Sopenharmony_ci return; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* Reads dwords from FIFO */ 3928c2ecf20Sopenharmony_ci while (len >= 4) { 3938c2ecf20Sopenharmony_ci *(u32 *)buffer = r592_read_reg_raw_be(dev, R592_FIFO_PIO); 3948c2ecf20Sopenharmony_ci buffer += 4; 3958c2ecf20Sopenharmony_ci len -= 4; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (len) { 3998c2ecf20Sopenharmony_ci *(u32 *)tmp = r592_read_reg_raw_be(dev, R592_FIFO_PIO); 4008c2ecf20Sopenharmony_ci kfifo_in(&dev->pio_fifo, tmp, 4); 4018c2ecf20Sopenharmony_ci len -= kfifo_out(&dev->pio_fifo, buffer, len); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci WARN_ON(len); 4058c2ecf20Sopenharmony_ci return; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/* Transfers actual data using PIO. */ 4098c2ecf20Sopenharmony_cistatic int r592_transfer_fifo_pio(struct r592_device *dev) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci unsigned long flags; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS; 4148c2ecf20Sopenharmony_ci struct sg_mapping_iter miter; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci kfifo_reset(&dev->pio_fifo); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (!dev->req->long_data) { 4198c2ecf20Sopenharmony_ci if (is_write) { 4208c2ecf20Sopenharmony_ci r592_write_fifo_pio(dev, dev->req->data, 4218c2ecf20Sopenharmony_ci dev->req->data_len); 4228c2ecf20Sopenharmony_ci r592_flush_fifo_write(dev); 4238c2ecf20Sopenharmony_ci } else 4248c2ecf20Sopenharmony_ci r592_read_fifo_pio(dev, dev->req->data, 4258c2ecf20Sopenharmony_ci dev->req->data_len); 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci local_irq_save(flags); 4308c2ecf20Sopenharmony_ci sg_miter_start(&miter, &dev->req->sg, 1, SG_MITER_ATOMIC | 4318c2ecf20Sopenharmony_ci (is_write ? SG_MITER_FROM_SG : SG_MITER_TO_SG)); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* Do the transfer fifo<->memory*/ 4348c2ecf20Sopenharmony_ci while (sg_miter_next(&miter)) 4358c2ecf20Sopenharmony_ci if (is_write) 4368c2ecf20Sopenharmony_ci r592_write_fifo_pio(dev, miter.addr, miter.length); 4378c2ecf20Sopenharmony_ci else 4388c2ecf20Sopenharmony_ci r592_read_fifo_pio(dev, miter.addr, miter.length); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Write last few non aligned bytes*/ 4428c2ecf20Sopenharmony_ci if (is_write) 4438c2ecf20Sopenharmony_ci r592_flush_fifo_write(dev); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci sg_miter_stop(&miter); 4468c2ecf20Sopenharmony_ci local_irq_restore(flags); 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/* Executes one TPC (data is read/written from small or large fifo) */ 4518c2ecf20Sopenharmony_cistatic void r592_execute_tpc(struct r592_device *dev) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci bool is_write; 4548c2ecf20Sopenharmony_ci int len, error; 4558c2ecf20Sopenharmony_ci u32 status, reg; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (!dev->req) { 4588c2ecf20Sopenharmony_ci message("BUG: tpc execution without request!"); 4598c2ecf20Sopenharmony_ci return; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS; 4638c2ecf20Sopenharmony_ci len = dev->req->long_data ? 4648c2ecf20Sopenharmony_ci dev->req->sg.length : dev->req->data_len; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* Ensure that FIFO can hold the input data */ 4678c2ecf20Sopenharmony_ci if (len > R592_LFIFO_SIZE) { 4688c2ecf20Sopenharmony_ci message("IO: hardware doesn't support TPCs longer that 512"); 4698c2ecf20Sopenharmony_ci error = -ENOSYS; 4708c2ecf20Sopenharmony_ci goto out; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (!(r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_PRSNT)) { 4748c2ecf20Sopenharmony_ci dbg("IO: refusing to send TPC because card is absent"); 4758c2ecf20Sopenharmony_ci error = -ENODEV; 4768c2ecf20Sopenharmony_ci goto out; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci dbg("IO: executing %s LEN=%d", 4808c2ecf20Sopenharmony_ci memstick_debug_get_tpc_name(dev->req->tpc), len); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* Set IO direction */ 4838c2ecf20Sopenharmony_ci if (is_write) 4848c2ecf20Sopenharmony_ci r592_set_reg_mask(dev, R592_IO, R592_IO_DIRECTION); 4858c2ecf20Sopenharmony_ci else 4868c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_IO, R592_IO_DIRECTION); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci error = r592_test_fifo_empty(dev); 4908c2ecf20Sopenharmony_ci if (error) 4918c2ecf20Sopenharmony_ci goto out; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* Transfer write data */ 4948c2ecf20Sopenharmony_ci if (is_write) { 4958c2ecf20Sopenharmony_ci error = r592_transfer_fifo_dma(dev); 4968c2ecf20Sopenharmony_ci if (error == -EINVAL) 4978c2ecf20Sopenharmony_ci error = r592_transfer_fifo_pio(dev); 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (error) 5018c2ecf20Sopenharmony_ci goto out; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* Trigger the TPC */ 5048c2ecf20Sopenharmony_ci reg = (len << R592_TPC_EXEC_LEN_SHIFT) | 5058c2ecf20Sopenharmony_ci (dev->req->tpc << R592_TPC_EXEC_TPC_SHIFT) | 5068c2ecf20Sopenharmony_ci R592_TPC_EXEC_BIG_FIFO; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_TPC_EXEC, reg); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* Wait for TPC completion */ 5118c2ecf20Sopenharmony_ci status = R592_STATUS_RDY; 5128c2ecf20Sopenharmony_ci if (dev->req->need_card_int) 5138c2ecf20Sopenharmony_ci status |= R592_STATUS_CED; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci error = r592_wait_status(dev, status, status); 5168c2ecf20Sopenharmony_ci if (error) { 5178c2ecf20Sopenharmony_ci message("card didn't respond"); 5188c2ecf20Sopenharmony_ci goto out; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* Test IO errors */ 5228c2ecf20Sopenharmony_ci error = r592_test_io_error(dev); 5238c2ecf20Sopenharmony_ci if (error) { 5248c2ecf20Sopenharmony_ci dbg("IO error"); 5258c2ecf20Sopenharmony_ci goto out; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Read data from FIFO */ 5298c2ecf20Sopenharmony_ci if (!is_write) { 5308c2ecf20Sopenharmony_ci error = r592_transfer_fifo_dma(dev); 5318c2ecf20Sopenharmony_ci if (error == -EINVAL) 5328c2ecf20Sopenharmony_ci error = r592_transfer_fifo_pio(dev); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* read INT reg. This can be shortened with shifts, but that way 5368c2ecf20Sopenharmony_ci its more readable */ 5378c2ecf20Sopenharmony_ci if (dev->parallel_mode && dev->req->need_card_int) { 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci dev->req->int_reg = 0; 5408c2ecf20Sopenharmony_ci status = r592_read_reg(dev, R592_STATUS); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (status & R592_STATUS_P_CMDNACK) 5438c2ecf20Sopenharmony_ci dev->req->int_reg |= MEMSTICK_INT_CMDNAK; 5448c2ecf20Sopenharmony_ci if (status & R592_STATUS_P_BREQ) 5458c2ecf20Sopenharmony_ci dev->req->int_reg |= MEMSTICK_INT_BREQ; 5468c2ecf20Sopenharmony_ci if (status & R592_STATUS_P_INTERR) 5478c2ecf20Sopenharmony_ci dev->req->int_reg |= MEMSTICK_INT_ERR; 5488c2ecf20Sopenharmony_ci if (status & R592_STATUS_P_CED) 5498c2ecf20Sopenharmony_ci dev->req->int_reg |= MEMSTICK_INT_CED; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (error) 5538c2ecf20Sopenharmony_ci dbg("FIFO read error"); 5548c2ecf20Sopenharmony_ciout: 5558c2ecf20Sopenharmony_ci dev->req->error = error; 5568c2ecf20Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, R592_REG_MSC_LED); 5578c2ecf20Sopenharmony_ci return; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci/* Main request processing thread */ 5618c2ecf20Sopenharmony_cistatic int r592_process_thread(void *data) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci int error; 5648c2ecf20Sopenharmony_ci struct r592_device *dev = (struct r592_device *)data; 5658c2ecf20Sopenharmony_ci unsigned long flags; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 5688c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->io_thread_lock, flags); 5698c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 5708c2ecf20Sopenharmony_ci error = memstick_next_req(dev->host, &dev->req); 5718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->io_thread_lock, flags); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (error) { 5748c2ecf20Sopenharmony_ci if (error == -ENXIO || error == -EAGAIN) { 5758c2ecf20Sopenharmony_ci dbg_verbose("IO: done IO, sleeping"); 5768c2ecf20Sopenharmony_ci } else { 5778c2ecf20Sopenharmony_ci dbg("IO: unknown error from " 5788c2ecf20Sopenharmony_ci "memstick_next_req %d", error); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (kthread_should_stop()) 5828c2ecf20Sopenharmony_ci set_current_state(TASK_RUNNING); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci schedule(); 5858c2ecf20Sopenharmony_ci } else { 5868c2ecf20Sopenharmony_ci set_current_state(TASK_RUNNING); 5878c2ecf20Sopenharmony_ci r592_execute_tpc(dev); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/* Reprogram chip to detect change in card state */ 5948c2ecf20Sopenharmony_ci/* eg, if card is detected, arm it to detect removal, and vice versa */ 5958c2ecf20Sopenharmony_cistatic void r592_update_card_detect(struct r592_device *dev) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci u32 reg = r592_read_reg(dev, R592_REG_MSC); 5988c2ecf20Sopenharmony_ci bool card_detected = reg & R592_REG_MSC_PRSNT; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci dbg("update card detect. card state: %s", card_detected ? 6018c2ecf20Sopenharmony_ci "present" : "absent"); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci reg &= ~((R592_REG_MSC_IRQ_REMOVE | R592_REG_MSC_IRQ_INSERT) << 16); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (card_detected) 6068c2ecf20Sopenharmony_ci reg |= (R592_REG_MSC_IRQ_REMOVE << 16); 6078c2ecf20Sopenharmony_ci else 6088c2ecf20Sopenharmony_ci reg |= (R592_REG_MSC_IRQ_INSERT << 16); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_REG_MSC, reg); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/* Timer routine that fires 1 second after last card detection event, */ 6148c2ecf20Sopenharmony_cistatic void r592_detect_timer(struct timer_list *t) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct r592_device *dev = from_timer(dev, t, detect_timer); 6178c2ecf20Sopenharmony_ci r592_update_card_detect(dev); 6188c2ecf20Sopenharmony_ci memstick_detect_change(dev->host); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci/* Interrupt handler */ 6228c2ecf20Sopenharmony_cistatic irqreturn_t r592_irq(int irq, void *data) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct r592_device *dev = (struct r592_device *)data; 6258c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 6268c2ecf20Sopenharmony_ci u32 reg; 6278c2ecf20Sopenharmony_ci u16 irq_enable, irq_status; 6288c2ecf20Sopenharmony_ci unsigned long flags; 6298c2ecf20Sopenharmony_ci int error; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->irq_lock, flags); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci reg = r592_read_reg(dev, R592_REG_MSC); 6348c2ecf20Sopenharmony_ci irq_enable = reg >> 16; 6358c2ecf20Sopenharmony_ci irq_status = reg & 0xFFFF; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* Ack the interrupts */ 6388c2ecf20Sopenharmony_ci reg &= ~irq_status; 6398c2ecf20Sopenharmony_ci r592_write_reg(dev, R592_REG_MSC, reg); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* Get the IRQ status minus bits that aren't enabled */ 6428c2ecf20Sopenharmony_ci irq_status &= (irq_enable); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Due to limitation of memstick core, we don't look at bits that 6458c2ecf20Sopenharmony_ci indicate that card was removed/inserted and/or present */ 6468c2ecf20Sopenharmony_ci if (irq_status & (R592_REG_MSC_IRQ_INSERT | R592_REG_MSC_IRQ_REMOVE)) { 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci bool card_was_added = irq_status & R592_REG_MSC_IRQ_INSERT; 6498c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci message("IRQ: card %s", card_was_added ? "added" : "removed"); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci mod_timer(&dev->detect_timer, 6548c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies(card_was_added ? 500 : 50)); 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (irq_status & 6588c2ecf20Sopenharmony_ci (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)) { 6598c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (irq_status & R592_REG_MSC_FIFO_DMA_ERR) { 6628c2ecf20Sopenharmony_ci message("IRQ: DMA error"); 6638c2ecf20Sopenharmony_ci error = -EIO; 6648c2ecf20Sopenharmony_ci } else { 6658c2ecf20Sopenharmony_ci dbg_verbose("IRQ: dma done"); 6668c2ecf20Sopenharmony_ci error = 0; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci r592_stop_dma(dev, error); 6708c2ecf20Sopenharmony_ci complete(&dev->dma_done); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->irq_lock, flags); 6748c2ecf20Sopenharmony_ci return ret; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci/* External inteface: set settings */ 6788c2ecf20Sopenharmony_cistatic int r592_set_param(struct memstick_host *host, 6798c2ecf20Sopenharmony_ci enum memstick_param param, int value) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct r592_device *dev = memstick_priv(host); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci switch (param) { 6848c2ecf20Sopenharmony_ci case MEMSTICK_POWER: 6858c2ecf20Sopenharmony_ci switch (value) { 6868c2ecf20Sopenharmony_ci case MEMSTICK_POWER_ON: 6878c2ecf20Sopenharmony_ci return r592_enable_device(dev, true); 6888c2ecf20Sopenharmony_ci case MEMSTICK_POWER_OFF: 6898c2ecf20Sopenharmony_ci return r592_enable_device(dev, false); 6908c2ecf20Sopenharmony_ci default: 6918c2ecf20Sopenharmony_ci return -EINVAL; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci case MEMSTICK_INTERFACE: 6948c2ecf20Sopenharmony_ci switch (value) { 6958c2ecf20Sopenharmony_ci case MEMSTICK_SERIAL: 6968c2ecf20Sopenharmony_ci return r592_set_mode(dev, 0); 6978c2ecf20Sopenharmony_ci case MEMSTICK_PAR4: 6988c2ecf20Sopenharmony_ci return r592_set_mode(dev, 1); 6998c2ecf20Sopenharmony_ci default: 7008c2ecf20Sopenharmony_ci return -EINVAL; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci default: 7038c2ecf20Sopenharmony_ci return -EINVAL; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci/* External interface: submit requests */ 7088c2ecf20Sopenharmony_cistatic void r592_submit_req(struct memstick_host *host) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci struct r592_device *dev = memstick_priv(host); 7118c2ecf20Sopenharmony_ci unsigned long flags; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (dev->req) 7148c2ecf20Sopenharmony_ci return; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->io_thread_lock, flags); 7178c2ecf20Sopenharmony_ci if (wake_up_process(dev->io_thread)) 7188c2ecf20Sopenharmony_ci dbg_verbose("IO thread woken to process requests"); 7198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->io_thread_lock, flags); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic const struct pci_device_id r592_pci_id_tbl[] = { 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci { PCI_VDEVICE(RICOH, 0x0592), }, 7258c2ecf20Sopenharmony_ci { }, 7268c2ecf20Sopenharmony_ci}; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci/* Main entry */ 7298c2ecf20Sopenharmony_cistatic int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci int error = -ENOMEM; 7328c2ecf20Sopenharmony_ci struct memstick_host *host; 7338c2ecf20Sopenharmony_ci struct r592_device *dev; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* Allocate memory */ 7368c2ecf20Sopenharmony_ci host = memstick_alloc_host(sizeof(struct r592_device), &pdev->dev); 7378c2ecf20Sopenharmony_ci if (!host) 7388c2ecf20Sopenharmony_ci goto error1; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci dev = memstick_priv(host); 7418c2ecf20Sopenharmony_ci dev->host = host; 7428c2ecf20Sopenharmony_ci dev->pci_dev = pdev; 7438c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* pci initialization */ 7468c2ecf20Sopenharmony_ci error = pci_enable_device(pdev); 7478c2ecf20Sopenharmony_ci if (error) 7488c2ecf20Sopenharmony_ci goto error2; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci pci_set_master(pdev); 7518c2ecf20Sopenharmony_ci error = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 7528c2ecf20Sopenharmony_ci if (error) 7538c2ecf20Sopenharmony_ci goto error3; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci error = pci_request_regions(pdev, DRV_NAME); 7568c2ecf20Sopenharmony_ci if (error) 7578c2ecf20Sopenharmony_ci goto error3; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci dev->mmio = pci_ioremap_bar(pdev, 0); 7608c2ecf20Sopenharmony_ci if (!dev->mmio) { 7618c2ecf20Sopenharmony_ci error = -ENOMEM; 7628c2ecf20Sopenharmony_ci goto error4; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci dev->irq = pdev->irq; 7668c2ecf20Sopenharmony_ci spin_lock_init(&dev->irq_lock); 7678c2ecf20Sopenharmony_ci spin_lock_init(&dev->io_thread_lock); 7688c2ecf20Sopenharmony_ci init_completion(&dev->dma_done); 7698c2ecf20Sopenharmony_ci INIT_KFIFO(dev->pio_fifo); 7708c2ecf20Sopenharmony_ci timer_setup(&dev->detect_timer, r592_detect_timer, 0); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* Host initialization */ 7738c2ecf20Sopenharmony_ci host->caps = MEMSTICK_CAP_PAR4; 7748c2ecf20Sopenharmony_ci host->request = r592_submit_req; 7758c2ecf20Sopenharmony_ci host->set_param = r592_set_param; 7768c2ecf20Sopenharmony_ci r592_check_dma(dev); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci dev->io_thread = kthread_run(r592_process_thread, dev, "r592_io"); 7798c2ecf20Sopenharmony_ci if (IS_ERR(dev->io_thread)) { 7808c2ecf20Sopenharmony_ci error = PTR_ERR(dev->io_thread); 7818c2ecf20Sopenharmony_ci goto error5; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* This is just a precation, so don't fail */ 7858c2ecf20Sopenharmony_ci dev->dummy_dma_page = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, 7868c2ecf20Sopenharmony_ci &dev->dummy_dma_page_physical_address, GFP_KERNEL); 7878c2ecf20Sopenharmony_ci r592_stop_dma(dev , 0); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci error = request_irq(dev->irq, &r592_irq, IRQF_SHARED, 7908c2ecf20Sopenharmony_ci DRV_NAME, dev); 7918c2ecf20Sopenharmony_ci if (error) 7928c2ecf20Sopenharmony_ci goto error6; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci r592_update_card_detect(dev); 7958c2ecf20Sopenharmony_ci error = memstick_add_host(host); 7968c2ecf20Sopenharmony_ci if (error) 7978c2ecf20Sopenharmony_ci goto error7; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci message("driver successfully loaded"); 8008c2ecf20Sopenharmony_ci return 0; 8018c2ecf20Sopenharmony_cierror7: 8028c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 8038c2ecf20Sopenharmony_cierror6: 8048c2ecf20Sopenharmony_ci if (dev->dummy_dma_page) 8058c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->dummy_dma_page, 8068c2ecf20Sopenharmony_ci dev->dummy_dma_page_physical_address); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci kthread_stop(dev->io_thread); 8098c2ecf20Sopenharmony_cierror5: 8108c2ecf20Sopenharmony_ci iounmap(dev->mmio); 8118c2ecf20Sopenharmony_cierror4: 8128c2ecf20Sopenharmony_ci pci_release_regions(pdev); 8138c2ecf20Sopenharmony_cierror3: 8148c2ecf20Sopenharmony_ci pci_disable_device(pdev); 8158c2ecf20Sopenharmony_cierror2: 8168c2ecf20Sopenharmony_ci memstick_free_host(host); 8178c2ecf20Sopenharmony_cierror1: 8188c2ecf20Sopenharmony_ci return error; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic void r592_remove(struct pci_dev *pdev) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci int error = 0; 8248c2ecf20Sopenharmony_ci struct r592_device *dev = pci_get_drvdata(pdev); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci /* Stop the processing thread. 8278c2ecf20Sopenharmony_ci That ensures that we won't take any more requests */ 8288c2ecf20Sopenharmony_ci kthread_stop(dev->io_thread); 8298c2ecf20Sopenharmony_ci del_timer_sync(&dev->detect_timer); 8308c2ecf20Sopenharmony_ci r592_enable_device(dev, false); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci while (!error && dev->req) { 8338c2ecf20Sopenharmony_ci dev->req->error = -ETIME; 8348c2ecf20Sopenharmony_ci error = memstick_next_req(dev->host, &dev->req); 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci memstick_remove_host(dev->host); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (dev->dummy_dma_page) 8398c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->dummy_dma_page, 8408c2ecf20Sopenharmony_ci dev->dummy_dma_page_physical_address); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 8438c2ecf20Sopenharmony_ci iounmap(dev->mmio); 8448c2ecf20Sopenharmony_ci pci_release_regions(pdev); 8458c2ecf20Sopenharmony_ci pci_disable_device(pdev); 8468c2ecf20Sopenharmony_ci memstick_free_host(dev->host); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 8508c2ecf20Sopenharmony_cistatic int r592_suspend(struct device *core_dev) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci struct r592_device *dev = dev_get_drvdata(core_dev); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci r592_clear_interrupts(dev); 8558c2ecf20Sopenharmony_ci memstick_suspend_host(dev->host); 8568c2ecf20Sopenharmony_ci del_timer_sync(&dev->detect_timer); 8578c2ecf20Sopenharmony_ci return 0; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic int r592_resume(struct device *core_dev) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci struct r592_device *dev = dev_get_drvdata(core_dev); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci r592_clear_interrupts(dev); 8658c2ecf20Sopenharmony_ci r592_enable_device(dev, false); 8668c2ecf20Sopenharmony_ci memstick_resume_host(dev->host); 8678c2ecf20Sopenharmony_ci r592_update_card_detect(dev); 8688c2ecf20Sopenharmony_ci return 0; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci#endif 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(r592_pm_ops, r592_suspend, r592_resume); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, r592_pci_id_tbl); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic struct pci_driver r852_pci_driver = { 8778c2ecf20Sopenharmony_ci .name = DRV_NAME, 8788c2ecf20Sopenharmony_ci .id_table = r592_pci_id_tbl, 8798c2ecf20Sopenharmony_ci .probe = r592_probe, 8808c2ecf20Sopenharmony_ci .remove = r592_remove, 8818c2ecf20Sopenharmony_ci .driver.pm = &r592_pm_ops, 8828c2ecf20Sopenharmony_ci}; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cimodule_pci_driver(r852_pci_driver); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cimodule_param_named(enable_dma, r592_enable_dma, bool, S_IRUGO); 8878c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); 8888c2ecf20Sopenharmony_cimodule_param(debug, int, S_IRUGO | S_IWUSR); 8898c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level (0-3)"); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 8928c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>"); 8938c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Ricoh R5C592 Memstick/Memstick PRO card reader driver"); 894