Version:  2.0.40 2.2.26 2.4.37 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17

Linux/drivers/pcmcia/pxa2xx_viper.c

  1 /*
  2  * Viper/Zeus PCMCIA support
  3  *   Copyright 2004 Arcom Control Systems
  4  *
  5  * Maintained by Marc Zyngier <maz@misterjones.org>
  6  *
  7  * Based on:
  8  *   iPAQ h2200 PCMCIA support
  9  *   Copyright 2004 Koen Kooi <koen@vestingbar.nl>
 10  *
 11  * This file is subject to the terms and conditions of the GNU General Public
 12  * License.  See the file COPYING in the main directory of this archive for
 13  * more details.
 14  */
 15 
 16 #include <linux/module.h>
 17 #include <linux/init.h>
 18 #include <linux/kernel.h>
 19 #include <linux/errno.h>
 20 #include <linux/interrupt.h>
 21 #include <linux/platform_device.h>
 22 #include <linux/gpio.h>
 23 
 24 #include <pcmcia/ss.h>
 25 
 26 #include <asm/irq.h>
 27 
 28 #include <linux/platform_data/pcmcia-pxa2xx_viper.h>
 29 
 30 #include "soc_common.h"
 31 #include "pxa2xx_base.h"
 32 
 33 static struct platform_device *arcom_pcmcia_dev;
 34 
 35 static inline struct arcom_pcmcia_pdata *viper_get_pdata(void)
 36 {
 37         return arcom_pcmcia_dev->dev.platform_data;
 38 }
 39 
 40 static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 41 {
 42         struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
 43         unsigned long flags;
 44 
 45         skt->stat[SOC_STAT_CD].gpio = pdata->cd_gpio;
 46         skt->stat[SOC_STAT_CD].name = "PCMCIA_CD";
 47         skt->stat[SOC_STAT_RDY].gpio = pdata->rdy_gpio;
 48         skt->stat[SOC_STAT_RDY].name = "CF ready";
 49 
 50         if (gpio_request(pdata->pwr_gpio, "CF power"))
 51                 goto err_request_pwr;
 52 
 53         local_irq_save(flags);
 54 
 55         if (gpio_direction_output(pdata->pwr_gpio, 0)) {
 56                 local_irq_restore(flags);
 57                 goto err_dir;
 58         }
 59 
 60         local_irq_restore(flags);
 61 
 62         return 0;
 63 
 64 err_dir:
 65         gpio_free(pdata->pwr_gpio);
 66 err_request_pwr:
 67         dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n");
 68         return -1;
 69 }
 70 
 71 /*
 72  * Release all resources.
 73  */
 74 static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 75 {
 76         struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
 77 
 78         gpio_free(pdata->pwr_gpio);
 79 }
 80 
 81 static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
 82                                       struct pcmcia_state *state)
 83 {
 84         state->vs_3v  = 1; /* Can only apply 3.3V */
 85         state->vs_Xv  = 0;
 86 }
 87 
 88 static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
 89                                          const socket_state_t *state)
 90 {
 91         struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
 92 
 93         /* Silently ignore Vpp, output enable, speaker enable. */
 94         pdata->reset(state->flags & SS_RESET);
 95 
 96         /* Apply socket voltage */
 97         switch (state->Vcc) {
 98         case 0:
 99                 gpio_set_value(pdata->pwr_gpio, 0);
100                 break;
101         case 33:
102                 gpio_set_value(pdata->pwr_gpio, 1);
103                 break;
104         default:
105                 dev_err(&arcom_pcmcia_dev->dev, "Unsupported Vcc:%d\n", state->Vcc);
106                 return -1;
107         }
108 
109         return 0;
110 }
111 
112 static struct pcmcia_low_level viper_pcmcia_ops = {
113         .owner                  = THIS_MODULE,
114         .hw_init                = viper_pcmcia_hw_init,
115         .hw_shutdown            = viper_pcmcia_hw_shutdown,
116         .socket_state           = viper_pcmcia_socket_state,
117         .configure_socket       = viper_pcmcia_configure_socket,
118         .nr                     = 1,
119 };
120 
121 static struct platform_device *viper_pcmcia_device;
122 
123 static int viper_pcmcia_probe(struct platform_device *pdev)
124 {
125         int ret;
126 
127         /* I can't imagine more than one device, but you never know... */
128         if (arcom_pcmcia_dev)
129                 return -EEXIST;
130 
131         if (!pdev->dev.platform_data)
132                 return -EINVAL;
133 
134         viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
135         if (!viper_pcmcia_device)
136                 return -ENOMEM;
137 
138         arcom_pcmcia_dev = pdev;
139 
140         viper_pcmcia_device->dev.parent = &pdev->dev;
141 
142         ret = platform_device_add_data(viper_pcmcia_device,
143                                        &viper_pcmcia_ops,
144                                        sizeof(viper_pcmcia_ops));
145 
146         if (!ret)
147                 ret = platform_device_add(viper_pcmcia_device);
148 
149         if (ret) {
150                 platform_device_put(viper_pcmcia_device);
151                 arcom_pcmcia_dev = NULL;
152         }
153 
154         return ret;
155 }
156 
157 static int viper_pcmcia_remove(struct platform_device *pdev)
158 {
159         platform_device_unregister(viper_pcmcia_device);
160         arcom_pcmcia_dev = NULL;
161         return 0;
162 }
163 
164 static struct platform_device_id viper_pcmcia_id_table[] = {
165         { .name = "viper-pcmcia", },
166         { .name = "zeus-pcmcia",  },
167         { },
168 };
169 
170 static struct platform_driver viper_pcmcia_driver = {
171         .probe          = viper_pcmcia_probe,
172         .remove         = viper_pcmcia_remove,
173         .driver         = {
174                 .name   = "arcom-pcmcia",
175                 .owner  = THIS_MODULE,
176         },
177         .id_table       = viper_pcmcia_id_table,
178 };
179 
180 module_platform_driver(viper_pcmcia_driver);
181 
182 MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table);
183 MODULE_LICENSE("GPL");
184 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us