patch-2.4.19 linux-2.4.19/drivers/pcmcia/sa1100_h3600.c

Next file: linux-2.4.19/drivers/pcmcia/sa1100_jornada720.c
Previous file: linux-2.4.19/drivers/pcmcia/sa1100_graphicsmaster.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/drivers/pcmcia/sa1100_h3600.c linux-2.4.19/drivers/pcmcia/sa1100_h3600.c
@@ -9,139 +9,188 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/arch/pcmcia.h>
+#include "sa1100_generic.h"
 
+static struct irqs {
+	int irq;
+	const char *str;
+} irqs[] = {
+	{ IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
+	{ IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
+};
 
-static int h3600_pcmcia_init(struct pcmcia_init *init){
-  int irq, res;
-
-  /* Enable CF bus: */
-  set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON);
-  clr_h3600_egpio(EGPIO_H3600_OPT_RESET);
-
-  /* All those are inputs */
-  GPDR &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1);
-
-  /* Set transition detect */
-  set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES );
-  set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE );
-
-  /* Register interrupts */
-  irq = IRQ_GPIO_H3600_PCMCIA_CD0;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL );
-  if( res < 0 ) goto irq_err;
-  irq = IRQ_GPIO_H3600_PCMCIA_CD1;
-  res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL );
-  if( res < 0 ) goto irq_err;
+static int h3600_pcmcia_init(struct pcmcia_init *init)
+{
+	int i, res;
 
-  return 2;
+	/*
+	 * Set transition detect
+	 */
+	set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_IRQ0 | GPIO_H3600_PCMCIA_IRQ1,
+			  GPIO_FALLING_EDGE);
+
+	/*
+	 * Register interrupts
+	 */
+	for (i = res = 0; i < ARRAY_SIZE(irqs); i++) {
+		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+				  irqs[i].str, NULL);
+		if (res)
+			break;
+	}
+
+	if (res) {
+		printk(KERN_ERR "h3600_pcmcia: request for IRQ%d failed: %d\n",
+		       irqs[i].irq, res);
+
+		while (i--)
+			free_irq(irqs[i].irq, NULL);
+	}
 
-irq_err:
-  printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq );
-  return -1;
+	return res ? -1 : 2;
 }
 
 static int h3600_pcmcia_shutdown(void)
 {
-  /* disable IRQs */
-  free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL );
-  free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL );
+	int i;
+
+	/*
+	 * disable IRQs
+	 */
+	for (i = 0; i < ARRAY_SIZE(irqs); i++)
+		free_irq(irqs[i].irq, NULL);
   
-  /* Disable CF bus: */
-  clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON);
-  set_h3600_egpio(EGPIO_H3600_OPT_RESET);
+	/* Disable CF bus: */
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+	set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
 
-  return 0;
+	return 0;
 }
 
-static int h3600_pcmcia_socket_state(struct pcmcia_state_array
-				       *state_array){
-  unsigned long levels;
-
-  if(state_array->size<2) return -1;
-
-  memset(state_array->state, 0, 
-	 (state_array->size)*sizeof(struct pcmcia_state));
+static int
+h3600_pcmcia_socket_state(struct pcmcia_state_array *state)
+{
+	unsigned long levels;
 
-  levels=GPLR;
+	if (state->size < 2)
+		return -1;
 
-  state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0;
-  state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0;
-  state_array->state[0].bvd1= 0;
-  state_array->state[0].bvd2= 0;
-  state_array->state[0].wrprot=0; /* Not available on H3600. */
-  state_array->state[0].vs_3v=0;
-  state_array->state[0].vs_Xv=0;
+	levels = GPLR;
 
-  state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0;
-  state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0;
-  state_array->state[1].bvd1=0;
-  state_array->state[1].bvd2=0;
-  state_array->state[1].wrprot=0; /* Not available on H3600. */
-  state_array->state[1].vs_3v=0;
-  state_array->state[1].vs_Xv=0;
+	state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
+	state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
+	state->state[0].bvd1 = 0;
+	state->state[0].bvd2 = 0;
+	state->state[0].wrprot = 0; /* Not available on H3600. */
+	state->state[0].vs_3v = 0;
+	state->state[0].vs_Xv = 0;
+
+	state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
+	state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
+	state->state[1].bvd1 = 0;
+	state->state[1].bvd2 = 0;
+	state->state[1].wrprot = 0; /* Not available on H3600. */
+	state->state[1].vs_3v = 0;
+	state->state[1].vs_Xv = 0;
 
-  return 1;
+	return 1;
 }
 
-static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
-
-  switch (info->sock) {
-  case 0:
-    info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0;
-    break;
-  case 1:
-    info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1;
-    break;
-  default:
-    return -1;
-  }
-  return 0;
+static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
+{
+	switch (info->sock) {
+	case 0:
+		info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0;
+		break;
+	case 1:
+		info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
 }
 
-static int h3600_pcmcia_configure_socket(const struct pcmcia_configure
-					   *configure)
+static int
+h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-  unsigned long flags;
-
-  if(configure->sock>1) return -1;
+	if (conf->sock > 1)
+		return -1;
 
-  save_flags_cli(flags);
+	if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) {
+		printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n",
+		       conf->vcc / 10, conf->vcc % 10);
+		return -1;
+	}
+
+	if (conf->reset)
+		set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
+	else
+		clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
 
-  switch (configure->vcc) {
-  case 0:
-    clr_h3600_egpio(EGPIO_H3600_OPT_ON);
-    break;
+	/* Silently ignore Vpp, output enable, speaker enable. */
 
-  case 33:
-  case 50:
-    set_h3600_egpio(EGPIO_H3600_OPT_ON);
-    break;
-
-  default:
-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
-	   configure->vcc);
-    restore_flags(flags);
-    return -1;
-  }
+	return 0;
+}
 
-  if (configure->reset)
-    set_h3600_egpio(EGPIO_H3600_CARD_RESET);
-  else
-    clr_h3600_egpio(EGPIO_H3600_CARD_RESET);
+static int h3600_pcmcia_socket_init(int sock)
+{
+	/* Enable CF bus: */
+	set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+	set_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+	clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(10*HZ / 1000);
+
+	switch (sock) {
+	case 0:
+		set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_BOTH_EDGES);
+		break;
+	case 1:
+		set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES);
+		break;
+	}
 
-  /* Silently ignore Vpp, output enable, speaker enable. */
+	return 0;
+}
 
-  restore_flags(flags);
+static int h3600_pcmcia_socket_suspend(int sock)
+{
+	switch (sock) {
+	case 0:
+		set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0, GPIO_NO_EDGES);
+		break;
+	case 1:
+		set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD1, GPIO_NO_EDGES);
+		break;
+	}
+
+	/*
+	 * FIXME:  This doesn't fit well.  We don't have the mechanism in
+	 * the generic PCMCIA layer to deal with the idea of two sockets
+	 * on one bus.  We rely on the cs.c behaviour shutting down
+	 * socket 0 then socket 1.
+	 */
+	if (sock == 1) {
+		clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
+		clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
+		/* hmm, does this suck power? */
+		set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
+	}
 
-  return 0;
+	return 0;
 }
 
 struct pcmcia_low_level h3600_pcmcia_ops = { 
-  h3600_pcmcia_init,
-  h3600_pcmcia_shutdown,
-  h3600_pcmcia_socket_state,
-  h3600_pcmcia_get_irq_info,
-  h3600_pcmcia_configure_socket
+	init:			h3600_pcmcia_init,
+	shutdown:		h3600_pcmcia_shutdown,
+	socket_state:		h3600_pcmcia_socket_state,
+	get_irq_info:		h3600_pcmcia_get_irq_info,
+	configure_socket:	h3600_pcmcia_configure_socket,
+
+	socket_init:		h3600_pcmcia_socket_init,
+	socket_suspend:		h3600_pcmcia_socket_suspend,
 };
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)