18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/drivers/pcmcia/pxa2xx_lubbock.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author:	George Davis
68c2ecf20Sopenharmony_ci * Created:	Jan 10, 2002
78c2ecf20Sopenharmony_ci * Copyright:	MontaVista Software Inc.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * Lubbock PCMCIA specific routines.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/device.h>
168c2ecf20Sopenharmony_ci#include <linux/errno.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/delay.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <mach/hardware.h>
218c2ecf20Sopenharmony_ci#include <asm/hardware/sa1111.h>
228c2ecf20Sopenharmony_ci#include <asm/mach-types.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "sa1111_generic.h"
258c2ecf20Sopenharmony_ci#include "max1600.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic int lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	struct max1600 *m;
308c2ecf20Sopenharmony_ci	int ret;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	ret = max1600_init(skt->socket.dev.parent, &m,
338c2ecf20Sopenharmony_ci			   skt->nr ? MAX1600_CHAN_B : MAX1600_CHAN_A,
348c2ecf20Sopenharmony_ci			   MAX1600_CODE_HIGH);
358c2ecf20Sopenharmony_ci	if (ret == 0)
368c2ecf20Sopenharmony_ci		skt->driver_data = m;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	return ret;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic int
428c2ecf20Sopenharmony_cilubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
438c2ecf20Sopenharmony_ci				const socket_state_t *state)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct max1600 *m = skt->driver_data;
468c2ecf20Sopenharmony_ci	int ret = 0;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* Lubbock uses the Maxim MAX1602, with the following connections:
498c2ecf20Sopenharmony_ci	 *
508c2ecf20Sopenharmony_ci	 * Socket 0 (PCMCIA):
518c2ecf20Sopenharmony_ci	 *	MAX1602	Lubbock		Register
528c2ecf20Sopenharmony_ci	 *	Pin	Signal
538c2ecf20Sopenharmony_ci	 *	-----	-------		----------------------
548c2ecf20Sopenharmony_ci	 *	A0VPP	S0_PWR0		SA-1111 GPIO A<0>
558c2ecf20Sopenharmony_ci	 *	A1VPP	S0_PWR1		SA-1111 GPIO A<1>
568c2ecf20Sopenharmony_ci	 *	A0VCC	S0_PWR2		SA-1111 GPIO A<2>
578c2ecf20Sopenharmony_ci	 *	A1VCC	S0_PWR3		SA-1111 GPIO A<3>
588c2ecf20Sopenharmony_ci	 *	VX	VCC
598c2ecf20Sopenharmony_ci	 *	VY	+3.3V
608c2ecf20Sopenharmony_ci	 *	12IN	+12V
618c2ecf20Sopenharmony_ci	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
628c2ecf20Sopenharmony_ci	 *
638c2ecf20Sopenharmony_ci	 * Socket 1 (CF):
648c2ecf20Sopenharmony_ci	 *	MAX1602	Lubbock		Register
658c2ecf20Sopenharmony_ci	 *	Pin	Signal
668c2ecf20Sopenharmony_ci	 *	-----	-------		----------------------
678c2ecf20Sopenharmony_ci	 *	A0VPP	GND		VPP is not connected
688c2ecf20Sopenharmony_ci	 *	A1VPP	GND		VPP is not connected
698c2ecf20Sopenharmony_ci	 *	A0VCC	S1_PWR0		MISC_WR<14>
708c2ecf20Sopenharmony_ci	 *	A1VCC	S1_PWR1		MISC_WR<15>
718c2ecf20Sopenharmony_ci	 *	VX	VCC
728c2ecf20Sopenharmony_ci	 *	VY	+3.3V
738c2ecf20Sopenharmony_ci	 *	12IN	GND		VPP is not connected
748c2ecf20Sopenharmony_ci	 *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
758c2ecf20Sopenharmony_ci	 *
768c2ecf20Sopenharmony_ci	 */
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci again:
798c2ecf20Sopenharmony_ci	switch (skt->nr) {
808c2ecf20Sopenharmony_ci	case 0:
818c2ecf20Sopenharmony_ci	case 1:
828c2ecf20Sopenharmony_ci		break;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	default:
858c2ecf20Sopenharmony_ci		ret = -1;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (ret == 0)
898c2ecf20Sopenharmony_ci		ret = sa1111_pcmcia_configure_socket(skt, state);
908c2ecf20Sopenharmony_ci	if (ret == 0)
918c2ecf20Sopenharmony_ci		ret = max1600_configure(m, state->Vcc, state->Vpp);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#if 1
948c2ecf20Sopenharmony_ci	if (ret == 0 && state->Vcc == 33) {
958c2ecf20Sopenharmony_ci		struct pcmcia_state new_state;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci		/*
988c2ecf20Sopenharmony_ci		 * HACK ALERT:
998c2ecf20Sopenharmony_ci		 * We can't sense the voltage properly on Lubbock before
1008c2ecf20Sopenharmony_ci		 * actually applying some power to the socket (catch 22).
1018c2ecf20Sopenharmony_ci		 * Resense the socket Voltage Sense pins after applying
1028c2ecf20Sopenharmony_ci		 * socket power.
1038c2ecf20Sopenharmony_ci		 *
1048c2ecf20Sopenharmony_ci		 * Note: It takes about 2.5ms for the MAX1602 VCC output
1058c2ecf20Sopenharmony_ci		 * to rise.
1068c2ecf20Sopenharmony_ci		 */
1078c2ecf20Sopenharmony_ci		mdelay(3);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		sa1111_pcmcia_socket_state(skt, &new_state);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		if (!new_state.vs_3v && !new_state.vs_Xv) {
1128c2ecf20Sopenharmony_ci			/*
1138c2ecf20Sopenharmony_ci			 * Switch to 5V,  Configure socket with 5V voltage
1148c2ecf20Sopenharmony_ci			 */
1158c2ecf20Sopenharmony_ci			max1600_configure(m, 0, 0);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci			/*
1188c2ecf20Sopenharmony_ci			 * It takes about 100ms to turn off Vcc.
1198c2ecf20Sopenharmony_ci			 */
1208c2ecf20Sopenharmony_ci			mdelay(100);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci			/*
1238c2ecf20Sopenharmony_ci			 * We need to hack around the const qualifier as
1248c2ecf20Sopenharmony_ci			 * well to keep this ugly workaround localized and
1258c2ecf20Sopenharmony_ci			 * not force it to the rest of the code. Barf bags
1268c2ecf20Sopenharmony_ci			 * available in the seat pocket in front of you!
1278c2ecf20Sopenharmony_ci			 */
1288c2ecf20Sopenharmony_ci			((socket_state_t *)state)->Vcc = 50;
1298c2ecf20Sopenharmony_ci			((socket_state_t *)state)->Vpp = 50;
1308c2ecf20Sopenharmony_ci			goto again;
1318c2ecf20Sopenharmony_ci		}
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci#endif
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return ret;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic struct pcmcia_low_level lubbock_pcmcia_ops = {
1398c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
1408c2ecf20Sopenharmony_ci	.hw_init		= lubbock_pcmcia_hw_init,
1418c2ecf20Sopenharmony_ci	.configure_socket	= lubbock_pcmcia_configure_socket,
1428c2ecf20Sopenharmony_ci	.first			= 0,
1438c2ecf20Sopenharmony_ci	.nr			= 2,
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#include "pxa2xx_base.h"
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ciint pcmcia_lubbock_init(struct sa1111_dev *sadev)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops);
1518c2ecf20Sopenharmony_ci	pxa2xx_configure_sockets(&sadev->dev, &lubbock_pcmcia_ops);
1528c2ecf20Sopenharmony_ci	return sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops,
1538c2ecf20Sopenharmony_ci				 pxa2xx_drv_pcmcia_add_one);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
157