^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * omap_cf.c -- OMAP 16xx CompactFlash controller driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2005 David Brownell
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <pcmcia/ss.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <mach/hardware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/sizes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <mach/mux.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <mach/tc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /* NOTE: don't expect this to support many I/O cards. The 16xx chips have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * hard-wired timings to support Compact Flash memory cards; they won't work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * with various other devices (like WLAN adapters) without some external
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * logic to help out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * NOTE: CF controller docs disagree with address space docs as to where
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * CF_BASE really lives; this is a doc erratum.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define CF_BASE 0xfffe2800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* status; read after IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define CF_STATUS (CF_BASE + 0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) # define CF_STATUS_BAD_READ (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) # define CF_STATUS_BAD_WRITE (1 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) # define CF_STATUS_CARD_DETECT (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* which chipselect (CS0..CS3) is used for CF (active low) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define CF_CFG (CF_BASE + 0x02)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* card reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define CF_CONTROL (CF_BASE + 0x04)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) # define CF_CONTROL_RESET (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define omap_cf_present() (!(omap_readw(CF_STATUS) & CF_STATUS_CARD_DETECT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /*--------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static const char driver_name[] = "omap_cf";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct omap_cf_socket {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct pcmcia_socket socket;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct timer_list timer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned present:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned active:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned long phys_cf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) u_int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct resource iomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define POLL_INTERVAL (2 * HZ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /*--------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int omap_cf_ss_init(struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /* the timer is primarily to kick this socket's pccardd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static void omap_cf_timer(struct timer_list *t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct omap_cf_socket *cf = from_timer(cf, t, timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned present = omap_cf_present();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (present != cf->present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) cf->present = present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) pr_debug("%s: card %s\n", driver_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) present ? "present" : "gone");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) pcmcia_parse_events(&cf->socket, SS_DETECT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (cf->active)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /* This irq handler prevents "irqNNN: nobody cared" messages as drivers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * claim the card's IRQ. It may also detect some card insertions, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * not removals; it can't always eliminate timer irqs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static irqreturn_t omap_cf_irq(int irq, void *_cf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct omap_cf_socket *cf = (struct omap_cf_socket *)_cf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) omap_cf_timer(&cf->timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static int omap_cf_get_status(struct pcmcia_socket *s, u_int *sp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (!sp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /* NOTE CF is always 3VCARD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (omap_cf_present()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct omap_cf_socket *cf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) cf = container_of(s, struct omap_cf_socket, socket);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) s->pcmcia_irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) s->pci_irq = cf->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) *sp = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) u16 control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* REVISIT some non-OSK boards may support power switching */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) switch (s->Vcc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) case 33:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) control = omap_readw(CF_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (s->flags & SS_RESET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) omap_writew(CF_CONTROL_RESET, CF_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) omap_writew(0, CF_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static int omap_cf_ss_suspend(struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) pr_debug("%s: %s\n", driver_name, __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return omap_cf_set_socket(s, &dead_socket);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* regions are 2K each: mem, attrib, io (and reserved-for-ide) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) omap_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct omap_cf_socket *cf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) cf = container_of(s, struct omap_cf_socket, socket);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) io->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) io->start = cf->phys_cf + SZ_4K;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) io->stop = io->start + SZ_2K - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) omap_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct omap_cf_socket *cf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (map->card_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) cf = container_of(s, struct omap_cf_socket, socket);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) map->static_start = cf->phys_cf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (map->flags & MAP_ATTRIB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) map->static_start += SZ_2K;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) static struct pccard_operations omap_cf_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) .init = omap_cf_ss_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .suspend = omap_cf_ss_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .get_status = omap_cf_get_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .set_socket = omap_cf_set_socket,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .set_io_map = omap_cf_set_io_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .set_mem_map = omap_cf_set_mem_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /*--------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * NOTE: right now the only board-specific platform_data is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * "what chipselect is used". Boards could want more.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) static int __init omap_cf_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) unsigned seg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) struct omap_cf_socket *cf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) seg = (int) pdev->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (seg == 0 || seg > 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* either CFLASH.IREQ (INT_1610_CF) or some GPIO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) cf = kzalloc(sizeof *cf, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (!cf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) timer_setup(&cf->timer, omap_cf_timer, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) cf->pdev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) platform_set_drvdata(pdev, cf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /* this primarily just shuts up irq handling noise */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) status = request_irq(irq, omap_cf_irq, IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) driver_name, cf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (status < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) goto fail0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) cf->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) cf->socket.pci_irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) switch (seg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* NOTE: CS0 could be configured too ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) cf->phys_cf = OMAP_CS1_PHYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) cf->phys_cf = OMAP_CS2_PHYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) cf->phys_cf = omap_cs3_phys();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) goto fail1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) cf->iomem.start = cf->phys_cf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) cf->iomem.end = cf->iomem.end + SZ_8K - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) cf->iomem.flags = IORESOURCE_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* pcmcia layer only remaps "real" memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) cf->socket.io_offset = (unsigned long)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) ioremap(cf->phys_cf + SZ_4K, SZ_2K);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (!cf->socket.io_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) goto fail1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (!request_mem_region(cf->phys_cf, SZ_8K, driver_name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) goto fail1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) /* NOTE: CF conflicts with MMC1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) omap_cfg_reg(W11_1610_CF_CD1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) omap_cfg_reg(P11_1610_CF_CD2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) omap_cfg_reg(R11_1610_CF_IOIS16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) omap_cfg_reg(V10_1610_CF_IREQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) omap_cfg_reg(W10_1610_CF_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) omap_writew(~(1 << seg), CF_CFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) pr_info("%s: cs%d on irq %d\n", driver_name, seg, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /* NOTE: better EMIFS setup might support more cards; but the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * TRM only shows how to affect regular flash signals, not their
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * CF/PCMCIA variants...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) pr_debug("%s: cs%d, previous ccs %08x acs %08x\n", driver_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) seg, omap_readl(EMIFS_CCS(seg)), omap_readl(EMIFS_ACS(seg)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) omap_writel(0x0004a1b3, EMIFS_CCS(seg)); /* synch mode 4 etc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) omap_writel(0x00000000, EMIFS_ACS(seg)); /* OE hold/setup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* CF uses armxor_ck, which is "always" available */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) pr_debug("%s: sts %04x cfg %04x control %04x %s\n", driver_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) omap_readw(CF_STATUS), omap_readw(CF_CFG),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) omap_readw(CF_CONTROL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) omap_cf_present() ? "present" : "(not present)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) cf->socket.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) cf->socket.dev.parent = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) cf->socket.ops = &omap_cf_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) cf->socket.resource_ops = &pccard_static_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) | SS_CAP_MEM_ALIGN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) cf->socket.map_size = SZ_2K;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) cf->socket.io[0].res = &cf->iomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) status = pcmcia_register_socket(&cf->socket);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (status < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) goto fail2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) cf->active = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) fail2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) release_mem_region(cf->phys_cf, SZ_8K);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) fail1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (cf->socket.io_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) iounmap((void __iomem *) cf->socket.io_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) free_irq(irq, cf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) fail0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) kfree(cf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) static int __exit omap_cf_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) struct omap_cf_socket *cf = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) cf->active = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) pcmcia_unregister_socket(&cf->socket);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) del_timer_sync(&cf->timer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) iounmap((void __iomem *) cf->socket.io_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) release_mem_region(cf->phys_cf, SZ_8K);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) free_irq(cf->irq, cf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) kfree(cf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static struct platform_driver omap_cf_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) .name = driver_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) .remove = __exit_p(omap_cf_remove),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static int __init omap_cf_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) if (cpu_is_omap16xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) return platform_driver_probe(&omap_cf_driver, omap_cf_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static void __exit omap_cf_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (cpu_is_omap16xx())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) platform_driver_unregister(&omap_cf_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) module_init(omap_cf_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) module_exit(omap_cf_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) MODULE_DESCRIPTION("OMAP CF Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) MODULE_ALIAS("platform:omap_cf");