Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/drivers/pcmcia/pxa2xx_palmtc.c
0004  *
0005  * Driver for Palm Tungsten|C PCMCIA
0006  *
0007  * Copyright (C) 2008 Alex Osborne <ato@meshy.org>
0008  * Copyright (C) 2009-2011 Marek Vasut <marek.vasut@gmail.com>
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/gpio.h>
0014 #include <linux/delay.h>
0015 
0016 #include <asm/mach-types.h>
0017 #include "palmtc.h"
0018 #include <pcmcia/soc_common.h>
0019 
0020 static struct gpio palmtc_pcmcia_gpios[] = {
0021     { GPIO_NR_PALMTC_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" },
0022     { GPIO_NR_PALMTC_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" },
0023     { GPIO_NR_PALMTC_PCMCIA_POWER3, GPIOF_INIT_LOW, "PCMCIA Power 3" },
0024     { GPIO_NR_PALMTC_PCMCIA_RESET,  GPIOF_INIT_HIGH,"PCMCIA Reset" },
0025     { GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN, "PCMCIA Power Ready" },
0026 };
0027 
0028 static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
0029 {
0030     int ret;
0031 
0032     ret = gpio_request_array(palmtc_pcmcia_gpios,
0033                 ARRAY_SIZE(palmtc_pcmcia_gpios));
0034 
0035     skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMTC_PCMCIA_READY;
0036     skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
0037 
0038     return ret;
0039 }
0040 
0041 static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
0042 {
0043     gpio_free_array(palmtc_pcmcia_gpios, ARRAY_SIZE(palmtc_pcmcia_gpios));
0044 }
0045 
0046 static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
0047                     struct pcmcia_state *state)
0048 {
0049     state->detect = 1; /* always inserted */
0050     state->vs_3v  = 1;
0051     state->vs_Xv  = 0;
0052 }
0053 
0054 static int palmtc_wifi_powerdown(void)
0055 {
0056     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
0057     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 0);
0058     mdelay(40);
0059     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 0);
0060     return 0;
0061 }
0062 
0063 static int palmtc_wifi_powerup(void)
0064 {
0065     int timeout = 50;
0066 
0067     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 1);
0068     mdelay(50);
0069 
0070     /* Power up the card, 1.8V first, after a while 3.3V */
0071     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER1, 1);
0072     mdelay(100);
0073     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER2, 1);
0074 
0075     /* Wait till the card is ready */
0076     while (!gpio_get_value(GPIO_NR_PALMTC_PCMCIA_PWRREADY) &&
0077         timeout) {
0078         mdelay(1);
0079         timeout--;
0080     }
0081 
0082     /* Power down the WiFi in case of error */
0083     if (!timeout) {
0084         palmtc_wifi_powerdown();
0085         return 1;
0086     }
0087 
0088     /* Reset the card */
0089     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 1);
0090     mdelay(20);
0091     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_RESET, 0);
0092     mdelay(25);
0093 
0094     gpio_set_value(GPIO_NR_PALMTC_PCMCIA_POWER3, 0);
0095 
0096     return 0;
0097 }
0098 
0099 static int palmtc_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
0100                     const socket_state_t *state)
0101 {
0102     int ret = 1;
0103 
0104     if (state->Vcc == 0)
0105         ret = palmtc_wifi_powerdown();
0106     else if (state->Vcc == 33)
0107         ret = palmtc_wifi_powerup();
0108 
0109     return ret;
0110 }
0111 
0112 static struct pcmcia_low_level palmtc_pcmcia_ops = {
0113     .owner          = THIS_MODULE,
0114 
0115     .first          = 0,
0116     .nr         = 1,
0117 
0118     .hw_init        = palmtc_pcmcia_hw_init,
0119     .hw_shutdown        = palmtc_pcmcia_hw_shutdown,
0120 
0121     .socket_state       = palmtc_pcmcia_socket_state,
0122     .configure_socket   = palmtc_pcmcia_configure_socket,
0123 };
0124 
0125 static struct platform_device *palmtc_pcmcia_device;
0126 
0127 static int __init palmtc_pcmcia_init(void)
0128 {
0129     int ret;
0130 
0131     if (!machine_is_palmtc())
0132         return -ENODEV;
0133 
0134     palmtc_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
0135     if (!palmtc_pcmcia_device)
0136         return -ENOMEM;
0137 
0138     ret = platform_device_add_data(palmtc_pcmcia_device, &palmtc_pcmcia_ops,
0139                     sizeof(palmtc_pcmcia_ops));
0140 
0141     if (!ret)
0142         ret = platform_device_add(palmtc_pcmcia_device);
0143 
0144     if (ret)
0145         platform_device_put(palmtc_pcmcia_device);
0146 
0147     return ret;
0148 }
0149 
0150 static void __exit palmtc_pcmcia_exit(void)
0151 {
0152     platform_device_unregister(palmtc_pcmcia_device);
0153 }
0154 
0155 module_init(palmtc_pcmcia_init);
0156 module_exit(palmtc_pcmcia_exit);
0157 
0158 MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
0159         " Marek Vasut <marek.vasut@gmail.com>");
0160 MODULE_DESCRIPTION("PCMCIA support for Palm Tungsten|C");
0161 MODULE_ALIAS("platform:pxa2xx-pcmcia");
0162 MODULE_LICENSE("GPL");