Re: [PATCH] MPC8xx PCMCIA driver

From: Jeff Garzik
Date: Mon Aug 29 2005 - 22:39:55 EST


Marcelo Tosatti wrote:
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ u_int reg = 0;
+
+ switch(vcc) {
+ case 0: break;
+ case 33:
+ reg |= BCSR1_PCVCTL4;
+ break;
+ case 50: + reg |= BCSR1_PCVCTL5;
+ break;
+ default: + return 1;
+ }
+
+ switch(vpp) {
+ case 0: break;
+ case 33: + case 50:
+ if(vcc == vpp)
+ reg |= BCSR1_PCVCTL6;
+ else
+ return 1;
+ break;
+ case 120: + reg |= BCSR1_PCVCTL7;
+ default:
+ return 1;
+ }
+
+ if(!((vcc == 50) || (vcc == 0)))
+ return 1;
+
+ /* first, turn off all power */
+
+ *((uint *)RPX_CSR_ADDR) &= ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5
+ | BCSR1_PCVCTL6 | BCSR1_PCVCTL7);
+
+ /* enable new powersettings */
+
+ *((uint *)RPX_CSR_ADDR) |= reg;

Should use bus read/write functions, such as foo_readl() or iowrite32().

Don't use weird types in kernel code such as 'uint'. Use the more explicitly-sized u32.


+ return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+#define hardware_enable(_slot_) /* No hardware to enable */
+#define hardware_disable(_slot_) /* No hardware to disable */
+
+#endif /* CONFIG_RPXCLASSIC */
+
+/* FADS Boards from Motorola */
+
+#if defined(CONFIG_FADS)
+
+#define PCMCIA_BOARD_MSG "FADS"
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ uint reg = 0;
+
+ switch(vcc) {
+ case 0:
+ break;
+ case 33:
+ reg |= BCSR1_PCCVCC0;
+ break;
+ case 50:
+ reg |= BCSR1_PCCVCC1;
+ break;
+ default:
+ return 1;
+ }
+
+ switch(vpp) {
+ case 0:
+ break;
+ case 33:
+ case 50:
+ if(vcc == vpp)
+ reg |= BCSR1_PCCVPP1;
+ else
+ return 1;
+ break;
+ case 120:
+ if ((vcc == 33) || (vcc == 50))
+ reg |= BCSR1_PCCVPP0;
+ else
+ return 1;
+ default:
+ return 1;
+ }
+
+ /* first, turn off all power */
+ *((uint *)BCSR1) &= ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK);
+
+ /* enable new powersettings */
+ *((uint *)BCSR1) |= reg;

ditto

+ return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+
+static void hardware_enable(int slot)
+{
+ *((uint *)BCSR1) &= ~BCSR1_PCCEN;
+}

ditto

+static void hardware_disable(int slot)
+{
+ *((uint *)BCSR1) |= BCSR1_PCCEN;
+}

etc.


+/* ------------------------------------------------------------------------- */
+/* Motorola MBX860 */
+
+#if defined(CONFIG_MBX)
+
+#define PCMCIA_BOARD_MSG "MBX"
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ unsigned char reg = 0;
+
+ switch(vcc) {
+ case 0:
+ break;
+ case 33:
+ reg |= CSR2_VCC_33;
+ break;
+ case 50:
+ reg |= CSR2_VCC_50;
+ break;
+ default:
+ return 1;
+ }
+
+ switch(vpp) {
+ case 0:
+ break;
+ case 33:
+ case 50:
+ if(vcc == vpp)
+ reg |= CSR2_VPP_VCC;
+ else
+ return 1;
+ break;
+ case 120:
+ if ((vcc == 33) || (vcc == 50))
+ reg |= CSR2_VPP_12;
+ else
+ return 1;
+ default:
+ return 1;
+ }
+
+ /* first, turn off all power */
+ *((unsigned char *)MBX_CSR2_ADDR) &= ~(CSR2_VCC_MASK | CSR2_VPP_MASK);
+
+ /* enable new powersettings */
+ *((unsigned char *)MBX_CSR2_ADDR) |= reg;

ditto.

also, use u8 not unsigned char.


+ return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
+#define hardware_enable(_slot_) /* No hardware to enable */
+#define hardware_disable(_slot_) /* No hardware to disable */
+
+#endif /* CONFIG_MBX */
+
+#if defined(CONFIG_PRxK)
+#include <asm/cpld.h>
+extern volatile fpga_pc_regs *fpga_pc;
+
+#define PCMCIA_BOARD_MSG "MPC855T"
+
+static int voltage_set(int slot, int vcc, int vpp)
+{
+ unsigned char reg = 0;
+ unsigned char regread;
+ cpld_regs *ccpld = get_cpld();
+
+ switch(vcc) {
+ case 0:
+ break;
+ case 33:
+ reg |= PCMCIA_VCC_33;
+ break;
+ case 50:
+ reg |= PCMCIA_VCC_50;
+ break;
+ default:
+ return 1;
+ }
+
+ switch(vpp) {
+ case 0:
+ break;
+ case 33:
+ case 50:
+ if(vcc == vpp)
+ reg |= PCMCIA_VPP_VCC;
+ else
+ return 1;
+ break;
+ case 120:
+ if ((vcc == 33) || (vcc == 50))
+ reg |= PCMCIA_VPP_12;
+ else
+ return 1;
+ default:
+ return 1;
+ }
+
+ reg = reg >> (slot << 2);
+ regread = ccpld->fpga_pc_ctl;
+ if (reg != (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) {
+ /* enable new powersettings */
+ regread = regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2));
+ ccpld->fpga_pc_ctl = reg | regread;
+ mdelay(100);

should be msleep() AFAICS


+ return 0;
+}
+
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_LV
+#define hardware_enable(_slot_) /* No hardware to enable */
+#define hardware_disable(_slot_) /* No hardware to disable */
+
+#endif /* CONFIG_PRxK */
+
+static void m8xx_shutdown(void)
+{
+ u_int m, i;
+ pcmcia_win_t *w;
+
+ for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
+ w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+
+ ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = + M8XX_PCMCIA_MASK(i); + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per + &= ~M8XX_PCMCIA_MASK(i);
+ + /* turn off interrupt and disable CxOE */
+ M8XX_PGCRX(i) = M8XX_PGCRX_CXOE;
+
+ /* turn off memory windows */
+ for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
+ w->or = 0; /* set to not valid */
+ w++;
+ }
+
+ /* turn off voltage */
+ voltage_set(i, 0, 0);
+
+ /* disable external hardware */
+ hardware_disable(i);
+ }
+
+ free_irq(pcmcia_schlvl, NULL);

don't you want to free_irq() first?



+}
+
+/* copied from tcic.c */
+
+static int m8xx_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+ int ret = 0;
+ if (level == SUSPEND_SAVE_STATE)
+ ret = pcmcia_socket_dev_suspend(dev, state);
+ return ret;
+}
+ +static int m8xx_drv_resume(struct device *dev, u32 level)
+{
+ int ret = 0;
+ if (level == RESUME_RESTORE_STATE)
+ ret = pcmcia_socket_dev_resume(dev);
+ return ret;
+}
+ +static struct device_driver m8xx_driver = {
+ .name = "m8xx-pcmcia",
+ .bus = &platform_bus_type,
+ .suspend = m8xx_drv_suspend,
+ .resume = m8xx_drv_resume,
+};
+
+static struct platform_device m8xx_device = {
+ .name = "m8xx-pcmcia",
+ .id = 0,
+};
+
+static u_int pending_events[PCMCIA_SOCKETS_NO];
+static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+
+static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+ socket_info_t *s;
+ event_table_t *e;
+ u_int i, events, pscr, pipr, per;
+
+ dprintk("Interrupt!\n");
+ /* get interrupt sources */
+
+ pscr = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr;
+ pipr = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr;
+ per = ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per;
+
+ for(i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+ s = &socket[i];
+ e = &s->events[0]; + events = 0;
+
+ while(e->regbit) {
+ if(pscr & e->regbit)
+ events |= e->eventbit;
+ + e++;
+ }
+
+ /* + * report only if both card detect signals are the same + * not too nice done, + * we depend on that CD2 is the bit to the left of CD1...
+ */
+ if(events & SS_DETECT)
+ if(((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^
+ (pipr & M8XX_PCMCIA_CD1(i)))
+ {
+ events &= ~SS_DETECT;
+ }
+
+#ifdef PCMCIA_GLITCHY_CD
+ /*
+ * I've experienced CD problems with my ADS board.
+ * We make an extra check to see if there was a
+ * real change of Card detection.
+ */
+ + if((events & SS_DETECT) && + ((pipr &
+ (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) &&
+ (s->state.Vcc | s->state.Vpp)) {
+ events &= ~SS_DETECT;
+ /*printk( "CD glitch workaround - CD = 0x%08x!\n",
+ (pipr & (M8XX_PCMCIA_CD2(i) + | M8XX_PCMCIA_CD1(i))));*/
+ }
+#endif
+ + /* call the handler */
+
+ dprintk("slot %u: events = 0x%02x, pscr = 0x%08x, "
+ "pipr = 0x%08x\n", + i, events, pscr, pipr);
+ + if(events) {
+ spin_lock(&pending_event_lock);
+ pending_events[i] |= events;
+ spin_unlock(&pending_event_lock);
+ /* + * Turn off RDY_L bits in the PER mask on + * CD interrupt receival.
+ *
+ * They can generate bad interrupts on the
+ * ACS4,8,16,32. - marcelo
+ */
+ per &= ~M8XX_PCMCIA_RDY_L(0);
+ per &= ~M8XX_PCMCIA_RDY_L(1);
+
+ ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per = per;
+
+ if (events)
+ pcmcia_parse_events(&socket[i].socket, events);
+ }
+ }
+
+ /* clear the interrupt sources */
+ ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr;

more direct memory writes which should be foo_writel()


+ dprintk("Interrupt done.\n");
+
+ return IRQ_HANDLED;
+}
+
+static int m8xx_suspend(struct pcmcia_socket *sock)
+{
+ return m8xx_set_socket(sock, &dead_socket);
+}
+
+static struct pccard_operations m8xx_services = {
+ .init = m8xx_sock_init,
+ .suspend = m8xx_suspend,
+ .get_status = m8xx_get_status,
+ .get_socket = m8xx_get_socket,
+ .set_socket = m8xx_set_socket,
+ .set_io_map = m8xx_set_io_map,
+ .set_mem_map = m8xx_set_mem_map,
+};
+
+static int __init m8xx_init(void)
+{
+ pcmcia_win_t *w;
+ u_int i,m;
+
+ pcmcia_info("%s\n", version);
+
+ if (driver_register(&m8xx_driver))
+ return -1;
+
+ pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG + " with IRQ %u.\n", pcmcia_schlvl); +
+ /* Configure Status change interrupt */
+
+ if(request_irq(pcmcia_schlvl, m8xx_interrupt, 0, + "m8xx_pcmcia", NULL)) {
+ pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n", + pcmcia_schlvl);
+ return -1;
+ }
+
+ w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+
+ ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = + M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1); + ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per + &= ~(M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1));

ditto etc.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/