aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/txx9/generic/smsc_fdc37m81x.c
blob: 40f4098d3ae1886651b557a69a52655008f60ff2 (plain) (blame)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
 * Interface for smsc fdc48m81x Super IO chip
 *
 * Author: MontaVista Software, Inc. source@mvista.com
 *
 * 2001-2003 (c) MontaVista Software, Inc. This file is licensed under
 * the terms of the GNU General Public License version 2. This program
 * is licensed "as is" without any warranty of any kind, whether express
 * or implied.
 *
 * Copyright 2004 (c) MontaVista Software, Inc.
 */
#include <linux/init.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/txx9/smsc_fdc37m81x.h>

/* Common Registers */
#define SMSC_FDC37M81X_CONFIG_INDEX  0x00
#define SMSC_FDC37M81X_CONFIG_DATA   0x01
#define SMSC_FDC37M81X_CONF	     0x02
#define SMSC_FDC37M81X_INDEX	     0x03
#define SMSC_FDC37M81X_DNUM	     0x07
#define SMSC_FDC37M81X_DID	     0x20
#define SMSC_FDC37M81X_DREV	     0x21
#define SMSC_FDC37M81X_PCNT	     0x22
#define SMSC_FDC37M81X_PMGT	     0x23
#define SMSC_FDC37M81X_OSC	     0x24
#define SMSC_FDC37M81X_CONFPA0	     0x26
#define SMSC_FDC37M81X_CONFPA1	     0x27
#define SMSC_FDC37M81X_TEST4	     0x2B
#define SMSC_FDC37M81X_TEST5	     0x2C
#define SMSC_FDC37M81X_TEST1	     0x2D
#define SMSC_FDC37M81X_TEST2	     0x2E
#define SMSC_FDC37M81X_TEST3	     0x2F

/* Logical device numbers */
#define SMSC_FDC37M81X_FDD	     0x00
#define SMSC_FDC37M81X_SERIAL1	     0x04
#define SMSC_FDC37M81X_SERIAL2	     0x05
#define SMSC_FDC37M81X_KBD	     0x07

/* Logical device Config Registers */
#define SMSC_FDC37M81X_ACTIVE	     0x30
#define SMSC_FDC37M81X_BASEADDR0     0x60
#define SMSC_FDC37M81X_BASEADDR1     0x61
#define SMSC_FDC37M81X_INT	     0x70
#define SMSC_FDC37M81X_INT2	     0x72
#define SMSC_FDC37M81X_MODE	     0xF0

/* Chip Config Values */
#define SMSC_FDC37M81X_CONFIG_ENTER  0x55
#define SMSC_FDC37M81X_CONFIG_EXIT   0xaa
#define SMSC_FDC37M81X_CHIP_ID	     0x4d

static unsigned long g_smsc_fdc37m81x_base;

static inline unsigned char smsc_fdc37m81x_rd(unsigned char index)
{
	outb(index, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);

	return inb(g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_DATA);
}

static inline void smsc_dc37m81x_wr(unsigned char index, unsigned char data)
{
	outb(index, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
	outb(data, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_DATA);
}

void smsc_fdc37m81x_config_beg(void)
{
	if (g_smsc_fdc37m81x_base) {
		outb(SMSC_FDC37M81X_CONFIG_ENTER,
		     g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
	}
}

void smsc_fdc37m81x_config_end(void)
{
	if (g_smsc_fdc37m81x_base)
		outb(SMSC_FDC37M81X_CONFIG_EXIT,
		     g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
}

u8 smsc_fdc37m81x_config_get(u8 reg)
{
	u8 val = 0;

	if (g_smsc_fdc37m81x_base)
		val = smsc_fdc37m81x_rd(reg);

	return val;
}

void smsc_fdc37m81x_config_set(u8 reg, u8 val)
{
	if (g_smsc_fdc37m81x_base)
		smsc_dc37m81x_wr(reg, val);
}

unsigned long __init smsc_fdc37m81x_init(unsigned long port)
{
	const int field = sizeof(unsigned long) * 2;
	u8 chip_id;

	if (g_smsc_fdc37m81x_base)
		pr_warn("%s: stepping on old base=0x%0*lx\n", __func__, field,
			g_smsc_fdc37m81x_base);

	g_smsc_fdc37m81x_base = port;

	smsc_fdc37m81x_config_beg();

	chip_id = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DID);
	if (chip_id == SMSC_FDC37M81X_CHIP_ID)
		smsc_fdc37m81x_config_end();
	else {
		pr_warn("%s: unknown chip id 0x%02x\n", __func__, chip_id);
		g_smsc_fdc37m81x_base = 0;
	}

	return g_smsc_fdc37m81x_base;
}

#ifdef DEBUG
static void smsc_fdc37m81x_config_dump_one(const char *key, u8 dev, u8 reg)
{
	pr_info("%s: dev=0x%02x reg=0x%02x val=0x%02x\n", key, dev, reg,
		smsc_fdc37m81x_rd(reg));
}

void smsc_fdc37m81x_config_dump(void)
{
	u8 orig;
	const char *fname = __func__;

	smsc_fdc37m81x_config_beg();

	orig = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DNUM);

	pr_info("%s: common\n", fname);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
				       SMSC_FDC37M81X_DNUM);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
				       SMSC_FDC37M81X_DID);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
				       SMSC_FDC37M81X_DREV);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
				       SMSC_FDC37M81X_PCNT);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
				       SMSC_FDC37M81X_PMGT);

	pr_info("%s: keyboard\n", fname);
	smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, SMSC_FDC37M81X_KBD);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
				       SMSC_FDC37M81X_ACTIVE);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
				       SMSC_FDC37M81X_INT);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
				       SMSC_FDC37M81X_INT2);
	smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
				       SMSC_FDC37M81X_LDCR_F0);

	smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, orig);

	smsc_fdc37m81x_config_end();
}
#endif