summaryrefslogtreecommitdiff
path: root/drivers/pcmcia/l1110.c
blob: 67507019d3db60ad591af67ee3fdb938605c8ec5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <linux/io.h>
#include <linux/module.h>

#include "l1110.h"
#include "soc_common.h"

enum {
	PRS_S1 = BIT(0),
	PRS_S2 = BIT(1),
	PRS_S3 = BIT(2),
	PRS_S4 = BIT(3),
	PRS_BVD1 = BIT(4),
	PRS_BVD2 = BIT(5),
	PRS_VS1 = BIT(6),
	PRS_VS2 = BIT(7),
	PRS_RDY = BIT(8),
	PRS_CD1 = BIT(9),
	PRS_CD2 = BIT(10),

	PRC_S1 = PRS_S1,	/* x1vcc - TPS2205 D2/D7 */
	PRC_S2 = PRS_S2,	/* x0vcc - TPS2205 D3/D6 */
	PRC_S3 = PRS_S3,	/* x0vpp - TPS2205 D1/D5 */
	PRC_S4 = PRS_S4,	/* x1vpp - TPS2205 D0/D4 */
	PRC_RST = BIT(4),
	PRC_APOE = BIT(5), /* auto power off enable */
	PRC_CFE = BIT(6), /* CF enable: A25:11 driven high */
	PRC_SOE = BIT(7), /* signal output enable */
	PRC_SSP = BIT(8), /* socket select polarity */
};

struct l1110 {
	void __iomem *reg;
	u16 prc;
};

int l1110_init(struct device *dev, struct l1110 **ptr, resource_size_t base,
	unsigned int ssp)
{
	struct l1110 *l;

	l = devm_kzalloc(dev, sizeof(*l), GFP_KERNEL);
	if (!l)
		return -ENOMEM;

	l->prc = PRC_APOE | (ssp ? PRC_SSP : 0);
	l->reg = devm_ioremap(dev, base, 2);
	if (!l->reg)
		return -ENOMEM;

	*ptr = l;

	writew_relaxed(l->prc, l->reg);

	return 0;
}
EXPORT_SYMBOL_GPL(l1110_init);

void l1110_socket_state(struct l1110 *l, struct pcmcia_state *state)
{
	u16 prs = readw_relaxed(l->reg);

	state->bvd1 = !!(prs & PRS_BVD1);
	state->bvd2 = !!(prs & PRS_BVD2);
	state->vs_3v = !(prs & PRS_VS1);
	state->vs_Xv = !(prs & PRS_VS2);
}
EXPORT_SYMBOL_GPL(l1110_socket_state);

int l1110_configure_socket(struct l1110 *l, const socket_state_t *state)
{
	u16 prc = l->prc;

	switch (state->Vcc) {
	case 0:
		break;
	case 33:
		prc |= PRC_S1;
		break;
	case 50:
		prc |= PRC_S2;
		break;
	default:
		return -EINVAL;
	}

	if (state->Vpp) {
		if (state->Vpp == 12)
			prc |= PRC_S4;
		else if (state->Vpp == state->Vcc)
			prc |= PRC_S3;
		else
			return -EINVAL;
	}

	if (state->flags & SS_RESET)
		prc |= PRC_RST;

	if (state->flags & SS_OUTPUT_ENA)
		prc |= PRC_SOE;

	writew_relaxed(prc, l->reg);

	return 0;
}
EXPORT_SYMBOL_GPL(l1110_configure_socket);

MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>");
MODULE_DESCRIPTION("LinkUp Systems L1110 driver");
MODULE_LICENSE("GPL");