18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * drivers/pcmcia/sa1100_jornada720.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Jornada720 PCMCIA specific routines
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/device.h>
108c2ecf20Sopenharmony_ci#include <linux/errno.h>
118c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <mach/hardware.h>
168c2ecf20Sopenharmony_ci#include <asm/mach-types.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "sa1111_generic.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * Socket 0 power: GPIO A0
228c2ecf20Sopenharmony_ci * Socket 0 3V: GPIO A2
238c2ecf20Sopenharmony_ci * Socket 1 power: GPIO A1 & GPIO A3
248c2ecf20Sopenharmony_ci * Socket 1 3V: GPIO A3
258c2ecf20Sopenharmony_ci * Does Socket 1 3V actually do anything?
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_cienum {
288c2ecf20Sopenharmony_ci	J720_GPIO_PWR,
298c2ecf20Sopenharmony_ci	J720_GPIO_3V,
308c2ecf20Sopenharmony_ci	J720_GPIO_MAX,
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_cistruct jornada720_data {
338c2ecf20Sopenharmony_ci	struct gpio_desc *gpio[J720_GPIO_MAX];
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct device *dev = skt->socket.dev.parent;
398c2ecf20Sopenharmony_ci	struct jornada720_data *j;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	j = devm_kzalloc(dev, sizeof(*j), GFP_KERNEL);
428c2ecf20Sopenharmony_ci	if (!j)
438c2ecf20Sopenharmony_ci		return -ENOMEM;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	j->gpio[J720_GPIO_PWR] = devm_gpiod_get(dev, skt->nr ? "s1-power" :
468c2ecf20Sopenharmony_ci						"s0-power", GPIOD_OUT_LOW);
478c2ecf20Sopenharmony_ci	if (IS_ERR(j->gpio[J720_GPIO_PWR]))
488c2ecf20Sopenharmony_ci		return PTR_ERR(j->gpio[J720_GPIO_PWR]);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	j->gpio[J720_GPIO_3V] = devm_gpiod_get(dev, skt->nr ? "s1-3v" :
518c2ecf20Sopenharmony_ci					       "s0-3v", GPIOD_OUT_LOW);
528c2ecf20Sopenharmony_ci	if (IS_ERR(j->gpio[J720_GPIO_3V]))
538c2ecf20Sopenharmony_ci		return PTR_ERR(j->gpio[J720_GPIO_3V]);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	skt->driver_data = j;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	return 0;
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic int
618c2ecf20Sopenharmony_cijornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct jornada720_data *j = skt->driver_data;
648c2ecf20Sopenharmony_ci	DECLARE_BITMAP(values, J720_GPIO_MAX) = { 0, };
658c2ecf20Sopenharmony_ci	int ret;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
688c2ecf20Sopenharmony_ci		skt->nr, state->Vcc, state->Vpp);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	switch (skt->nr) {
718c2ecf20Sopenharmony_ci	case 0:
728c2ecf20Sopenharmony_ci		switch (state->Vcc) {
738c2ecf20Sopenharmony_ci		default:
748c2ecf20Sopenharmony_ci		case  0:
758c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 0);
768c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 0);
778c2ecf20Sopenharmony_ci			break;
788c2ecf20Sopenharmony_ci		case 33:
798c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 1);
808c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 1);
818c2ecf20Sopenharmony_ci			break;
828c2ecf20Sopenharmony_ci		case 50:
838c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 1);
848c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 0);
858c2ecf20Sopenharmony_ci			break;
868c2ecf20Sopenharmony_ci		}
878c2ecf20Sopenharmony_ci		break;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	case 1:
908c2ecf20Sopenharmony_ci		switch (state->Vcc) {
918c2ecf20Sopenharmony_ci		default:
928c2ecf20Sopenharmony_ci		case 0:
938c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 0);
948c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 0);
958c2ecf20Sopenharmony_ci			break;
968c2ecf20Sopenharmony_ci		case 33:
978c2ecf20Sopenharmony_ci		case 50:
988c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 1);
998c2ecf20Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 1);
1008c2ecf20Sopenharmony_ci			break;
1018c2ecf20Sopenharmony_ci		}
1028c2ecf20Sopenharmony_ci		break;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	default:
1058c2ecf20Sopenharmony_ci		return -1;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (state->Vpp != state->Vcc && state->Vpp != 0) {
1098c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
1108c2ecf20Sopenharmony_ci			__func__, state->Vpp);
1118c2ecf20Sopenharmony_ci		return -EPERM;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	ret = sa1111_pcmcia_configure_socket(skt, state);
1158c2ecf20Sopenharmony_ci	if (ret == 0)
1168c2ecf20Sopenharmony_ci		ret = gpiod_set_array_value_cansleep(J720_GPIO_MAX, j->gpio,
1178c2ecf20Sopenharmony_ci						     NULL, values);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return ret;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic struct pcmcia_low_level jornada720_pcmcia_ops = {
1238c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
1248c2ecf20Sopenharmony_ci	.hw_init		= jornada720_pcmcia_hw_init,
1258c2ecf20Sopenharmony_ci	.configure_socket	= jornada720_pcmcia_configure_socket,
1268c2ecf20Sopenharmony_ci	.first			= 0,
1278c2ecf20Sopenharmony_ci	.nr			= 2,
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciint pcmcia_jornada720_init(struct sa1111_dev *sadev)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	/* Fixme: why messing around with SA11x0's GPIO1? */
1338c2ecf20Sopenharmony_ci	GRER |= 0x00000002;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
1368c2ecf20Sopenharmony_ci	return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
1378c2ecf20Sopenharmony_ci				 sa11xx_drv_pcmcia_add_one);
1388c2ecf20Sopenharmony_ci}
139