162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/pcmcia/sa1100_jornada720.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Jornada720 PCMCIA specific routines
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/errno.h>
1162306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <mach/hardware.h>
1662306a36Sopenharmony_ci#include <asm/mach-types.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "sa1111_generic.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*
2162306a36Sopenharmony_ci * Socket 0 power: GPIO A0
2262306a36Sopenharmony_ci * Socket 0 3V: GPIO A2
2362306a36Sopenharmony_ci * Socket 1 power: GPIO A1 & GPIO A3
2462306a36Sopenharmony_ci * Socket 1 3V: GPIO A3
2562306a36Sopenharmony_ci * Does Socket 1 3V actually do anything?
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_cienum {
2862306a36Sopenharmony_ci	J720_GPIO_PWR,
2962306a36Sopenharmony_ci	J720_GPIO_3V,
3062306a36Sopenharmony_ci	J720_GPIO_MAX,
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_cistruct jornada720_data {
3362306a36Sopenharmony_ci	struct gpio_desc *gpio[J720_GPIO_MAX];
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int jornada720_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct device *dev = skt->socket.dev.parent;
3962306a36Sopenharmony_ci	struct jornada720_data *j;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	j = devm_kzalloc(dev, sizeof(*j), GFP_KERNEL);
4262306a36Sopenharmony_ci	if (!j)
4362306a36Sopenharmony_ci		return -ENOMEM;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	j->gpio[J720_GPIO_PWR] = devm_gpiod_get(dev, skt->nr ? "s1-power" :
4662306a36Sopenharmony_ci						"s0-power", GPIOD_OUT_LOW);
4762306a36Sopenharmony_ci	if (IS_ERR(j->gpio[J720_GPIO_PWR]))
4862306a36Sopenharmony_ci		return PTR_ERR(j->gpio[J720_GPIO_PWR]);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	j->gpio[J720_GPIO_3V] = devm_gpiod_get(dev, skt->nr ? "s1-3v" :
5162306a36Sopenharmony_ci					       "s0-3v", GPIOD_OUT_LOW);
5262306a36Sopenharmony_ci	if (IS_ERR(j->gpio[J720_GPIO_3V]))
5362306a36Sopenharmony_ci		return PTR_ERR(j->gpio[J720_GPIO_3V]);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	skt->driver_data = j;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return 0;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int
6162306a36Sopenharmony_cijornada720_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	struct jornada720_data *j = skt->driver_data;
6462306a36Sopenharmony_ci	DECLARE_BITMAP(values, J720_GPIO_MAX) = { 0, };
6562306a36Sopenharmony_ci	int ret;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	printk(KERN_INFO "%s(): config socket %d vcc %d vpp %d\n", __func__,
6862306a36Sopenharmony_ci		skt->nr, state->Vcc, state->Vpp);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	switch (skt->nr) {
7162306a36Sopenharmony_ci	case 0:
7262306a36Sopenharmony_ci		switch (state->Vcc) {
7362306a36Sopenharmony_ci		default:
7462306a36Sopenharmony_ci		case  0:
7562306a36Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 0);
7662306a36Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 0);
7762306a36Sopenharmony_ci			break;
7862306a36Sopenharmony_ci		case 33:
7962306a36Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 1);
8062306a36Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 1);
8162306a36Sopenharmony_ci			break;
8262306a36Sopenharmony_ci		case 50:
8362306a36Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 1);
8462306a36Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 0);
8562306a36Sopenharmony_ci			break;
8662306a36Sopenharmony_ci		}
8762306a36Sopenharmony_ci		break;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	case 1:
9062306a36Sopenharmony_ci		switch (state->Vcc) {
9162306a36Sopenharmony_ci		default:
9262306a36Sopenharmony_ci		case 0:
9362306a36Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 0);
9462306a36Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 0);
9562306a36Sopenharmony_ci			break;
9662306a36Sopenharmony_ci		case 33:
9762306a36Sopenharmony_ci		case 50:
9862306a36Sopenharmony_ci			__assign_bit(J720_GPIO_PWR, values, 1);
9962306a36Sopenharmony_ci			__assign_bit(J720_GPIO_3V, values, 1);
10062306a36Sopenharmony_ci			break;
10162306a36Sopenharmony_ci		}
10262306a36Sopenharmony_ci		break;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	default:
10562306a36Sopenharmony_ci		return -1;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (state->Vpp != state->Vcc && state->Vpp != 0) {
10962306a36Sopenharmony_ci		printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
11062306a36Sopenharmony_ci			__func__, state->Vpp);
11162306a36Sopenharmony_ci		return -EPERM;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	ret = sa1111_pcmcia_configure_socket(skt, state);
11562306a36Sopenharmony_ci	if (ret == 0)
11662306a36Sopenharmony_ci		ret = gpiod_set_array_value_cansleep(J720_GPIO_MAX, j->gpio,
11762306a36Sopenharmony_ci						     NULL, values);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return ret;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic struct pcmcia_low_level jornada720_pcmcia_ops = {
12362306a36Sopenharmony_ci	.owner			= THIS_MODULE,
12462306a36Sopenharmony_ci	.hw_init		= jornada720_pcmcia_hw_init,
12562306a36Sopenharmony_ci	.configure_socket	= jornada720_pcmcia_configure_socket,
12662306a36Sopenharmony_ci	.first			= 0,
12762306a36Sopenharmony_ci	.nr			= 2,
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciint pcmcia_jornada720_init(struct sa1111_dev *sadev)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	/* Fixme: why messing around with SA11x0's GPIO1? */
13362306a36Sopenharmony_ci	GRER |= 0x00000002;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	sa11xx_drv_pcmcia_ops(&jornada720_pcmcia_ops);
13662306a36Sopenharmony_ci	return sa1111_pcmcia_add(sadev, &jornada720_pcmcia_ops,
13762306a36Sopenharmony_ci				 sa11xx_drv_pcmcia_add_one);
13862306a36Sopenharmony_ci}
139