Merge tag 'mtd/for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
[linux-2.6-microblaze.git] / drivers / pcmcia / pxa2xx_stargate2.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * linux/drivers/pcmcia/pxa2xx_stargate2.c
4  *
5  * Stargate 2 PCMCIA specific routines.
6  *
7  * Created:     December 6, 2005
8  * Author:      Ed C. Epp
9  * Copyright:   Intel Corp 2005
10  *              Jonathan Cameron <jic23@cam.ac.uk> 2009
11  */
12
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/kernel.h>
16 #include <linux/interrupt.h>
17 #include <linux/delay.h>
18 #include <linux/platform_device.h>
19 #include <linux/gpio.h>
20
21 #include <pcmcia/ss.h>
22
23 #include <asm/irq.h>
24 #include <asm/mach-types.h>
25
26 #include "soc_common.h"
27
28 #define SG2_S0_POWER_CTL        108
29 #define SG2_S0_GPIO_RESET       82
30 #define SG2_S0_GPIO_DETECT      53
31 #define SG2_S0_GPIO_READY       81
32
33 static struct gpio sg2_pcmcia_gpios[] = {
34         { SG2_S0_GPIO_RESET, GPIOF_OUT_INIT_HIGH, "PCMCIA Reset" },
35         { SG2_S0_POWER_CTL, GPIOF_OUT_INIT_HIGH, "PCMCIA Power Ctrl" },
36 };
37
38 static int sg2_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
39 {
40         skt->stat[SOC_STAT_CD].gpio = SG2_S0_GPIO_DETECT;
41         skt->stat[SOC_STAT_CD].name = "PCMCIA0 CD";
42         skt->stat[SOC_STAT_RDY].gpio = SG2_S0_GPIO_READY;
43         skt->stat[SOC_STAT_RDY].name = "PCMCIA0 RDY";
44         return 0;
45 }
46
47 static void sg2_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
48                                     struct pcmcia_state *state)
49 {
50         state->bvd1   = 0; /* not available - battery detect on card */
51         state->bvd2   = 0; /* not available */
52         state->vs_3v  = 1; /* not available - voltage detect for card */
53         state->vs_Xv  = 0; /* not available */
54 }
55
56 static int sg2_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
57                                        const socket_state_t *state)
58 {
59         /* Enable card power */
60         switch (state->Vcc) {
61         case 0:
62                 /* sets power ctl register high */
63                 gpio_set_value(SG2_S0_POWER_CTL, 1);
64                 break;
65         case 33:
66         case 50:
67                 /* sets power control register low (clear) */
68                 gpio_set_value(SG2_S0_POWER_CTL, 0);
69                 msleep(100);
70                 break;
71         default:
72                 pr_err("%s(): bad Vcc %u\n",
73                        __func__, state->Vcc);
74                 return -1;
75         }
76
77         /* reset */
78         gpio_set_value(SG2_S0_GPIO_RESET, !!(state->flags & SS_RESET));
79
80         return 0;
81 }
82
83 static struct pcmcia_low_level sg2_pcmcia_ops __initdata = {
84         .owner                  = THIS_MODULE,
85         .hw_init                = sg2_pcmcia_hw_init,
86         .socket_state           = sg2_pcmcia_socket_state,
87         .configure_socket       = sg2_pcmcia_configure_socket,
88         .nr                     = 1,
89 };
90
91 static struct platform_device *sg2_pcmcia_device;
92
93 static int __init sg2_pcmcia_init(void)
94 {
95         int ret;
96
97         if (!machine_is_stargate2())
98                 return -ENODEV;
99
100         sg2_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
101         if (!sg2_pcmcia_device)
102                 return -ENOMEM;
103
104         ret = gpio_request_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
105         if (ret)
106                 goto error_put_platform_device;
107
108         ret = platform_device_add_data(sg2_pcmcia_device,
109                                        &sg2_pcmcia_ops,
110                                        sizeof(sg2_pcmcia_ops));
111         if (ret)
112                 goto error_free_gpios;
113
114         ret = platform_device_add(sg2_pcmcia_device);
115         if (ret)
116                 goto error_free_gpios;
117
118         return 0;
119 error_free_gpios:
120         gpio_free_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
121 error_put_platform_device:
122         platform_device_put(sg2_pcmcia_device);
123
124         return ret;
125 }
126
127 static void __exit sg2_pcmcia_exit(void)
128 {
129         platform_device_unregister(sg2_pcmcia_device);
130         gpio_free_array(sg2_pcmcia_gpios, ARRAY_SIZE(sg2_pcmcia_gpios));
131 }
132
133 fs_initcall(sg2_pcmcia_init);
134 module_exit(sg2_pcmcia_exit);
135
136 MODULE_LICENSE("GPL");
137 MODULE_ALIAS("platform:pxa2xx-pcmcia");