Пример #1
0
/* pxa_pcmcia_driver_init()
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 *
 * This routine performs a basic sanity check to ensure that this
 * kernel has been built with the appropriate board-specific low-level
 * PCMCIA support, performs low-level PCMCIA initialization, registers
 * this socket driver with Card Services, and then spawns the daemon
 * thread which is the real workhorse of the socket driver.
 *
 * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
 * on the low-level kernel interface.
 *
 * Returns: 0 on success, -1 on error
 */
static int __init pxa_pcmcia_driver_init(void){
  servinfo_t info;
  struct pcmcia_init pcmcia_init;
  struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK];
  struct pcmcia_state_array state_array;
  unsigned int i, clock;
  unsigned long mecr;

  printk(KERN_INFO "Intel PXA250/210 PCMCIA (CS release %s)\n", CS_RELEASE);

  CardServices(GetCardServicesInfo, &info);

  if(info.Revision!=CS_RELEASE_CODE){
    printk(KERN_ERR "Card Services release codes do not match\n");
    return -1;
  }

  /* Setup GPIOs for PCMCIA/CF alternate function mode.
   *
   * It would be nice if set_GPIO_mode included support
   * for driving GPIO outputs to default high/low state
   * before programming GPIOs as outputs. Setting GPIO
   * outputs to default high/low state via GPSR/GPCR
   * before defining them as outputs should reduce
   * the possibility of glitching outputs during GPIO
   * setup. This of course assumes external terminators
   * are present to hold GPIOs in a defined state.
   *
   * In the meantime, setup default state of GPIO
   * outputs before we enable them as outputs.
   */

  GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
                      GPIO_bit(GPIO49_nPWE) |
                      GPIO_bit(GPIO50_nPIOR) |
                      GPIO_bit(GPIO51_nPIOW) |
                      GPIO_bit(GPIO52_nPCE_1) |
                      GPIO_bit(GPIO53_nPCE_2);

  set_GPIO_mode(GPIO48_nPOE_MD);
  set_GPIO_mode(GPIO49_nPWE_MD);
  set_GPIO_mode(GPIO50_nPIOR_MD);
  set_GPIO_mode(GPIO51_nPIOW_MD);
  set_GPIO_mode(GPIO52_nPCE_1_MD);
  set_GPIO_mode(GPIO53_nPCE_2_MD);
  set_GPIO_mode(GPIO54_pSKTSEL_MD); /* REVISIT: s/b dependent on num sockets */
  set_GPIO_mode(GPIO55_nPREG_MD);
  set_GPIO_mode(GPIO56_nPWAIT_MD);
  set_GPIO_mode(GPIO57_nIOIS16_MD);


  if(machine_is_lubbock()){
#ifdef CONFIG_ARCH_LUBBOCK
    pcmcia_low_level=&lubbock_pcmcia_ops;
#endif
  } else if (machine_is_pxa_idp()) {
    pcmcia_low_level=&pxa_idp_pcmcia_ops;
  } else if( machine_is_pxa_cerf()){
    pcmcia_low_level=&cerf_pcmcia_ops;
  }

  if (!pcmcia_low_level) {
    printk(KERN_ERR "This hardware is not supported by the PXA250/210 Card Service driver\n");
    return -ENODEV;
  }

  pcmcia_init.handler=pxa_pcmcia_interrupt;

  if((pxa_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){
    printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n");
    return -EIO;
  }

  state_array.size=pxa_pcmcia_socket_count;
  state_array.state=state;

  /* Configure MECR based on the number of sockets present. */
  if (pxa_pcmcia_socket_count == 2) {
    MECR |= GPIO_bit(0);
  } else {
    MECR &= ~GPIO_bit(0);
  }

  if(pcmcia_low_level->socket_state(&state_array)<0){
    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
    return -EIO;
  }

  /* Well, it looks good to go. So we can now enable the PCMCIA
   * controller.
   */
  MECR |= GPIO_bit(1);

  /* We need to initialize the MCXX registers to default values
   * here because we're not guaranteed to see a SetIOMap operation
   * at runtime.
   */

  clock = get_lclk_frequency_10khz();

  for(i=0; i<pxa_pcmcia_socket_count; ++i){
    pxa_pcmcia_socket[i].k_state=state[i];

    /* This is an interim fix. Apparently, SetSocket is no longer
     * called to initialize each socket (prior to the first detect
     * event). For now, we'll just manually set up the mask.
     */
    pxa_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;

    pxa_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE;
    pxa_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i);
    pxa_pcmcia_socket[i].phys_mem=_PCMCIAMem(i);

    /* REVISIT: cleanup these macros */
    //MCIO_SET(i, PXA_PCMCIA_IO_ACCESS, clock);
    //MCATTR_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock);
    //MCMEM_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock);

    pxa_pcmcia_socket[i].speed_io=PXA_PCMCIA_IO_ACCESS;
    pxa_pcmcia_socket[i].speed_attr=PXA_PCMCIA_5V_MEM_ACCESS;
    pxa_pcmcia_socket[i].speed_mem=PXA_PCMCIA_5V_MEM_ACCESS;
  }

/* REVISIT: cleanup these macros */
MCMEM0 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
       | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
       | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
MCMEM1 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
       | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
       | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
       | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
       | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
       | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
       | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock)
		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
MCIO0 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock)
		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
       | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock)
		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
       | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock)
		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
MCIO1 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock)
		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
       | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock)
		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
       | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock)
		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);

#ifdef CONFIG_CPU_FREQ
  if(cpufreq_register_notifier(&pxa_pcmcia_notifier_block) < 0){
    printk(KERN_ERR "Unable to register CPU frequency change notifier\n");
    return -ENXIO;
  }
#endif

  /* Only advertise as many sockets as we can detect: */
  if(register_ss_entry(pxa_pcmcia_socket_count, 
		       &pxa_pcmcia_operations)<0){
    printk(KERN_ERR "Unable to register socket service routine\n");
    return -ENXIO;
  }

  /* Start the event poll timer.  It will reschedule by itself afterwards. */
  pxa_pcmcia_poll_event(0);

  DEBUG(1, "pxa_cs: initialization complete\n");

  return 0;

}  /* pxa_pcmcia_driver_init() */
Пример #2
0
/* pxa_pcmcia_set_io_map()
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Implements the set_io_map() operation for the in-kernel PCMCIA
 * service (formerly SS_SetIOMap in Card Services). We configure
 * the map speed as requested, but override the address ranges
 * supplied by Card Services.
 *
 * Returns: 0 on success, -1 on error
 */
static int pxa_pcmcia_set_io_map(unsigned int sock,
				    struct pccard_io_map *map){
  unsigned int clock, speed;
  unsigned long mecr, start;

  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);

  DEBUG(4, "\tmap %u  speed %u\n\tstart 0x%08lx  stop 0x%08lx\n"
	"\tflags: %s%s%s%s%s%s%s%s\n",
	map->map, map->speed, map->start, map->stop,
	(map->flags==0)?"<NONE>":"",
	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
	(map->flags&MAP_16BIT)?"16BIT ":"",
	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
	(map->flags&MAP_0WS)?"0WS ":"",
	(map->flags&MAP_WRPROT)?"WRPROT ":"",
	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
	(map->flags&MAP_PREFETCH)?"PREFETCH ":"");

  if(map->map>=MAX_IO_WIN){
    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
	   map->map);
    return -1;
  }

  if(map->flags&MAP_ACTIVE){

    speed=(map->speed>0)?map->speed:PXA_PCMCIA_IO_ACCESS;

    clock = get_lclk_frequency_10khz();

    pxa_pcmcia_socket[sock].speed_io=speed;

    if (sock == 0) {
      MCIO0 = ((pxa_mcxx_setup(speed, clock)
			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
            | ((pxa_mcxx_asst(speed, clock)
			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
            | ((pxa_mcxx_hold(speed, clock)
			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
    } else {
      MCIO1 = ((pxa_mcxx_setup(speed, clock)
			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
            | ((pxa_mcxx_asst(speed, clock)
			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
            | ((pxa_mcxx_hold(speed, clock)
			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
    }

    DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
	  sock, MECR_BSIO_GET(mecr, sock));

  }

  start=map->start;

  if(map->stop==1)
    map->stop=PAGE_SIZE-1;

  map->start=pxa_pcmcia_socket[sock].virt_io;
  map->stop=map->start+(map->stop-start);

  pxa_pcmcia_socket[sock].io_map[map->map]=*map;

  return 0;

}  /* pxa_pcmcia_set_io_map() */
Пример #3
0
/* pxa_pcmcia_set_mem_map()
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Implements the set_mem_map() operation for the in-kernel PCMCIA
 * service (formerly SS_SetMemMap in Card Services). We configure
 * the map speed as requested, but override the address ranges
 * supplied by Card Services.
 *
 * Returns: 0 on success, -1 on error
 */
static int pxa_pcmcia_set_mem_map(unsigned int sock,
				     struct pccard_mem_map *map){
  unsigned int clock, speed;
  unsigned long mecr, start;

  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);

  DEBUG(4, "\tmap %u  speed %u\n\tsys_start  %#lx\n"
	"\tsys_stop   %#lx\n\tcard_start %#x\n"
	"\tflags: %s%s%s%s%s%s%s%s\n",
	map->map, map->speed, map->sys_start, map->sys_stop,
	map->card_start, (map->flags==0)?"<NONE>":"",
	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
	(map->flags&MAP_16BIT)?"16BIT ":"",
	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
	(map->flags&MAP_0WS)?"0WS ":"",
	(map->flags&MAP_WRPROT)?"WRPROT ":"",
	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");

  if(map->map>=MAX_WIN){
    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
	   map->map);
    return -1;
  }

  if(map->flags&MAP_ACTIVE){
    /* When clients issue RequestMap, the access speed is not always
     * properly configured:
     */
    if(map->speed > 0)
      speed = map->speed;
    else
      switch(pxa_pcmcia_socket[sock].cs_state.Vcc){
      case 33:
	speed = PXA_PCMCIA_3V_MEM_ACCESS;
	break;
      default:
	speed = PXA_PCMCIA_5V_MEM_ACCESS;
      }

    clock = get_lclk_frequency_10khz();

    if(map->flags&MAP_ATTRIB){
      if (sock == 0) {
        MCATT0 = ((pxa_mcxx_setup(speed, clock)
			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
               | ((pxa_mcxx_asst(speed, clock)
			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
               | ((pxa_mcxx_hold(speed, clock)
			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
      } else {
        MCATT1 = ((pxa_mcxx_setup(speed, clock)
			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
               | ((pxa_mcxx_asst(speed, clock)
			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
               | ((pxa_mcxx_hold(speed, clock)
			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
      }
      pxa_pcmcia_socket[sock].speed_attr=speed;
    } else {
      if (sock == 0) {
        MCMEM0 = ((pxa_mcxx_setup(speed, clock)
			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
               | ((pxa_mcxx_asst(speed, clock)
			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
               | ((pxa_mcxx_hold(speed, clock)
			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
      } else {
        MCMEM1 = ((pxa_mcxx_setup(speed, clock)
			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
               | ((pxa_mcxx_asst(speed, clock)
			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
               | ((pxa_mcxx_hold(speed, clock)
			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
      }
      pxa_pcmcia_socket[sock].speed_mem=speed;
    }
    DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
	  sock, MECR_BSIO_GET(mecr, sock));
  }

  start=map->sys_start;

  if(map->sys_stop==0)
    map->sys_stop=PAGE_SIZE-1;

  map->sys_start=(map->flags & MAP_ATTRIB)?\
    pxa_pcmcia_socket[sock].phys_attr:\
    pxa_pcmcia_socket[sock].phys_mem;

  map->sys_stop=map->sys_start+(map->sys_stop-start);

  pxa_pcmcia_socket[sock].mem_map[map->map]=*map;

  return 0;

}  /* pxa_pcmcia_set_mem_map() */