1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * drivers/pcmcia/sa1100_jornada720.c
4  *
5  * Jornada720 PCMCIA specific routines
6  *
7  */
8 #include <linux/module.h>
9 #include <linux/device.h>
10 #include <linux/errno.h>
11 #include <linux/gpio/consumer.h>
12 #include <linux/init.h>
13 #include <linux/io.h>
14 
15 #include <mach/hardware.h>
16 #include <asm/mach-types.h>
17 
18 #include "sa1111_generic.h"
19 
20 /*
21  * Socket 0 power: GPIO A0
22  * Socket 0 3V: GPIO A2
23  * Socket 1 power: GPIO A1 & GPIO A3
24  * Socket 1 3V: GPIO A3
25  * Does Socket 1 3V actually do anything?
26  */
27 enum {
28 	J720_GPIO_PWR,
29 	J720_GPIO_3V,
30 	J720_GPIO_MAX,
31 };
32 struct jornada720_data {
33 	struct gpio_desc *gpio[J720_GPIO_MAX];
34 };
35 
36 static int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
37 {
38 	struct device *dev = skt->socket.dev.parent;
39 	struct jornada720_data *j;
40 
41 	j = devm_kzalloc(dev, sizeof(*j), GFP_KERNEL);
42 	if (!j)
43 		return -ENOMEM;
44 
45 	j->gpio[J720_GPIO_PWR] = devm_gpiod_get(dev, skt->nr ? "s1-power" :
46 						"s0-power", GPIOD_OUT_LOW);
47 	if (IS_ERR(j->gpio[J720_GPIO_PWR]))
48 		return PTR_ERR(j->gpio[J720_GPIO_PWR]);
49 
50 	j->gpio[J720_GPIO_3V] = devm_gpiod_get(dev, skt->nr ? "s1-3v" :
51 					       "s0-3v", GPIOD_OUT_LOW);
52 	if (IS_ERR(j->gpio[J720_GPIO_3V]))
53 		return PTR_ERR(j->gpio[J720_GPIO_3V]);
54 
55 	skt->driver_data = j;
56 
57 	return 0;
58 }
59 
60 static int
61 jornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
62 {
63 	struct jornada720_data *j = skt->driver_data;
64 	DECLARE_BITMAP(values, J720_GPIO_MAX) = { 0, };
65 	int ret;
66 
67 	printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
68 		skt->nr, state->Vcc, state->Vpp);
69 
70 	switch (skt->nr) {
71 	case 0:
72 		switch (state->Vcc) {
73 		default:
74 		case  0:
75 			__assign_bit(J720_GPIO_PWR, values, 0);
76 			__assign_bit(J720_GPIO_3V, values, 0);
77 			break;
78 		case 33:
79 			__assign_bit(J720_GPIO_PWR, values, 1);
80 			__assign_bit(J720_GPIO_3V, values, 1);
81 			break;
82 		case 50:
83 			__assign_bit(J720_GPIO_PWR, values, 1);
84 			__assign_bit(J720_GPIO_3V, values, 0);
85 			break;
86 		}
87 		break;
88 
89 	case 1:
90 		switch (state->Vcc) {
91 		default:
92 		case 0:
93 			__assign_bit(J720_GPIO_PWR, values, 0);
94 			__assign_bit(J720_GPIO_3V, values, 0);
95 			break;
96 		case 33:
97 		case 50:
98 			__assign_bit(J720_GPIO_PWR, values, 1);
99 			__assign_bit(J720_GPIO_3V, values, 1);
100 			break;
101 		}
102 		break;
103 
104 	default:
105 		return -1;
106 	}
107 
108 	if (state->Vpp != state->Vcc && state->Vpp != 0) {
109 		printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
110 			__func__, state->Vpp);
111 		return -EPERM;
112 	}
113 
114 	ret = sa1111_pcmcia_configure_socket(skt, state);
115 	if (ret == 0)
116 		ret = gpiod_set_array_value_cansleep(J720_GPIO_MAX, j->gpio,
117 						     NULL, values);
118 
119 	return ret;
120 }
121 
122 static struct pcmcia_low_level jornada720_pcmcia_ops = {
123 	.owner			= THIS_MODULE,
124 	.hw_init		= jornada720_pcmcia_hw_init,
125 	.configure_socket	= jornada720_pcmcia_configure_socket,
126 	.first			= 0,
127 	.nr			= 2,
128 };
129 
130 int pcmcia_jornada720_init(struct sa1111_dev *sadev)
131 {
132 	/* Fixme: why messing around with SA11x0's GPIO1? */
133 	GRER |= 0x00000002;
134 
135 	sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
136 	return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
137 				 sa11xx_drv_pcmcia_add_one);
138 }
139