balloon3-pcmcia.c (3510B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * linux/drivers/pcmcia/pxa2xx_balloon3.c 4 * 5 * Balloon3 PCMCIA specific routines. 6 * 7 * Author: Nick Bane 8 * Created: June, 2006 9 * Copyright: Toby Churchill Ltd 10 * Derived from pxa2xx_mainstone.c, by Nico Pitre 11 * 12 * Various modification by Marek Vasut <marek.vasut@gmail.com> 13 */ 14 15#include <linux/module.h> 16#include <linux/gpio.h> 17#include <linux/errno.h> 18#include <linux/interrupt.h> 19#include <linux/platform_device.h> 20#include <linux/irq.h> 21#include <linux/io.h> 22 23#include "balloon3.h" 24 25#include <asm/mach-types.h> 26 27#include <pcmcia/soc_common.h> 28 29static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt) 30{ 31 uint16_t ver; 32 33 ver = __raw_readw(BALLOON3_FPGA_VER); 34 if (ver < 0x4f08) 35 pr_warn("The FPGA code, version 0x%04x, is too old. " 36 "PCMCIA/CF support might be broken in this version!", 37 ver); 38 39 skt->socket.pci_irq = BALLOON3_BP_CF_NRDY_IRQ; 40 skt->stat[SOC_STAT_CD].gpio = BALLOON3_GPIO_S0_CD; 41 skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD"; 42 skt->stat[SOC_STAT_BVD1].irq = BALLOON3_BP_NSTSCHG_IRQ; 43 skt->stat[SOC_STAT_BVD1].name = "PCMCIA0 STSCHG"; 44 45 return 0; 46} 47 48static unsigned long balloon3_pcmcia_status[2] = { 49 BALLOON3_CF_nSTSCHG_BVD1, 50 BALLOON3_CF_nSTSCHG_BVD1 51}; 52 53static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt, 54 struct pcmcia_state *state) 55{ 56 uint16_t status; 57 int flip; 58 59 /* This actually reads the STATUS register */ 60 status = __raw_readw(BALLOON3_CF_STATUS_REG); 61 flip = (status ^ balloon3_pcmcia_status[skt->nr]) 62 & BALLOON3_CF_nSTSCHG_BVD1; 63 /* 64 * Workaround for STSCHG which can't be deasserted: 65 * We therefore disable/enable corresponding IRQs 66 * as needed to avoid IRQ locks. 67 */ 68 if (flip) { 69 balloon3_pcmcia_status[skt->nr] = status; 70 if (status & BALLOON3_CF_nSTSCHG_BVD1) 71 enable_irq(BALLOON3_BP_NSTSCHG_IRQ); 72 else 73 disable_irq(BALLOON3_BP_NSTSCHG_IRQ); 74 } 75 76 state->ready = !!(status & BALLOON3_CF_nIRQ); 77 state->bvd1 = !!(status & BALLOON3_CF_nSTSCHG_BVD1); 78 state->bvd2 = 0; /* not available */ 79 state->vs_3v = 1; /* Always true its a CF card */ 80 state->vs_Xv = 0; /* not available */ 81} 82 83static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, 84 const socket_state_t *state) 85{ 86 __raw_writew(BALLOON3_CF_RESET, BALLOON3_CF_CONTROL_REG + 87 ((state->flags & SS_RESET) ? 88 BALLOON3_FPGA_SETnCLR : 0)); 89 return 0; 90} 91 92static struct pcmcia_low_level balloon3_pcmcia_ops = { 93 .owner = THIS_MODULE, 94 .hw_init = balloon3_pcmcia_hw_init, 95 .socket_state = balloon3_pcmcia_socket_state, 96 .configure_socket = balloon3_pcmcia_configure_socket, 97 .first = 0, 98 .nr = 1, 99}; 100 101static struct platform_device *balloon3_pcmcia_device; 102 103static int __init balloon3_pcmcia_init(void) 104{ 105 int ret; 106 107 if (!machine_is_balloon3()) 108 return -ENODEV; 109 110 balloon3_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); 111 if (!balloon3_pcmcia_device) 112 return -ENOMEM; 113 114 ret = platform_device_add_data(balloon3_pcmcia_device, 115 &balloon3_pcmcia_ops, sizeof(balloon3_pcmcia_ops)); 116 117 if (!ret) 118 ret = platform_device_add(balloon3_pcmcia_device); 119 120 if (ret) 121 platform_device_put(balloon3_pcmcia_device); 122 123 return ret; 124} 125 126static void __exit balloon3_pcmcia_exit(void) 127{ 128 platform_device_unregister(balloon3_pcmcia_device); 129} 130 131module_init(balloon3_pcmcia_init); 132module_exit(balloon3_pcmcia_exit); 133 134MODULE_LICENSE("GPL"); 135MODULE_AUTHOR("Nick Bane <nick@cecomputing.co.uk>"); 136MODULE_ALIAS("platform:pxa2xx-pcmcia"); 137MODULE_DESCRIPTION("Balloon3 board CF/PCMCIA driver");