162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2010 - Maxim Levitsky 462306a36Sopenharmony_ci * driver for Ricoh memstick readers 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/freezer.h> 1062306a36Sopenharmony_ci#include <linux/jiffies.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <linux/pci_ids.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/kthread.h> 1762306a36Sopenharmony_ci#include <linux/sched.h> 1862306a36Sopenharmony_ci#include <linux/highmem.h> 1962306a36Sopenharmony_ci#include <asm/byteorder.h> 2062306a36Sopenharmony_ci#include <linux/swab.h> 2162306a36Sopenharmony_ci#include "r592.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic bool r592_enable_dma = 1; 2462306a36Sopenharmony_cistatic int debug; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const char *tpc_names[] = { 2762306a36Sopenharmony_ci "MS_TPC_READ_MG_STATUS", 2862306a36Sopenharmony_ci "MS_TPC_READ_LONG_DATA", 2962306a36Sopenharmony_ci "MS_TPC_READ_SHORT_DATA", 3062306a36Sopenharmony_ci "MS_TPC_READ_REG", 3162306a36Sopenharmony_ci "MS_TPC_READ_QUAD_DATA", 3262306a36Sopenharmony_ci "INVALID", 3362306a36Sopenharmony_ci "MS_TPC_GET_INT", 3462306a36Sopenharmony_ci "MS_TPC_SET_RW_REG_ADRS", 3562306a36Sopenharmony_ci "MS_TPC_EX_SET_CMD", 3662306a36Sopenharmony_ci "MS_TPC_WRITE_QUAD_DATA", 3762306a36Sopenharmony_ci "MS_TPC_WRITE_REG", 3862306a36Sopenharmony_ci "MS_TPC_WRITE_SHORT_DATA", 3962306a36Sopenharmony_ci "MS_TPC_WRITE_LONG_DATA", 4062306a36Sopenharmony_ci "MS_TPC_SET_CMD", 4162306a36Sopenharmony_ci}; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * memstick_debug_get_tpc_name - debug helper that returns string for 4562306a36Sopenharmony_ci * a TPC number 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistatic __maybe_unused const char *memstick_debug_get_tpc_name(int tpc) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return tpc_names[tpc-1]; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* Read a register*/ 5362306a36Sopenharmony_cistatic inline u32 r592_read_reg(struct r592_device *dev, int address) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci u32 value = readl(dev->mmio + address); 5662306a36Sopenharmony_ci dbg_reg("reg #%02d == 0x%08x", address, value); 5762306a36Sopenharmony_ci return value; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Write a register */ 6162306a36Sopenharmony_cistatic inline void r592_write_reg(struct r592_device *dev, 6262306a36Sopenharmony_ci int address, u32 value) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci dbg_reg("reg #%02d <- 0x%08x", address, value); 6562306a36Sopenharmony_ci writel(value, dev->mmio + address); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Reads a big endian DWORD register */ 6962306a36Sopenharmony_cistatic inline u32 r592_read_reg_raw_be(struct r592_device *dev, int address) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci u32 value = __raw_readl(dev->mmio + address); 7262306a36Sopenharmony_ci dbg_reg("reg #%02d == 0x%08x", address, value); 7362306a36Sopenharmony_ci return be32_to_cpu(value); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* Writes a big endian DWORD register */ 7762306a36Sopenharmony_cistatic inline void r592_write_reg_raw_be(struct r592_device *dev, 7862306a36Sopenharmony_ci int address, u32 value) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci dbg_reg("reg #%02d <- 0x%08x", address, value); 8162306a36Sopenharmony_ci __raw_writel(cpu_to_be32(value), dev->mmio + address); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Set specific bits in a register (little endian) */ 8562306a36Sopenharmony_cistatic inline void r592_set_reg_mask(struct r592_device *dev, 8662306a36Sopenharmony_ci int address, u32 mask) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci u32 reg = readl(dev->mmio + address); 8962306a36Sopenharmony_ci dbg_reg("reg #%02d |= 0x%08x (old =0x%08x)", address, mask, reg); 9062306a36Sopenharmony_ci writel(reg | mask , dev->mmio + address); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* Clear specific bits in a register (little endian) */ 9462306a36Sopenharmony_cistatic inline void r592_clear_reg_mask(struct r592_device *dev, 9562306a36Sopenharmony_ci int address, u32 mask) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci u32 reg = readl(dev->mmio + address); 9862306a36Sopenharmony_ci dbg_reg("reg #%02d &= 0x%08x (old = 0x%08x, mask = 0x%08x)", 9962306a36Sopenharmony_ci address, ~mask, reg, mask); 10062306a36Sopenharmony_ci writel(reg & ~mask, dev->mmio + address); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Wait for status bits while checking for errors */ 10562306a36Sopenharmony_cistatic int r592_wait_status(struct r592_device *dev, u32 mask, u32 wanted_mask) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(1000); 10862306a36Sopenharmony_ci u32 reg = r592_read_reg(dev, R592_STATUS); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if ((reg & mask) == wanted_mask) 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci while (time_before(jiffies, timeout)) { 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci reg = r592_read_reg(dev, R592_STATUS); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if ((reg & mask) == wanted_mask) 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (reg & (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR)) 12162306a36Sopenharmony_ci return -EIO; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci cpu_relax(); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci return -ETIME; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* Enable/disable device */ 13062306a36Sopenharmony_cistatic int r592_enable_device(struct r592_device *dev, bool enable) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci dbg("%sabling the device", enable ? "en" : "dis"); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (enable) { 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Power up the card */ 13762306a36Sopenharmony_ci r592_write_reg(dev, R592_POWER, R592_POWER_0 | R592_POWER_1); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* Perform a reset */ 14062306a36Sopenharmony_ci r592_set_reg_mask(dev, R592_IO, R592_IO_RESET); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci msleep(100); 14362306a36Sopenharmony_ci } else 14462306a36Sopenharmony_ci /* Power down the card */ 14562306a36Sopenharmony_ci r592_write_reg(dev, R592_POWER, 0); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* Set serial/parallel mode */ 15162306a36Sopenharmony_cistatic int r592_set_mode(struct r592_device *dev, bool parallel_mode) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci if (!parallel_mode) { 15462306a36Sopenharmony_ci dbg("switching to serial mode"); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Set serial mode */ 15762306a36Sopenharmony_ci r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_SERIAL); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_POWER, R592_POWER_20); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci } else { 16262306a36Sopenharmony_ci dbg("switching to parallel mode"); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* This setting should be set _before_ switch TPC */ 16562306a36Sopenharmony_ci r592_set_reg_mask(dev, R592_POWER, R592_POWER_20); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_IO, 16862306a36Sopenharmony_ci R592_IO_SERIAL1 | R592_IO_SERIAL2); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Set the parallel mode now */ 17162306a36Sopenharmony_ci r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_PARALLEL); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci dev->parallel_mode = parallel_mode; 17562306a36Sopenharmony_ci return 0; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* Perform a controller reset without powering down the card */ 17962306a36Sopenharmony_cistatic void r592_host_reset(struct r592_device *dev) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci r592_set_reg_mask(dev, R592_IO, R592_IO_RESET); 18262306a36Sopenharmony_ci msleep(100); 18362306a36Sopenharmony_ci r592_set_mode(dev, dev->parallel_mode); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 18762306a36Sopenharmony_ci/* Disable all hardware interrupts */ 18862306a36Sopenharmony_cistatic void r592_clear_interrupts(struct r592_device *dev) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci /* Disable & ACK all interrupts */ 19162306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK); 19262306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci#endif 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* Tests if there is an CRC error */ 19762306a36Sopenharmony_cistatic int r592_test_io_error(struct r592_device *dev) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci if (!(r592_read_reg(dev, R592_STATUS) & 20062306a36Sopenharmony_ci (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR))) 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return -EIO; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* Ensure that FIFO is ready for use */ 20762306a36Sopenharmony_cistatic int r592_test_fifo_empty(struct r592_device *dev) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY) 21062306a36Sopenharmony_ci return 0; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci dbg("FIFO not ready, trying to reset the device"); 21362306a36Sopenharmony_ci r592_host_reset(dev); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY) 21662306a36Sopenharmony_ci return 0; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci message("FIFO still not ready, giving up"); 21962306a36Sopenharmony_ci return -EIO; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* Activates the DMA transfer from to FIFO */ 22362306a36Sopenharmony_cistatic void r592_start_dma(struct r592_device *dev, bool is_write) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci unsigned long flags; 22662306a36Sopenharmony_ci u32 reg; 22762306a36Sopenharmony_ci spin_lock_irqsave(&dev->irq_lock, flags); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Ack interrupts (just in case) + enable them */ 23062306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK); 23162306a36Sopenharmony_ci r592_set_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Set DMA address */ 23462306a36Sopenharmony_ci r592_write_reg(dev, R592_FIFO_DMA, sg_dma_address(&dev->req->sg)); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* Enable the DMA */ 23762306a36Sopenharmony_ci reg = r592_read_reg(dev, R592_FIFO_DMA_SETTINGS); 23862306a36Sopenharmony_ci reg |= R592_FIFO_DMA_SETTINGS_EN; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!is_write) 24162306a36Sopenharmony_ci reg |= R592_FIFO_DMA_SETTINGS_DIR; 24262306a36Sopenharmony_ci else 24362306a36Sopenharmony_ci reg &= ~R592_FIFO_DMA_SETTINGS_DIR; 24462306a36Sopenharmony_ci r592_write_reg(dev, R592_FIFO_DMA_SETTINGS, reg); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->irq_lock, flags); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/* Cleanups DMA related settings */ 25062306a36Sopenharmony_cistatic void r592_stop_dma(struct r592_device *dev, int error) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_FIFO_DMA_SETTINGS, 25362306a36Sopenharmony_ci R592_FIFO_DMA_SETTINGS_EN); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* This is only a precation */ 25662306a36Sopenharmony_ci r592_write_reg(dev, R592_FIFO_DMA, 25762306a36Sopenharmony_ci dev->dummy_dma_page_physical_address); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK); 26062306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK); 26162306a36Sopenharmony_ci dev->dma_error = error; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* Test if hardware supports DMA */ 26562306a36Sopenharmony_cistatic void r592_check_dma(struct r592_device *dev) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci dev->dma_capable = r592_enable_dma && 26862306a36Sopenharmony_ci (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & 26962306a36Sopenharmony_ci R592_FIFO_DMA_SETTINGS_CAP); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* Transfers fifo contents in/out using DMA */ 27362306a36Sopenharmony_cistatic int r592_transfer_fifo_dma(struct r592_device *dev) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci int len, sg_count; 27662306a36Sopenharmony_ci bool is_write; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!dev->dma_capable || !dev->req->long_data) 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci len = dev->req->sg.length; 28262306a36Sopenharmony_ci is_write = dev->req->data_dir == WRITE; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (len != R592_LFIFO_SIZE) 28562306a36Sopenharmony_ci return -EINVAL; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci dbg_verbose("doing dma transfer"); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci dev->dma_error = 0; 29062306a36Sopenharmony_ci reinit_completion(&dev->dma_done); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* TODO: hidden assumption about nenth beeing always 1 */ 29362306a36Sopenharmony_ci sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? 29462306a36Sopenharmony_ci DMA_TO_DEVICE : DMA_FROM_DEVICE); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (sg_count != 1 || sg_dma_len(&dev->req->sg) < R592_LFIFO_SIZE) { 29762306a36Sopenharmony_ci message("problem in dma_map_sg"); 29862306a36Sopenharmony_ci return -EIO; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci r592_start_dma(dev, is_write); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* Wait for DMA completion */ 30462306a36Sopenharmony_ci if (!wait_for_completion_timeout( 30562306a36Sopenharmony_ci &dev->dma_done, msecs_to_jiffies(1000))) { 30662306a36Sopenharmony_ci message("DMA timeout"); 30762306a36Sopenharmony_ci r592_stop_dma(dev, -ETIMEDOUT); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci dma_unmap_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? 31162306a36Sopenharmony_ci DMA_TO_DEVICE : DMA_FROM_DEVICE); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return dev->dma_error; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* 31762306a36Sopenharmony_ci * Writes the FIFO in 4 byte chunks. 31862306a36Sopenharmony_ci * If length isn't 4 byte aligned, rest of the data if put to a fifo 31962306a36Sopenharmony_ci * to be written later 32062306a36Sopenharmony_ci * Use r592_flush_fifo_write to flush that fifo when writing for the 32162306a36Sopenharmony_ci * last time 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_cistatic void r592_write_fifo_pio(struct r592_device *dev, 32462306a36Sopenharmony_ci unsigned char *buffer, int len) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci /* flush spill from former write */ 32762306a36Sopenharmony_ci if (!kfifo_is_empty(&dev->pio_fifo)) { 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci u8 tmp[4] = {0}; 33062306a36Sopenharmony_ci int copy_len = kfifo_in(&dev->pio_fifo, buffer, len); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (!kfifo_is_full(&dev->pio_fifo)) 33362306a36Sopenharmony_ci return; 33462306a36Sopenharmony_ci len -= copy_len; 33562306a36Sopenharmony_ci buffer += copy_len; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci copy_len = kfifo_out(&dev->pio_fifo, tmp, 4); 33862306a36Sopenharmony_ci WARN_ON(copy_len != 4); 33962306a36Sopenharmony_ci r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)tmp); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci WARN_ON(!kfifo_is_empty(&dev->pio_fifo)); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* write full dwords */ 34562306a36Sopenharmony_ci while (len >= 4) { 34662306a36Sopenharmony_ci r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer); 34762306a36Sopenharmony_ci buffer += 4; 34862306a36Sopenharmony_ci len -= 4; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* put remaining bytes to the spill */ 35262306a36Sopenharmony_ci if (len) 35362306a36Sopenharmony_ci kfifo_in(&dev->pio_fifo, buffer, len); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* Flushes the temporary FIFO used to make aligned DWORD writes */ 35762306a36Sopenharmony_cistatic void r592_flush_fifo_write(struct r592_device *dev) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci int ret; 36062306a36Sopenharmony_ci u8 buffer[4] = { 0 }; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (kfifo_is_empty(&dev->pio_fifo)) 36362306a36Sopenharmony_ci return; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ret = kfifo_out(&dev->pio_fifo, buffer, 4); 36662306a36Sopenharmony_ci /* intentionally ignore __must_check return code */ 36762306a36Sopenharmony_ci (void)ret; 36862306a36Sopenharmony_ci r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/* 37262306a36Sopenharmony_ci * Read a fifo in 4 bytes chunks. 37362306a36Sopenharmony_ci * If input doesn't fit the buffer, it places bytes of last dword in spill 37462306a36Sopenharmony_ci * buffer, so that they don't get lost on last read, just throw these away. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_cistatic void r592_read_fifo_pio(struct r592_device *dev, 37762306a36Sopenharmony_ci unsigned char *buffer, int len) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci u8 tmp[4]; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Read from last spill */ 38262306a36Sopenharmony_ci if (!kfifo_is_empty(&dev->pio_fifo)) { 38362306a36Sopenharmony_ci int bytes_copied = 38462306a36Sopenharmony_ci kfifo_out(&dev->pio_fifo, buffer, min(4, len)); 38562306a36Sopenharmony_ci buffer += bytes_copied; 38662306a36Sopenharmony_ci len -= bytes_copied; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (!kfifo_is_empty(&dev->pio_fifo)) 38962306a36Sopenharmony_ci return; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Reads dwords from FIFO */ 39362306a36Sopenharmony_ci while (len >= 4) { 39462306a36Sopenharmony_ci *(u32 *)buffer = r592_read_reg_raw_be(dev, R592_FIFO_PIO); 39562306a36Sopenharmony_ci buffer += 4; 39662306a36Sopenharmony_ci len -= 4; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (len) { 40062306a36Sopenharmony_ci *(u32 *)tmp = r592_read_reg_raw_be(dev, R592_FIFO_PIO); 40162306a36Sopenharmony_ci kfifo_in(&dev->pio_fifo, tmp, 4); 40262306a36Sopenharmony_ci len -= kfifo_out(&dev->pio_fifo, buffer, len); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci WARN_ON(len); 40662306a36Sopenharmony_ci return; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/* Transfers actual data using PIO. */ 41062306a36Sopenharmony_cistatic int r592_transfer_fifo_pio(struct r592_device *dev) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci unsigned long flags; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS; 41562306a36Sopenharmony_ci struct sg_mapping_iter miter; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci kfifo_reset(&dev->pio_fifo); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!dev->req->long_data) { 42062306a36Sopenharmony_ci if (is_write) { 42162306a36Sopenharmony_ci r592_write_fifo_pio(dev, dev->req->data, 42262306a36Sopenharmony_ci dev->req->data_len); 42362306a36Sopenharmony_ci r592_flush_fifo_write(dev); 42462306a36Sopenharmony_ci } else 42562306a36Sopenharmony_ci r592_read_fifo_pio(dev, dev->req->data, 42662306a36Sopenharmony_ci dev->req->data_len); 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci local_irq_save(flags); 43162306a36Sopenharmony_ci sg_miter_start(&miter, &dev->req->sg, 1, SG_MITER_ATOMIC | 43262306a36Sopenharmony_ci (is_write ? SG_MITER_FROM_SG : SG_MITER_TO_SG)); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Do the transfer fifo<->memory*/ 43562306a36Sopenharmony_ci while (sg_miter_next(&miter)) 43662306a36Sopenharmony_ci if (is_write) 43762306a36Sopenharmony_ci r592_write_fifo_pio(dev, miter.addr, miter.length); 43862306a36Sopenharmony_ci else 43962306a36Sopenharmony_ci r592_read_fifo_pio(dev, miter.addr, miter.length); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* Write last few non aligned bytes*/ 44362306a36Sopenharmony_ci if (is_write) 44462306a36Sopenharmony_ci r592_flush_fifo_write(dev); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci sg_miter_stop(&miter); 44762306a36Sopenharmony_ci local_irq_restore(flags); 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci/* Executes one TPC (data is read/written from small or large fifo) */ 45262306a36Sopenharmony_cistatic void r592_execute_tpc(struct r592_device *dev) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci bool is_write; 45562306a36Sopenharmony_ci int len, error; 45662306a36Sopenharmony_ci u32 status, reg; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (!dev->req) { 45962306a36Sopenharmony_ci message("BUG: tpc execution without request!"); 46062306a36Sopenharmony_ci return; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS; 46462306a36Sopenharmony_ci len = dev->req->long_data ? 46562306a36Sopenharmony_ci dev->req->sg.length : dev->req->data_len; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Ensure that FIFO can hold the input data */ 46862306a36Sopenharmony_ci if (len > R592_LFIFO_SIZE) { 46962306a36Sopenharmony_ci message("IO: hardware doesn't support TPCs longer that 512"); 47062306a36Sopenharmony_ci error = -ENOSYS; 47162306a36Sopenharmony_ci goto out; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!(r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_PRSNT)) { 47562306a36Sopenharmony_ci dbg("IO: refusing to send TPC because card is absent"); 47662306a36Sopenharmony_ci error = -ENODEV; 47762306a36Sopenharmony_ci goto out; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci dbg("IO: executing %s LEN=%d", 48162306a36Sopenharmony_ci memstick_debug_get_tpc_name(dev->req->tpc), len); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Set IO direction */ 48462306a36Sopenharmony_ci if (is_write) 48562306a36Sopenharmony_ci r592_set_reg_mask(dev, R592_IO, R592_IO_DIRECTION); 48662306a36Sopenharmony_ci else 48762306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_IO, R592_IO_DIRECTION); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci error = r592_test_fifo_empty(dev); 49162306a36Sopenharmony_ci if (error) 49262306a36Sopenharmony_ci goto out; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Transfer write data */ 49562306a36Sopenharmony_ci if (is_write) { 49662306a36Sopenharmony_ci error = r592_transfer_fifo_dma(dev); 49762306a36Sopenharmony_ci if (error == -EINVAL) 49862306a36Sopenharmony_ci error = r592_transfer_fifo_pio(dev); 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (error) 50262306a36Sopenharmony_ci goto out; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* Trigger the TPC */ 50562306a36Sopenharmony_ci reg = (len << R592_TPC_EXEC_LEN_SHIFT) | 50662306a36Sopenharmony_ci (dev->req->tpc << R592_TPC_EXEC_TPC_SHIFT) | 50762306a36Sopenharmony_ci R592_TPC_EXEC_BIG_FIFO; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci r592_write_reg(dev, R592_TPC_EXEC, reg); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* Wait for TPC completion */ 51262306a36Sopenharmony_ci status = R592_STATUS_RDY; 51362306a36Sopenharmony_ci if (dev->req->need_card_int) 51462306a36Sopenharmony_ci status |= R592_STATUS_CED; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci error = r592_wait_status(dev, status, status); 51762306a36Sopenharmony_ci if (error) { 51862306a36Sopenharmony_ci message("card didn't respond"); 51962306a36Sopenharmony_ci goto out; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Test IO errors */ 52362306a36Sopenharmony_ci error = r592_test_io_error(dev); 52462306a36Sopenharmony_ci if (error) { 52562306a36Sopenharmony_ci dbg("IO error"); 52662306a36Sopenharmony_ci goto out; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* Read data from FIFO */ 53062306a36Sopenharmony_ci if (!is_write) { 53162306a36Sopenharmony_ci error = r592_transfer_fifo_dma(dev); 53262306a36Sopenharmony_ci if (error == -EINVAL) 53362306a36Sopenharmony_ci error = r592_transfer_fifo_pio(dev); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* read INT reg. This can be shortened with shifts, but that way 53762306a36Sopenharmony_ci its more readable */ 53862306a36Sopenharmony_ci if (dev->parallel_mode && dev->req->need_card_int) { 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci dev->req->int_reg = 0; 54162306a36Sopenharmony_ci status = r592_read_reg(dev, R592_STATUS); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (status & R592_STATUS_P_CMDNACK) 54462306a36Sopenharmony_ci dev->req->int_reg |= MEMSTICK_INT_CMDNAK; 54562306a36Sopenharmony_ci if (status & R592_STATUS_P_BREQ) 54662306a36Sopenharmony_ci dev->req->int_reg |= MEMSTICK_INT_BREQ; 54762306a36Sopenharmony_ci if (status & R592_STATUS_P_INTERR) 54862306a36Sopenharmony_ci dev->req->int_reg |= MEMSTICK_INT_ERR; 54962306a36Sopenharmony_ci if (status & R592_STATUS_P_CED) 55062306a36Sopenharmony_ci dev->req->int_reg |= MEMSTICK_INT_CED; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (error) 55462306a36Sopenharmony_ci dbg("FIFO read error"); 55562306a36Sopenharmony_ciout: 55662306a36Sopenharmony_ci dev->req->error = error; 55762306a36Sopenharmony_ci r592_clear_reg_mask(dev, R592_REG_MSC, R592_REG_MSC_LED); 55862306a36Sopenharmony_ci return; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci/* Main request processing thread */ 56262306a36Sopenharmony_cistatic int r592_process_thread(void *data) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci int error; 56562306a36Sopenharmony_ci struct r592_device *dev = (struct r592_device *)data; 56662306a36Sopenharmony_ci unsigned long flags; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci while (!kthread_should_stop()) { 56962306a36Sopenharmony_ci spin_lock_irqsave(&dev->io_thread_lock, flags); 57062306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 57162306a36Sopenharmony_ci error = memstick_next_req(dev->host, &dev->req); 57262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->io_thread_lock, flags); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (error) { 57562306a36Sopenharmony_ci if (error == -ENXIO || error == -EAGAIN) { 57662306a36Sopenharmony_ci dbg_verbose("IO: done IO, sleeping"); 57762306a36Sopenharmony_ci } else { 57862306a36Sopenharmony_ci dbg("IO: unknown error from " 57962306a36Sopenharmony_ci "memstick_next_req %d", error); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (kthread_should_stop()) 58362306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci schedule(); 58662306a36Sopenharmony_ci } else { 58762306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 58862306a36Sopenharmony_ci r592_execute_tpc(dev); 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/* Reprogram chip to detect change in card state */ 59562306a36Sopenharmony_ci/* eg, if card is detected, arm it to detect removal, and vice versa */ 59662306a36Sopenharmony_cistatic void r592_update_card_detect(struct r592_device *dev) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci u32 reg = r592_read_reg(dev, R592_REG_MSC); 59962306a36Sopenharmony_ci bool card_detected = reg & R592_REG_MSC_PRSNT; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci dbg("update card detect. card state: %s", card_detected ? 60262306a36Sopenharmony_ci "present" : "absent"); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci reg &= ~((R592_REG_MSC_IRQ_REMOVE | R592_REG_MSC_IRQ_INSERT) << 16); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (card_detected) 60762306a36Sopenharmony_ci reg |= (R592_REG_MSC_IRQ_REMOVE << 16); 60862306a36Sopenharmony_ci else 60962306a36Sopenharmony_ci reg |= (R592_REG_MSC_IRQ_INSERT << 16); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci r592_write_reg(dev, R592_REG_MSC, reg); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/* Timer routine that fires 1 second after last card detection event, */ 61562306a36Sopenharmony_cistatic void r592_detect_timer(struct timer_list *t) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct r592_device *dev = from_timer(dev, t, detect_timer); 61862306a36Sopenharmony_ci r592_update_card_detect(dev); 61962306a36Sopenharmony_ci memstick_detect_change(dev->host); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/* Interrupt handler */ 62362306a36Sopenharmony_cistatic irqreturn_t r592_irq(int irq, void *data) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct r592_device *dev = (struct r592_device *)data; 62662306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 62762306a36Sopenharmony_ci u32 reg; 62862306a36Sopenharmony_ci u16 irq_enable, irq_status; 62962306a36Sopenharmony_ci unsigned long flags; 63062306a36Sopenharmony_ci int error; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci spin_lock_irqsave(&dev->irq_lock, flags); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci reg = r592_read_reg(dev, R592_REG_MSC); 63562306a36Sopenharmony_ci irq_enable = reg >> 16; 63662306a36Sopenharmony_ci irq_status = reg & 0xFFFF; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Ack the interrupts */ 63962306a36Sopenharmony_ci reg &= ~irq_status; 64062306a36Sopenharmony_ci r592_write_reg(dev, R592_REG_MSC, reg); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* Get the IRQ status minus bits that aren't enabled */ 64362306a36Sopenharmony_ci irq_status &= (irq_enable); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* Due to limitation of memstick core, we don't look at bits that 64662306a36Sopenharmony_ci indicate that card was removed/inserted and/or present */ 64762306a36Sopenharmony_ci if (irq_status & (R592_REG_MSC_IRQ_INSERT | R592_REG_MSC_IRQ_REMOVE)) { 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci bool card_was_added = irq_status & R592_REG_MSC_IRQ_INSERT; 65062306a36Sopenharmony_ci ret = IRQ_HANDLED; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci message("IRQ: card %s", card_was_added ? "added" : "removed"); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci mod_timer(&dev->detect_timer, 65562306a36Sopenharmony_ci jiffies + msecs_to_jiffies(card_was_added ? 500 : 50)); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci if (irq_status & 65962306a36Sopenharmony_ci (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)) { 66062306a36Sopenharmony_ci ret = IRQ_HANDLED; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (irq_status & R592_REG_MSC_FIFO_DMA_ERR) { 66362306a36Sopenharmony_ci message("IRQ: DMA error"); 66462306a36Sopenharmony_ci error = -EIO; 66562306a36Sopenharmony_ci } else { 66662306a36Sopenharmony_ci dbg_verbose("IRQ: dma done"); 66762306a36Sopenharmony_ci error = 0; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci r592_stop_dma(dev, error); 67162306a36Sopenharmony_ci complete(&dev->dma_done); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->irq_lock, flags); 67562306a36Sopenharmony_ci return ret; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/* External inteface: set settings */ 67962306a36Sopenharmony_cistatic int r592_set_param(struct memstick_host *host, 68062306a36Sopenharmony_ci enum memstick_param param, int value) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct r592_device *dev = memstick_priv(host); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci switch (param) { 68562306a36Sopenharmony_ci case MEMSTICK_POWER: 68662306a36Sopenharmony_ci switch (value) { 68762306a36Sopenharmony_ci case MEMSTICK_POWER_ON: 68862306a36Sopenharmony_ci return r592_enable_device(dev, true); 68962306a36Sopenharmony_ci case MEMSTICK_POWER_OFF: 69062306a36Sopenharmony_ci return r592_enable_device(dev, false); 69162306a36Sopenharmony_ci default: 69262306a36Sopenharmony_ci return -EINVAL; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci case MEMSTICK_INTERFACE: 69562306a36Sopenharmony_ci switch (value) { 69662306a36Sopenharmony_ci case MEMSTICK_SERIAL: 69762306a36Sopenharmony_ci return r592_set_mode(dev, 0); 69862306a36Sopenharmony_ci case MEMSTICK_PAR4: 69962306a36Sopenharmony_ci return r592_set_mode(dev, 1); 70062306a36Sopenharmony_ci default: 70162306a36Sopenharmony_ci return -EINVAL; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci default: 70462306a36Sopenharmony_ci return -EINVAL; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci/* External interface: submit requests */ 70962306a36Sopenharmony_cistatic void r592_submit_req(struct memstick_host *host) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct r592_device *dev = memstick_priv(host); 71262306a36Sopenharmony_ci unsigned long flags; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (dev->req) 71562306a36Sopenharmony_ci return; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci spin_lock_irqsave(&dev->io_thread_lock, flags); 71862306a36Sopenharmony_ci if (wake_up_process(dev->io_thread)) 71962306a36Sopenharmony_ci dbg_verbose("IO thread woken to process requests"); 72062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->io_thread_lock, flags); 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic const struct pci_device_id r592_pci_id_tbl[] = { 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci { PCI_VDEVICE(RICOH, 0x0592), }, 72662306a36Sopenharmony_ci { }, 72762306a36Sopenharmony_ci}; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci/* Main entry */ 73062306a36Sopenharmony_cistatic int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci int error = -ENOMEM; 73362306a36Sopenharmony_ci struct memstick_host *host; 73462306a36Sopenharmony_ci struct r592_device *dev; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Allocate memory */ 73762306a36Sopenharmony_ci host = memstick_alloc_host(sizeof(struct r592_device), &pdev->dev); 73862306a36Sopenharmony_ci if (!host) 73962306a36Sopenharmony_ci goto error1; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci dev = memstick_priv(host); 74262306a36Sopenharmony_ci dev->host = host; 74362306a36Sopenharmony_ci dev->pci_dev = pdev; 74462306a36Sopenharmony_ci pci_set_drvdata(pdev, dev); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* pci initialization */ 74762306a36Sopenharmony_ci error = pci_enable_device(pdev); 74862306a36Sopenharmony_ci if (error) 74962306a36Sopenharmony_ci goto error2; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci pci_set_master(pdev); 75262306a36Sopenharmony_ci error = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 75362306a36Sopenharmony_ci if (error) 75462306a36Sopenharmony_ci goto error3; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci error = pci_request_regions(pdev, DRV_NAME); 75762306a36Sopenharmony_ci if (error) 75862306a36Sopenharmony_ci goto error3; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci dev->mmio = pci_ioremap_bar(pdev, 0); 76162306a36Sopenharmony_ci if (!dev->mmio) { 76262306a36Sopenharmony_ci error = -ENOMEM; 76362306a36Sopenharmony_ci goto error4; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci dev->irq = pdev->irq; 76762306a36Sopenharmony_ci spin_lock_init(&dev->irq_lock); 76862306a36Sopenharmony_ci spin_lock_init(&dev->io_thread_lock); 76962306a36Sopenharmony_ci init_completion(&dev->dma_done); 77062306a36Sopenharmony_ci INIT_KFIFO(dev->pio_fifo); 77162306a36Sopenharmony_ci timer_setup(&dev->detect_timer, r592_detect_timer, 0); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* Host initialization */ 77462306a36Sopenharmony_ci host->caps = MEMSTICK_CAP_PAR4; 77562306a36Sopenharmony_ci host->request = r592_submit_req; 77662306a36Sopenharmony_ci host->set_param = r592_set_param; 77762306a36Sopenharmony_ci r592_check_dma(dev); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci dev->io_thread = kthread_run(r592_process_thread, dev, "r592_io"); 78062306a36Sopenharmony_ci if (IS_ERR(dev->io_thread)) { 78162306a36Sopenharmony_ci error = PTR_ERR(dev->io_thread); 78262306a36Sopenharmony_ci goto error5; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* This is just a precation, so don't fail */ 78662306a36Sopenharmony_ci dev->dummy_dma_page = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, 78762306a36Sopenharmony_ci &dev->dummy_dma_page_physical_address, GFP_KERNEL); 78862306a36Sopenharmony_ci r592_stop_dma(dev , 0); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci error = request_irq(dev->irq, &r592_irq, IRQF_SHARED, 79162306a36Sopenharmony_ci DRV_NAME, dev); 79262306a36Sopenharmony_ci if (error) 79362306a36Sopenharmony_ci goto error6; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci r592_update_card_detect(dev); 79662306a36Sopenharmony_ci error = memstick_add_host(host); 79762306a36Sopenharmony_ci if (error) 79862306a36Sopenharmony_ci goto error7; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci message("driver successfully loaded"); 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_cierror7: 80362306a36Sopenharmony_ci free_irq(dev->irq, dev); 80462306a36Sopenharmony_cierror6: 80562306a36Sopenharmony_ci if (dev->dummy_dma_page) 80662306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->dummy_dma_page, 80762306a36Sopenharmony_ci dev->dummy_dma_page_physical_address); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci kthread_stop(dev->io_thread); 81062306a36Sopenharmony_cierror5: 81162306a36Sopenharmony_ci iounmap(dev->mmio); 81262306a36Sopenharmony_cierror4: 81362306a36Sopenharmony_ci pci_release_regions(pdev); 81462306a36Sopenharmony_cierror3: 81562306a36Sopenharmony_ci pci_disable_device(pdev); 81662306a36Sopenharmony_cierror2: 81762306a36Sopenharmony_ci memstick_free_host(host); 81862306a36Sopenharmony_cierror1: 81962306a36Sopenharmony_ci return error; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic void r592_remove(struct pci_dev *pdev) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci int error = 0; 82562306a36Sopenharmony_ci struct r592_device *dev = pci_get_drvdata(pdev); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* Stop the processing thread. 82862306a36Sopenharmony_ci That ensures that we won't take any more requests */ 82962306a36Sopenharmony_ci kthread_stop(dev->io_thread); 83062306a36Sopenharmony_ci del_timer_sync(&dev->detect_timer); 83162306a36Sopenharmony_ci r592_enable_device(dev, false); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci while (!error && dev->req) { 83462306a36Sopenharmony_ci dev->req->error = -ETIME; 83562306a36Sopenharmony_ci error = memstick_next_req(dev->host, &dev->req); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci memstick_remove_host(dev->host); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (dev->dummy_dma_page) 84062306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->dummy_dma_page, 84162306a36Sopenharmony_ci dev->dummy_dma_page_physical_address); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci free_irq(dev->irq, dev); 84462306a36Sopenharmony_ci iounmap(dev->mmio); 84562306a36Sopenharmony_ci pci_release_regions(pdev); 84662306a36Sopenharmony_ci pci_disable_device(pdev); 84762306a36Sopenharmony_ci memstick_free_host(dev->host); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 85162306a36Sopenharmony_cistatic int r592_suspend(struct device *core_dev) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct r592_device *dev = dev_get_drvdata(core_dev); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci r592_clear_interrupts(dev); 85662306a36Sopenharmony_ci memstick_suspend_host(dev->host); 85762306a36Sopenharmony_ci del_timer_sync(&dev->detect_timer); 85862306a36Sopenharmony_ci return 0; 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic int r592_resume(struct device *core_dev) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct r592_device *dev = dev_get_drvdata(core_dev); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci r592_clear_interrupts(dev); 86662306a36Sopenharmony_ci r592_enable_device(dev, false); 86762306a36Sopenharmony_ci memstick_resume_host(dev->host); 86862306a36Sopenharmony_ci r592_update_card_detect(dev); 86962306a36Sopenharmony_ci return 0; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci#endif 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(r592_pm_ops, r592_suspend, r592_resume); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, r592_pci_id_tbl); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic struct pci_driver r592_pci_driver = { 87862306a36Sopenharmony_ci .name = DRV_NAME, 87962306a36Sopenharmony_ci .id_table = r592_pci_id_tbl, 88062306a36Sopenharmony_ci .probe = r592_probe, 88162306a36Sopenharmony_ci .remove = r592_remove, 88262306a36Sopenharmony_ci .driver.pm = &r592_pm_ops, 88362306a36Sopenharmony_ci}; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cimodule_pci_driver(r592_pci_driver); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cimodule_param_named(enable_dma, r592_enable_dma, bool, S_IRUGO); 88862306a36Sopenharmony_ciMODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); 88962306a36Sopenharmony_cimodule_param(debug, int, S_IRUGO | S_IWUSR); 89062306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level (0-3)"); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 89362306a36Sopenharmony_ciMODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>"); 89462306a36Sopenharmony_ciMODULE_DESCRIPTION("Ricoh R5C592 Memstick/Memstick PRO card reader driver"); 895