| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 1 | /* | 
|  | 2 | * linux/drivers/pcmcia/pxa/pxa_cm_x255.c | 
|  | 3 | * | 
|  | 4 | * This program is free software; you can redistribute it and/or modify | 
|  | 5 | * it under the terms of the GNU General Public License version 2 as | 
|  | 6 | * published by the Free Software Foundation. | 
|  | 7 | * | 
|  | 8 | * Compulab Ltd., 2003, 2007, 2008 | 
|  | 9 | * Mike Rapoport <mike@compulab.co.il> | 
|  | 10 | * | 
|  | 11 | */ | 
|  | 12 |  | 
|  | 13 | #include <linux/platform_device.h> | 
|  | 14 | #include <linux/irq.h> | 
|  | 15 | #include <linux/delay.h> | 
|  | 16 | #include <linux/gpio.h> | 
| Paul Gortmaker | 402b20d | 2011-07-31 16:21:42 -0400 | [diff] [blame] | 17 | #include <linux/export.h> | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 18 |  | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 19 | #include "soc_common.h" | 
|  | 20 |  | 
|  | 21 | #define GPIO_PCMCIA_SKTSEL	(54) | 
|  | 22 | #define GPIO_PCMCIA_S0_CD_VALID	(16) | 
|  | 23 | #define GPIO_PCMCIA_S1_CD_VALID	(17) | 
|  | 24 | #define GPIO_PCMCIA_S0_RDYINT	(6) | 
|  | 25 | #define GPIO_PCMCIA_S1_RDYINT	(8) | 
|  | 26 | #define GPIO_PCMCIA_RESET	(9) | 
|  | 27 |  | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 28 | static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | 
|  | 29 | { | 
|  | 30 | int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset"); | 
|  | 31 | if (ret) | 
|  | 32 | return ret; | 
|  | 33 | gpio_direction_output(GPIO_PCMCIA_RESET, 0); | 
|  | 34 |  | 
| Russell King | a9bb5a4 | 2012-01-13 22:56:32 +0000 | [diff] [blame] | 35 | if (skt->nr == 0) { | 
|  | 36 | skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S0_CD_VALID; | 
|  | 37 | skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD"; | 
|  | 38 | skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S0_RDYINT; | 
|  | 39 | skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY"; | 
|  | 40 | } else { | 
|  | 41 | skt->stat[SOC_STAT_CD].gpio = GPIO_PCMCIA_S1_CD_VALID; | 
|  | 42 | skt->stat[SOC_STAT_CD].name = "PCMCIA1 CD"; | 
|  | 43 | skt->stat[SOC_STAT_RDY].gpio = GPIO_PCMCIA_S1_RDYINT; | 
|  | 44 | skt->stat[SOC_STAT_RDY].name = "PCMCIA1 RDY"; | 
|  | 45 | } | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 46 |  | 
| Russell King | a9bb5a4 | 2012-01-13 22:56:32 +0000 | [diff] [blame] | 47 | return 0; | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 48 | } | 
|  | 49 |  | 
|  | 50 | static void cmx255_pcmcia_shutdown(struct soc_pcmcia_socket *skt) | 
|  | 51 | { | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 52 | gpio_free(GPIO_PCMCIA_RESET); | 
|  | 53 | } | 
|  | 54 |  | 
|  | 55 |  | 
|  | 56 | static void cmx255_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | 
|  | 57 | struct pcmcia_state *state) | 
|  | 58 | { | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 59 | state->vs_3v  = 0; | 
|  | 60 | state->vs_Xv  = 0; | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 61 | } | 
|  | 62 |  | 
|  | 63 |  | 
|  | 64 | static int cmx255_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | 
|  | 65 | const socket_state_t *state) | 
|  | 66 | { | 
|  | 67 | switch (skt->nr) { | 
|  | 68 | case 0: | 
|  | 69 | if (state->flags & SS_RESET) { | 
|  | 70 | gpio_set_value(GPIO_PCMCIA_SKTSEL, 0); | 
|  | 71 | udelay(1); | 
|  | 72 | gpio_set_value(GPIO_PCMCIA_RESET, 1); | 
|  | 73 | udelay(10); | 
|  | 74 | gpio_set_value(GPIO_PCMCIA_RESET, 0); | 
|  | 75 | } | 
|  | 76 | break; | 
|  | 77 | case 1: | 
|  | 78 | if (state->flags & SS_RESET) { | 
|  | 79 | gpio_set_value(GPIO_PCMCIA_SKTSEL, 1); | 
|  | 80 | udelay(1); | 
|  | 81 | gpio_set_value(GPIO_PCMCIA_RESET, 1); | 
|  | 82 | udelay(10); | 
|  | 83 | gpio_set_value(GPIO_PCMCIA_RESET, 0); | 
|  | 84 | } | 
|  | 85 | break; | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | return 0; | 
|  | 89 | } | 
|  | 90 |  | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 91 | static struct pcmcia_low_level cmx255_pcmcia_ops __initdata = { | 
|  | 92 | .owner			= THIS_MODULE, | 
|  | 93 | .hw_init		= cmx255_pcmcia_hw_init, | 
|  | 94 | .hw_shutdown		= cmx255_pcmcia_shutdown, | 
|  | 95 | .socket_state		= cmx255_pcmcia_socket_state, | 
|  | 96 | .configure_socket	= cmx255_pcmcia_configure_socket, | 
| Mike Rapoport | 8616e2f | 2008-10-05 10:27:22 +0100 | [diff] [blame] | 97 | .nr			= 1, | 
|  | 98 | }; | 
|  | 99 |  | 
|  | 100 | static struct platform_device *cmx255_pcmcia_device; | 
|  | 101 |  | 
|  | 102 | int __init cmx255_pcmcia_init(void) | 
|  | 103 | { | 
|  | 104 | int ret; | 
|  | 105 |  | 
|  | 106 | cmx255_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); | 
|  | 107 |  | 
|  | 108 | if (!cmx255_pcmcia_device) | 
|  | 109 | return -ENOMEM; | 
|  | 110 |  | 
|  | 111 | ret = platform_device_add_data(cmx255_pcmcia_device, &cmx255_pcmcia_ops, | 
|  | 112 | sizeof(cmx255_pcmcia_ops)); | 
|  | 113 |  | 
|  | 114 | if (ret == 0) { | 
|  | 115 | printk(KERN_INFO "Registering cm-x255 PCMCIA interface.\n"); | 
|  | 116 | ret = platform_device_add(cmx255_pcmcia_device); | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | if (ret) | 
|  | 120 | platform_device_put(cmx255_pcmcia_device); | 
|  | 121 |  | 
|  | 122 | return ret; | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | void __exit cmx255_pcmcia_exit(void) | 
|  | 126 | { | 
|  | 127 | platform_device_unregister(cmx255_pcmcia_device); | 
|  | 128 | } |