11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for the Cirrus PD6729 PCI-PCMCIA bridge. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Based on the i82092.c driver. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms of 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the GNU General Public License, incorporated herein by reference. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 185cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro#include <linux/io.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ss.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pd6729.h" 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "i82365.h" 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cirrus.h" 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Driver for the Cirrus PD6729 PCI-PCMCIA bridge"); 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>"); 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_SOCKETS 2 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * simple helper functions 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * External clock time, in nanoseconds. 120 ns = 8.33 MHz 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define to_cycles(ns) ((ns)/120) 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef NO_IRQ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NO_IRQ ((unsigned int)(0)) 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PARAMETERS 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * irq_mode=n 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Specifies the interrupt delivery mode. The default (1) is to use PCI 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts; a value of 0 selects ISA interrupts. This must be set for 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * correct operation of PCI card readers. 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */ 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(irq_mode, int, 0444); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq_mode, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1"); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(port_lock); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* basic value read/write functions */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char indirect_read(struct pd6729_socket *socket, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short reg) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long port; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port_lock, flags); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg += socket->number * 0x40; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port = socket->io_base; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = inb(port + 1); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port_lock, flags); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short indirect_read16(struct pd6729_socket *socket, 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short reg) 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long port; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short tmp; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port_lock, flags); 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = reg + socket->number * 0x40; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port = socket->io_base; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = inb(port + 1); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg++; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = tmp | (inb(port + 1) << 8); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port_lock, flags); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tmp; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void indirect_write(struct pd6729_socket *socket, unsigned short reg, 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char value) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long port; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port_lock, flags); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = reg + socket->number * 0x40; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port = socket->io_base; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(value, port + 1); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port_lock, flags); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void indirect_setbit(struct pd6729_socket *socket, unsigned short reg, 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char mask) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long port; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port_lock, flags); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = reg + socket->number * 0x40; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port = socket->io_base; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = inb(port + 1); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= mask; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(val, port + 1); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port_lock, flags); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void indirect_resetbit(struct pd6729_socket *socket, unsigned short reg, 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char mask) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long port; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port_lock, flags); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = reg + socket->number * 0x40; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port = socket->io_base; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = inb(port + 1); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val &= ~mask; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(val, port + 1); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port_lock, flags); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void indirect_write16(struct pd6729_socket *socket, unsigned short reg, 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short value) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long port; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char val; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&port_lock, flags); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = reg + socket->number * 0x40; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port = socket->io_base; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = value & 255; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(val, port + 1); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg++; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, port); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = value >> 8; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(val, port + 1); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&port_lock, flags); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Interrupt handler functionality */ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1737d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pd6729_interrupt(int irq, void *dev) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *socket = (struct pd6729_socket *)dev; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int loopcount = 0; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int handled = 0; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int events, active = 0; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loopcount++; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (loopcount > 20) { 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "pd6729: infinite eventloop " 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "in interrupt\n"); 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds active = 0; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_SOCKETS; i++) { 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int csc; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* card status change register */ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csc = indirect_read(&socket[i], I365_CSC); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csc == 0) /* no events on this socket */ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handled = 1; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events = 0; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csc & I365_CSC_DETECT) { 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events |= SS_DETECT; 204a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_vdbg(&socket[i].socket.dev, 205a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "Card detected in socket %i!\n", i); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (indirect_read(&socket[i], I365_INTCTL) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & I365_PC_IOCARD) { 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For IO/CARDS, bit 0 means "read the card" */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events |= (csc & I365_CSC_STSCHG) 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? SS_STSCHG : 0; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check for battery/ready events */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events |= (csc & I365_CSC_BVD1) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? SS_BATDEAD : 0; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events |= (csc & I365_CSC_BVD2) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? SS_BATWARN : 0; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events |= (csc & I365_CSC_READY) 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? SS_READY : 0; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2235cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (events) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_parse_events(&socket[i].socket, events); 2255cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds active |= events; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (active == 0) /* no more events to handle */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(handled); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* socket functions */ 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pd6729_interrupt_wrapper(unsigned long data) 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *socket = (struct pd6729_socket *) data; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2417d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells pd6729_interrupt(0, (void *)socket); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&socket->poll_timer, jiffies + HZ); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pd6729_get_status(struct pcmcia_socket *sock, u_int *value) 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *socket 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds = container_of(sock, struct pd6729_socket, socket); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int data; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *t; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Interface Status Register */ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = indirect_read(socket, I365_STATUS); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value = 0; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2575cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if ((status & I365_CS_DETECT) == I365_CS_DETECT) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value |= SS_DETECT; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IO cards have a different meaning of bits 0,1 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Also notice the inverse-logic on the bits 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (indirect_read(socket, I365_INTCTL) & I365_PC_IOCARD) { 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* IO card */ 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & I365_CS_STSCHG)) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value |= SS_STSCHG; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* non I/O card */ 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & I365_CS_BVD1)) 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value |= SS_BATDEAD; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(status & I365_CS_BVD2)) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value |= SS_BATWARN; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & I365_CS_WRPROT) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value |= SS_WRPROT; /* card is write protected */ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & I365_CS_READY) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value |= SS_READY; /* card is not busy */ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & I365_CS_POWERON) 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value |= SS_POWERON; /* power is applied to the card */ 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = (socket->number) ? socket : socket + 1; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(t, PD67_EXT_INDEX, PD67_EXTERN_DATA); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = indirect_read16(t, PD67_EXT_DATA); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value |= (data & PD67_EXD_VS1(socket->number)) ? 0 : SS_3VCARD; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *socket 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds = container_of(sock, struct pd6729_socket, socket); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char reg, data; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First, set the global controller options */ 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, I365_GBLCTL, 0x00); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, I365_GENCTL, 0x00); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Values for the IGENC register */ 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->card_irq = state->io_irq; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = 0; 3085cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro /* The reset bit has "inverse" logic */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(state->flags & SS_RESET)) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_PC_RESET; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->flags & SS_IOCARD) 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_PC_IOCARD; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* IGENC, Interrupt and General Control Register */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, I365_INTCTL, reg); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Power registers */ 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */ 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->flags & SS_PWR_AUTO) { 322a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, "Auto power\n"); 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_PWR_AUTO; /* automatic power mngmnt */ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->flags & SS_OUTPUT_ENA) { 326a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, "Power Enabled\n"); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_PWR_OUT; /* enable power */ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (state->Vcc) { 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 33: 334a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, 335a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "setting voltage to Vcc to 3.3V on socket %i\n", 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->number); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_VCC_5V; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 50: 341a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, 342a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "setting voltage to Vcc to 5V on socket %i\n", 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->number); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_VCC_5V; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 348a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, 349a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "pd6729_set_socket called with invalid VCC power " 350a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "value: %i\n", state->Vcc); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (state->Vpp) { 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 356a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, "not setting Vpp on socket %i\n", 357a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski socket->number); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 33: 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 50: 361a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, "setting Vpp to Vcc for socket %i\n", 362a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski socket->number); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_VPP1_5V; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 120: 366a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, "setting Vpp to 12.0\n"); 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_VPP1_12V; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 370a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, "pd6729: pd6729_set_socket called with " 371a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "invalid VPP power value: %i\n", state->Vpp); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* only write if changed */ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg != indirect_read(socket, I365_POWER)) 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, I365_POWER, reg); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_mode == 1) { 3805cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro /* all interrupts are to be done as PCI interrupts */ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = 0; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, PD67_EXT_INDEX, PD67_EXT_CTL_1); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, PD67_EXT_DATA, data); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable specific interrupt events */ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = 0x00; 3915cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (state->csc_mask & SS_DETECT) 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_CSC_DETECT; 3935cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->flags & SS_IOCARD) { 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->csc_mask & SS_STSCHG) 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_CSC_STSCHG; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->csc_mask & SS_BATDEAD) 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_CSC_BVD1; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->csc_mask & SS_BATWARN) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_CSC_BVD2; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->csc_mask & SS_READY) 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= I365_CSC_READY; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_mode == 1) 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= 0x30; /* management IRQ: PCI INTA# = "irq 3" */ 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, I365_CSCINT, reg); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = indirect_read(socket, I365_INTCTL); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_mode == 1) 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= 0x03; /* card IRQ: PCI INTA# = "irq 3" */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg |= socket->card_irq; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, I365_INTCTL, reg); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now clear the (probably bogus) pending stuff by doing a dummy read */ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void)indirect_read(socket, I365_CSC); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pd6729_set_io_map(struct pcmcia_socket *sock, 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pccard_io_map *io) 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *socket 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds = container_of(sock, struct pd6729_socket, socket); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char map, ioctl; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map = io->map; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check error conditions */ 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map > 1) { 433a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&sock->dev, "pd6729_set_io_map with invalid map\n"); 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn off the window before changing anything */ 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map)) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map)); 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski /* dev_dbg(&sock->dev, "set_io_map: Setting range to %x - %x\n", 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io->start, io->stop);*/ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* write the new values */ 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write16(socket, I365_IO(map)+I365_W_START, io->start); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write16(socket, I365_IO(map)+I365_W_STOP, io->stop); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4505cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (io->flags & MAP_0WS) 4515cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro ioctl |= I365_IOCTL_0WS(map); 4525cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (io->flags & MAP_16BIT) 4535cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro ioctl |= I365_IOCTL_16BIT(map); 4545cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (io->flags & MAP_AUTOSZ) 4555cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro ioctl |= I365_IOCTL_IOCS16(map); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, I365_IOCTL, ioctl); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn the window back on if needed */ 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (io->flags & MAP_ACTIVE) 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_setbit(socket, I365_ADDRWIN, I365_ENA_IO(map)); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pd6729_set_mem_map(struct pcmcia_socket *sock, 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pccard_mem_map *mem) 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *socket 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds = container_of(sock, struct pd6729_socket, socket); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short base, i; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char map; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map = mem->map; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map > 4) { 476a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_warn(&sock->dev, "invalid map requested\n"); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) { 481a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_warn(&sock->dev, "invalid invalid address / speed\n"); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn off the window before changing anything */ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_MEM(map)) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_MEM(map)); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* write the start address */ 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds base = I365_MEM(map); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (mem->res->start >> 12) & 0x0fff; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_16BIT) 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= I365_MEM_16BIT; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_0WS) 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= I365_MEM_0WS; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write16(socket, base + I365_W_START, i); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* write the stop address */ 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5005cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro i = (mem->res->end >> 12) & 0x0fff; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (to_cycles(mem->speed)) { 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= I365_MEM_WS0; 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= I365_MEM_WS1; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= I365_MEM_WS1 | I365_MEM_WS0; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write16(socket, base + I365_W_STOP, i); 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Take care of high byte */ 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* card start */ 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_WRPROT) 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= I365_MEM_WRPROT; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_ATTRIB) { 527a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski /* dev_dbg(&sock->dev, "requesting attribute memory for " 528a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "socket %i\n", socket->number);*/ 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i |= I365_MEM_REG; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 531a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski /* dev_dbg(&sock->dev, "requesting normal memory for " 532a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "socket %i\n", socket->number);*/ 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write16(socket, base + I365_W_OFF, i); 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable the window if necessary */ 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_ACTIVE) 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_setbit(socket, I365_ADDRWIN, I365_ENA_MEM(map)); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pd6729_init(struct pcmcia_socket *sock) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct resource res = { .end = 0x0fff }; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pccard_io_map io = { 0, 0, 0, 0, 1 }; 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pccard_mem_map mem = { .res = &res, }; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd6729_set_socket(sock, &dead_socket); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 2; i++) { 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io.map = i; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd6729_set_io_map(sock, &io); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 5; i++) { 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem.map = i; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pd6729_set_mem_map(sock, &mem); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* the pccard structure and its functions */ 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pccard_operations pd6729_operations = { 5665cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro .init = pd6729_init, 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_status = pd6729_get_status, 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_socket = pd6729_set_socket, 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_io_map = pd6729_set_io_map, 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_mem_map = pd6729_set_mem_map, 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5737d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t pd6729_test(int irq, void *dev) 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 575a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski pr_devel("-> hit on irq %d\n", irq); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5793e022d0c77e159a59d3ebfc44ad76a05202c2a6bKomurostatic int pd6729_check_irq(int irq) 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5815cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro int ret; 5825cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro 5835cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro ret = request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x", 5845cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro pd6729_test); 5855cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (ret) 5865cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro return -1; 5875cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(irq, pd6729_test); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5929781b8b055bd0a02a043ed80fb8d59d703a49dafAndrew Mortonstatic u_int __devinit pd6729_isa_scan(void) 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int mask0, mask = 0; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_mode == 1) { 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "pd6729: PCI card interrupts, " 5995cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro "PCI status changes\n"); 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 603f9097dce5d799462e086adca28815dac5006bb30Komuro mask0 = PD67_MASK; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* just find interrupts that aren't in use */ 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) 6073e022d0c77e159a59d3ebfc44ad76a05202c2a6bKomuro if ((mask0 & (1 << i)) && (pd6729_check_irq(i) == 0)) 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= (1 << i); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "pd6729: ISA irqs = "); 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mask & (1<<i)) 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6155cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (mask == 0) 6165cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro printk("none!"); 6175cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro else 6185cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro printk(" polling status changes.\n"); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mask; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit pd6729_pci_probe(struct pci_dev *dev, 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct pci_device_id *id) 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, ret; 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int mask; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char configbyte; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *socket; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6318084b372adac9c24ff7abdd939b2e8816e7b88a3Dominik Brodowski socket = kzalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS, 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GFP_KERNEL); 6335cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (!socket) { 6345cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro dev_warn(&dev->dev, "failed to kzalloc socket.\n"); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6365cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro } 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6385cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro ret = pci_enable_device(dev); 6395cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (ret) { 6405cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro dev_warn(&dev->dev, "failed to enable pci_device.\n"); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out_free_mem; 6425cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro } 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64494efb72328afa29ea5fd93e48ed17489afcdaa12Komuro if (!pci_resource_start(dev, 0)) { 645a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_warn(&dev->dev, "refusing to load the driver as the " 646a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "io_base is NULL.\n"); 64740d24ff9b4309d37999bc0ae91a271f57651d9ddRahul Ruikar goto err_out_disable; 64894efb72328afa29ea5fd93e48ed17489afcdaa12Komuro } 64994efb72328afa29ea5fd93e48ed17489afcdaa12Komuro 650a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx " 651a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski "on irq %d\n", 652490ab72af6a7a74b1d77e8f1b67fdfad04371876Greg Kroah-Hartman (unsigned long long)pci_resource_start(dev, 0), dev->irq); 6535cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro /* 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since we have no memory BARs some firmware may not 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have had PCI_COMMAND_MEMORY enabled, yet the device needs it. 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(dev, PCI_COMMAND, &configbyte); 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(configbyte & PCI_COMMAND_MEMORY)) { 659a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_dbg(&dev->dev, "pd6729: Enabling PCI_COMMAND_MEMORY.\n"); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds configbyte |= PCI_COMMAND_MEMORY; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(dev, PCI_COMMAND, configbyte); 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pci_request_regions(dev, "pd6729"); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 666a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_warn(&dev->dev, "pci request region failed.\n"); 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out_disable; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq == NO_IRQ) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_mode = 0; /* fall back to ISA interrupt mode */ 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask = pd6729_isa_scan(); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_mode == 0 && mask == 0) { 675a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_warn(&dev->dev, "no ISA interrupt is available.\n"); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out_free_res; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_SOCKETS; i++) { 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].io_base = pci_resource_start(dev, 0); 681c35e66a4216c99fe94868ed3f714bd2708d0032aDominik Brodowski socket[i].socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].socket.map_size = 0x1000; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].socket.irq_mask = mask; 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].socket.pci_irq = dev->irq; 6857a96e87d6e58a07235a2bc3eff9b093af4937a72Dominik Brodowski socket[i].socket.cb_dev = dev; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].socket.owner = THIS_MODULE; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].number = i; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].socket.ops = &pd6729_operations; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].socket.resource_ops = &pccard_nonstatic_ops; 692873733188a019acdb7fa253011cbdc0a8afd97f3Greg Kroah-Hartman socket[i].socket.dev.parent = &dev->dev; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket[i].socket.driver_data = &socket[i]; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_set_drvdata(dev, socket); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_mode == 1) { 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Register the interrupt handler */ 6995cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED, 7005cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro "pd6729", socket); 7015cbb2b941d2cc77e6b915e8e55d375be632c9f6aKomuro if (ret) { 702a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_err(&dev->dev, "Failed to register irq %d\n", 703a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev->irq); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out_free_res; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* poll Card status change */ 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&socket->poll_timer); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->poll_timer.function = pd6729_interrupt_wrapper; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->poll_timer.data = (unsigned long)socket; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->poll_timer.expires = jiffies + HZ; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&socket->poll_timer); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_SOCKETS; i++) { 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = pcmcia_register_socket(&socket[i].socket); 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 718a7149f9a26eb44a5658d56335c23104ba529e9f6Dominik Brodowski dev_warn(&dev->dev, "pcmcia_register_socket failed.\n"); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < i ; j++) 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_unregister_socket(&socket[j].socket); 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto err_out_free_res2; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 727006839f12e9dc484a6227b263843f987abb709a4Komuroerr_out_free_res2: 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_mode == 1) 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, socket); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&socket->poll_timer); 732006839f12e9dc484a6227b263843f987abb709a4Komuroerr_out_free_res: 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_release_regions(dev); 734006839f12e9dc484a6227b263843f987abb709a4Komuroerr_out_disable: 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_disable_device(dev); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 737006839f12e9dc484a6227b263843f987abb709a4Komuroerr_out_free_mem: 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(socket); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit pd6729_pci_remove(struct pci_dev *dev) 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pd6729_socket *socket = pci_get_drvdata(dev); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_SOCKETS; i++) { 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn off all interrupt sources */ 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(&socket[i], I365_CSCINT, 0); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indirect_write(&socket[i], I365_INTCTL, 0); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcmcia_unregister_socket(&socket[i].socket); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_mode == 1) 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, socket); 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&socket->poll_timer); 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_release_regions(dev); 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_disable_device(dev); 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(socket); 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7652b2c5d8c1dff8ed42d6d841f56428c0ce2bd71b5Axel Linstatic DEFINE_PCI_DEVICE_TABLE(pd6729_pci_ids) = { 7662b2c5d8c1dff8ed42d6d841f56428c0ce2bd71b5Axel Lin { PCI_DEVICE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729) }, 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, pd6729_pci_ids); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771ba66ddfa613886cbb554f7b064dc05bdc2c7138bSam Ravnborgstatic struct pci_driver pd6729_pci_driver = { 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "pd6729", 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = pd6729_pci_ids, 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = pd6729_pci_probe, 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = __devexit_p(pd6729_pci_remove), 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pd6729_module_init(void) 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 780ba66ddfa613886cbb554f7b064dc05bdc2c7138bSam Ravnborg return pci_register_driver(&pd6729_pci_driver); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pd6729_module_exit(void) 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 785ba66ddfa613886cbb554f7b064dc05bdc2c7138bSam Ravnborg pci_unregister_driver(&pd6729_pci_driver); 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pd6729_module_init); 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pd6729_module_exit); 790