Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Viper/Zeus PCMCIA support
0003  *   Copyright 2004 Arcom Control Systems
0004  *
0005  * Maintained by Marc Zyngier <maz@misterjones.org>
0006  *
0007  * Based on:
0008  *   iPAQ h2200 PCMCIA support
0009  *   Copyright 2004 Koen Kooi <koen@vestingbar.nl>
0010  *
0011  * This file is subject to the terms and conditions of the GNU General Public
0012  * License.  See the file COPYING in the main directory of this archive for
0013  * more details.
0014  */
0015 
0016 #include <linux/module.h>
0017 #include <linux/init.h>
0018 #include <linux/kernel.h>
0019 #include <linux/errno.h>
0020 #include <linux/interrupt.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/gpio.h>
0023 
0024 #include <pcmcia/ss.h>
0025 #include <pcmcia/soc_common.h>
0026 
0027 #include <asm/irq.h>
0028 
0029 #include "viper-pcmcia.h"
0030 
0031 static struct platform_device *arcom_pcmcia_dev;
0032 
0033 static inline struct arcom_pcmcia_pdata *viper_get_pdata(void)
0034 {
0035     return arcom_pcmcia_dev->dev.platform_data;
0036 }
0037 
0038 static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
0039 {
0040     struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
0041     unsigned long flags;
0042 
0043     skt->stat[SOC_STAT_CD].gpio = pdata->cd_gpio;
0044     skt->stat[SOC_STAT_CD].name = "PCMCIA_CD";
0045     skt->stat[SOC_STAT_RDY].gpio = pdata->rdy_gpio;
0046     skt->stat[SOC_STAT_RDY].name = "CF ready";
0047 
0048     if (gpio_request(pdata->pwr_gpio, "CF power"))
0049         goto err_request_pwr;
0050 
0051     local_irq_save(flags);
0052 
0053     if (gpio_direction_output(pdata->pwr_gpio, 0)) {
0054         local_irq_restore(flags);
0055         goto err_dir;
0056     }
0057 
0058     local_irq_restore(flags);
0059 
0060     return 0;
0061 
0062 err_dir:
0063     gpio_free(pdata->pwr_gpio);
0064 err_request_pwr:
0065     dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n");
0066     return -1;
0067 }
0068 
0069 /*
0070  * Release all resources.
0071  */
0072 static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
0073 {
0074     struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
0075 
0076     gpio_free(pdata->pwr_gpio);
0077 }
0078 
0079 static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
0080                       struct pcmcia_state *state)
0081 {
0082     state->vs_3v  = 1; /* Can only apply 3.3V */
0083     state->vs_Xv  = 0;
0084 }
0085 
0086 static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
0087                      const socket_state_t *state)
0088 {
0089     struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
0090 
0091     /* Silently ignore Vpp, output enable, speaker enable. */
0092     pdata->reset(state->flags & SS_RESET);
0093 
0094     /* Apply socket voltage */
0095     switch (state->Vcc) {
0096     case 0:
0097         gpio_set_value(pdata->pwr_gpio, 0);
0098         break;
0099     case 33:
0100         gpio_set_value(pdata->pwr_gpio, 1);
0101         break;
0102     default:
0103         dev_err(&arcom_pcmcia_dev->dev, "Unsupported Vcc:%d\n", state->Vcc);
0104         return -1;
0105     }
0106 
0107     return 0;
0108 }
0109 
0110 static struct pcmcia_low_level viper_pcmcia_ops = {
0111     .owner              = THIS_MODULE,
0112     .hw_init            = viper_pcmcia_hw_init,
0113     .hw_shutdown        = viper_pcmcia_hw_shutdown,
0114     .socket_state       = viper_pcmcia_socket_state,
0115     .configure_socket   = viper_pcmcia_configure_socket,
0116     .nr                 = 1,
0117 };
0118 
0119 static struct platform_device *viper_pcmcia_device;
0120 
0121 static int viper_pcmcia_probe(struct platform_device *pdev)
0122 {
0123     int ret;
0124 
0125     /* I can't imagine more than one device, but you never know... */
0126     if (arcom_pcmcia_dev)
0127         return -EEXIST;
0128 
0129     if (!pdev->dev.platform_data)
0130         return -EINVAL;
0131 
0132     viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
0133     if (!viper_pcmcia_device)
0134         return -ENOMEM;
0135 
0136     arcom_pcmcia_dev = pdev;
0137 
0138     viper_pcmcia_device->dev.parent = &pdev->dev;
0139 
0140     ret = platform_device_add_data(viper_pcmcia_device,
0141                        &viper_pcmcia_ops,
0142                        sizeof(viper_pcmcia_ops));
0143 
0144     if (!ret)
0145         ret = platform_device_add(viper_pcmcia_device);
0146 
0147     if (ret) {
0148         platform_device_put(viper_pcmcia_device);
0149         arcom_pcmcia_dev = NULL;
0150     }
0151 
0152     return ret;
0153 }
0154 
0155 static int viper_pcmcia_remove(struct platform_device *pdev)
0156 {
0157     platform_device_unregister(viper_pcmcia_device);
0158     arcom_pcmcia_dev = NULL;
0159     return 0;
0160 }
0161 
0162 static struct platform_device_id viper_pcmcia_id_table[] = {
0163     { .name = "viper-pcmcia", },
0164     { .name = "zeus-pcmcia",  },
0165     { },
0166 };
0167 
0168 static struct platform_driver viper_pcmcia_driver = {
0169     .probe      = viper_pcmcia_probe,
0170     .remove     = viper_pcmcia_remove,
0171     .driver     = {
0172         .name   = "arcom-pcmcia",
0173     },
0174     .id_table   = viper_pcmcia_id_table,
0175 };
0176 
0177 module_platform_driver(viper_pcmcia_driver);
0178 
0179 MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table);
0180 MODULE_LICENSE("GPL");