xref: /OK3568_Linux_fs/kernel/drivers/net/phy/spi_ks8995.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2008 Gabor Juhos <juhosg at openwrt.org>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This file was based on: drivers/spi/at25.c
8*4882a593Smuzhiyun  *     Copyright (C) 2006 David Brownell
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/types.h>
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/module.h>
16*4882a593Smuzhiyun #include <linux/delay.h>
17*4882a593Smuzhiyun #include <linux/device.h>
18*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
19*4882a593Smuzhiyun #include <linux/of.h>
20*4882a593Smuzhiyun #include <linux/of_gpio.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <linux/spi/spi.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define DRV_VERSION		"0.1.1"
25*4882a593Smuzhiyun #define DRV_DESC		"Micrel KS8995 Ethernet switch SPI driver"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define KS8995_REG_ID0		0x00    /* Chip ID0 */
30*4882a593Smuzhiyun #define KS8995_REG_ID1		0x01    /* Chip ID1 */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define KS8995_REG_GC0		0x02    /* Global Control 0 */
33*4882a593Smuzhiyun #define KS8995_REG_GC1		0x03    /* Global Control 1 */
34*4882a593Smuzhiyun #define KS8995_REG_GC2		0x04    /* Global Control 2 */
35*4882a593Smuzhiyun #define KS8995_REG_GC3		0x05    /* Global Control 3 */
36*4882a593Smuzhiyun #define KS8995_REG_GC4		0x06    /* Global Control 4 */
37*4882a593Smuzhiyun #define KS8995_REG_GC5		0x07    /* Global Control 5 */
38*4882a593Smuzhiyun #define KS8995_REG_GC6		0x08    /* Global Control 6 */
39*4882a593Smuzhiyun #define KS8995_REG_GC7		0x09    /* Global Control 7 */
40*4882a593Smuzhiyun #define KS8995_REG_GC8		0x0a    /* Global Control 8 */
41*4882a593Smuzhiyun #define KS8995_REG_GC9		0x0b    /* Global Control 9 */
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define KS8995_REG_PC(p, r)	((0x10 * p) + r)	 /* Port Control */
44*4882a593Smuzhiyun #define KS8995_REG_PS(p, r)	((0x10 * p) + r + 0xe)  /* Port Status */
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define KS8995_REG_TPC0		0x60    /* TOS Priority Control 0 */
47*4882a593Smuzhiyun #define KS8995_REG_TPC1		0x61    /* TOS Priority Control 1 */
48*4882a593Smuzhiyun #define KS8995_REG_TPC2		0x62    /* TOS Priority Control 2 */
49*4882a593Smuzhiyun #define KS8995_REG_TPC3		0x63    /* TOS Priority Control 3 */
50*4882a593Smuzhiyun #define KS8995_REG_TPC4		0x64    /* TOS Priority Control 4 */
51*4882a593Smuzhiyun #define KS8995_REG_TPC5		0x65    /* TOS Priority Control 5 */
52*4882a593Smuzhiyun #define KS8995_REG_TPC6		0x66    /* TOS Priority Control 6 */
53*4882a593Smuzhiyun #define KS8995_REG_TPC7		0x67    /* TOS Priority Control 7 */
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define KS8995_REG_MAC0		0x68    /* MAC address 0 */
56*4882a593Smuzhiyun #define KS8995_REG_MAC1		0x69    /* MAC address 1 */
57*4882a593Smuzhiyun #define KS8995_REG_MAC2		0x6a    /* MAC address 2 */
58*4882a593Smuzhiyun #define KS8995_REG_MAC3		0x6b    /* MAC address 3 */
59*4882a593Smuzhiyun #define KS8995_REG_MAC4		0x6c    /* MAC address 4 */
60*4882a593Smuzhiyun #define KS8995_REG_MAC5		0x6d    /* MAC address 5 */
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #define KS8995_REG_IAC0		0x6e    /* Indirect Access Control 0 */
63*4882a593Smuzhiyun #define KS8995_REG_IAC1		0x6f    /* Indirect Access Control 0 */
64*4882a593Smuzhiyun #define KS8995_REG_IAD7		0x70    /* Indirect Access Data 7 */
65*4882a593Smuzhiyun #define KS8995_REG_IAD6		0x71    /* Indirect Access Data 6 */
66*4882a593Smuzhiyun #define KS8995_REG_IAD5		0x72    /* Indirect Access Data 5 */
67*4882a593Smuzhiyun #define KS8995_REG_IAD4		0x73    /* Indirect Access Data 4 */
68*4882a593Smuzhiyun #define KS8995_REG_IAD3		0x74    /* Indirect Access Data 3 */
69*4882a593Smuzhiyun #define KS8995_REG_IAD2		0x75    /* Indirect Access Data 2 */
70*4882a593Smuzhiyun #define KS8995_REG_IAD1		0x76    /* Indirect Access Data 1 */
71*4882a593Smuzhiyun #define KS8995_REG_IAD0		0x77    /* Indirect Access Data 0 */
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define KSZ8864_REG_ID1		0xfe	/* Chip ID in bit 7 */
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #define KS8995_REGS_SIZE	0x80
76*4882a593Smuzhiyun #define KSZ8864_REGS_SIZE	0x100
77*4882a593Smuzhiyun #define KSZ8795_REGS_SIZE	0x100
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define ID1_CHIPID_M		0xf
80*4882a593Smuzhiyun #define ID1_CHIPID_S		4
81*4882a593Smuzhiyun #define ID1_REVISION_M		0x7
82*4882a593Smuzhiyun #define ID1_REVISION_S		1
83*4882a593Smuzhiyun #define ID1_START_SW		1	/* start the switch */
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #define FAMILY_KS8995		0x95
86*4882a593Smuzhiyun #define FAMILY_KSZ8795		0x87
87*4882a593Smuzhiyun #define CHIPID_M		0
88*4882a593Smuzhiyun #define KS8995_CHIP_ID		0x00
89*4882a593Smuzhiyun #define KSZ8864_CHIP_ID		0x01
90*4882a593Smuzhiyun #define KSZ8795_CHIP_ID		0x09
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun #define KS8995_CMD_WRITE	0x02U
93*4882a593Smuzhiyun #define KS8995_CMD_READ		0x03U
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun #define KS8995_RESET_DELAY	10 /* usec */
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun enum ks8995_chip_variant {
98*4882a593Smuzhiyun 	ks8995,
99*4882a593Smuzhiyun 	ksz8864,
100*4882a593Smuzhiyun 	ksz8795,
101*4882a593Smuzhiyun 	max_variant
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun struct ks8995_chip_params {
105*4882a593Smuzhiyun 	char *name;
106*4882a593Smuzhiyun 	int family_id;
107*4882a593Smuzhiyun 	int chip_id;
108*4882a593Smuzhiyun 	int regs_size;
109*4882a593Smuzhiyun 	int addr_width;
110*4882a593Smuzhiyun 	int addr_shift;
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun static const struct ks8995_chip_params ks8995_chip[] = {
114*4882a593Smuzhiyun 	[ks8995] = {
115*4882a593Smuzhiyun 		.name = "KS8995MA",
116*4882a593Smuzhiyun 		.family_id = FAMILY_KS8995,
117*4882a593Smuzhiyun 		.chip_id = KS8995_CHIP_ID,
118*4882a593Smuzhiyun 		.regs_size = KS8995_REGS_SIZE,
119*4882a593Smuzhiyun 		.addr_width = 8,
120*4882a593Smuzhiyun 		.addr_shift = 0,
121*4882a593Smuzhiyun 	},
122*4882a593Smuzhiyun 	[ksz8864] = {
123*4882a593Smuzhiyun 		.name = "KSZ8864RMN",
124*4882a593Smuzhiyun 		.family_id = FAMILY_KS8995,
125*4882a593Smuzhiyun 		.chip_id = KSZ8864_CHIP_ID,
126*4882a593Smuzhiyun 		.regs_size = KSZ8864_REGS_SIZE,
127*4882a593Smuzhiyun 		.addr_width = 8,
128*4882a593Smuzhiyun 		.addr_shift = 0,
129*4882a593Smuzhiyun 	},
130*4882a593Smuzhiyun 	[ksz8795] = {
131*4882a593Smuzhiyun 		.name = "KSZ8795CLX",
132*4882a593Smuzhiyun 		.family_id = FAMILY_KSZ8795,
133*4882a593Smuzhiyun 		.chip_id = KSZ8795_CHIP_ID,
134*4882a593Smuzhiyun 		.regs_size = KSZ8795_REGS_SIZE,
135*4882a593Smuzhiyun 		.addr_width = 12,
136*4882a593Smuzhiyun 		.addr_shift = 1,
137*4882a593Smuzhiyun 	},
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun struct ks8995_pdata {
141*4882a593Smuzhiyun 	int reset_gpio;
142*4882a593Smuzhiyun 	enum of_gpio_flags reset_gpio_flags;
143*4882a593Smuzhiyun };
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun struct ks8995_switch {
146*4882a593Smuzhiyun 	struct spi_device	*spi;
147*4882a593Smuzhiyun 	struct mutex		lock;
148*4882a593Smuzhiyun 	struct ks8995_pdata	*pdata;
149*4882a593Smuzhiyun 	struct bin_attribute	regs_attr;
150*4882a593Smuzhiyun 	const struct ks8995_chip_params	*chip;
151*4882a593Smuzhiyun 	int			revision_id;
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun static const struct spi_device_id ks8995_id[] = {
155*4882a593Smuzhiyun 	{"ks8995", ks8995},
156*4882a593Smuzhiyun 	{"ksz8864", ksz8864},
157*4882a593Smuzhiyun 	{"ksz8795", ksz8795},
158*4882a593Smuzhiyun 	{ }
159*4882a593Smuzhiyun };
160*4882a593Smuzhiyun MODULE_DEVICE_TABLE(spi, ks8995_id);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun static const struct of_device_id ks8895_spi_of_match[] = {
163*4882a593Smuzhiyun         { .compatible = "micrel,ks8995" },
164*4882a593Smuzhiyun         { .compatible = "micrel,ksz8864" },
165*4882a593Smuzhiyun         { .compatible = "micrel,ksz8795" },
166*4882a593Smuzhiyun         { },
167*4882a593Smuzhiyun  };
168*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, ks8895_spi_of_match);
169*4882a593Smuzhiyun 
get_chip_id(u8 val)170*4882a593Smuzhiyun static inline u8 get_chip_id(u8 val)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	return (val >> ID1_CHIPID_S) & ID1_CHIPID_M;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
get_chip_rev(u8 val)175*4882a593Smuzhiyun static inline u8 get_chip_rev(u8 val)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	return (val >> ID1_REVISION_S) & ID1_REVISION_M;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun /* create_spi_cmd - create a chip specific SPI command header
181*4882a593Smuzhiyun  * @ks: pointer to switch instance
182*4882a593Smuzhiyun  * @cmd: SPI command for switch
183*4882a593Smuzhiyun  * @address: register address for command
184*4882a593Smuzhiyun  *
185*4882a593Smuzhiyun  * Different chip families use different bit pattern to address the switches
186*4882a593Smuzhiyun  * registers:
187*4882a593Smuzhiyun  *
188*4882a593Smuzhiyun  * KS8995: 8bit command + 8bit address
189*4882a593Smuzhiyun  * KSZ8795: 3bit command + 12bit address + 1bit TR (?)
190*4882a593Smuzhiyun  */
create_spi_cmd(struct ks8995_switch * ks,int cmd,unsigned address)191*4882a593Smuzhiyun static inline __be16 create_spi_cmd(struct ks8995_switch *ks, int cmd,
192*4882a593Smuzhiyun 				    unsigned address)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	u16 result = cmd;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/* make room for address (incl. address shift) */
197*4882a593Smuzhiyun 	result <<= ks->chip->addr_width + ks->chip->addr_shift;
198*4882a593Smuzhiyun 	/* add address */
199*4882a593Smuzhiyun 	result |= address << ks->chip->addr_shift;
200*4882a593Smuzhiyun 	/* SPI protocol needs big endian */
201*4882a593Smuzhiyun 	return cpu_to_be16(result);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
ks8995_read(struct ks8995_switch * ks,char * buf,unsigned offset,size_t count)204*4882a593Smuzhiyun static int ks8995_read(struct ks8995_switch *ks, char *buf,
205*4882a593Smuzhiyun 		 unsigned offset, size_t count)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	__be16 cmd;
208*4882a593Smuzhiyun 	struct spi_transfer t[2];
209*4882a593Smuzhiyun 	struct spi_message m;
210*4882a593Smuzhiyun 	int err;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	cmd = create_spi_cmd(ks, KS8995_CMD_READ, offset);
213*4882a593Smuzhiyun 	spi_message_init(&m);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	memset(&t, 0, sizeof(t));
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	t[0].tx_buf = &cmd;
218*4882a593Smuzhiyun 	t[0].len = sizeof(cmd);
219*4882a593Smuzhiyun 	spi_message_add_tail(&t[0], &m);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	t[1].rx_buf = buf;
222*4882a593Smuzhiyun 	t[1].len = count;
223*4882a593Smuzhiyun 	spi_message_add_tail(&t[1], &m);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	mutex_lock(&ks->lock);
226*4882a593Smuzhiyun 	err = spi_sync(ks->spi, &m);
227*4882a593Smuzhiyun 	mutex_unlock(&ks->lock);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	return err ? err : count;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
ks8995_write(struct ks8995_switch * ks,char * buf,unsigned offset,size_t count)232*4882a593Smuzhiyun static int ks8995_write(struct ks8995_switch *ks, char *buf,
233*4882a593Smuzhiyun 		 unsigned offset, size_t count)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	__be16 cmd;
236*4882a593Smuzhiyun 	struct spi_transfer t[2];
237*4882a593Smuzhiyun 	struct spi_message m;
238*4882a593Smuzhiyun 	int err;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	cmd = create_spi_cmd(ks, KS8995_CMD_WRITE, offset);
241*4882a593Smuzhiyun 	spi_message_init(&m);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	memset(&t, 0, sizeof(t));
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	t[0].tx_buf = &cmd;
246*4882a593Smuzhiyun 	t[0].len = sizeof(cmd);
247*4882a593Smuzhiyun 	spi_message_add_tail(&t[0], &m);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	t[1].tx_buf = buf;
250*4882a593Smuzhiyun 	t[1].len = count;
251*4882a593Smuzhiyun 	spi_message_add_tail(&t[1], &m);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	mutex_lock(&ks->lock);
254*4882a593Smuzhiyun 	err = spi_sync(ks->spi, &m);
255*4882a593Smuzhiyun 	mutex_unlock(&ks->lock);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	return err ? err : count;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
ks8995_read_reg(struct ks8995_switch * ks,u8 addr,u8 * buf)260*4882a593Smuzhiyun static inline int ks8995_read_reg(struct ks8995_switch *ks, u8 addr, u8 *buf)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	return ks8995_read(ks, buf, addr, 1) != 1;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun 
ks8995_write_reg(struct ks8995_switch * ks,u8 addr,u8 val)265*4882a593Smuzhiyun static inline int ks8995_write_reg(struct ks8995_switch *ks, u8 addr, u8 val)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	char buf = val;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	return ks8995_write(ks, &buf, addr, 1) != 1;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
273*4882a593Smuzhiyun 
ks8995_stop(struct ks8995_switch * ks)274*4882a593Smuzhiyun static int ks8995_stop(struct ks8995_switch *ks)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	return ks8995_write_reg(ks, KS8995_REG_ID1, 0);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
ks8995_start(struct ks8995_switch * ks)279*4882a593Smuzhiyun static int ks8995_start(struct ks8995_switch *ks)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	return ks8995_write_reg(ks, KS8995_REG_ID1, 1);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun 
ks8995_reset(struct ks8995_switch * ks)284*4882a593Smuzhiyun static int ks8995_reset(struct ks8995_switch *ks)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	int err;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	err = ks8995_stop(ks);
289*4882a593Smuzhiyun 	if (err)
290*4882a593Smuzhiyun 		return err;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	udelay(KS8995_RESET_DELAY);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	return ks8995_start(ks);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
ks8995_registers_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)297*4882a593Smuzhiyun static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj,
298*4882a593Smuzhiyun 	struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	struct device *dev;
301*4882a593Smuzhiyun 	struct ks8995_switch *ks8995;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	dev = kobj_to_dev(kobj);
304*4882a593Smuzhiyun 	ks8995 = dev_get_drvdata(dev);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	return ks8995_read(ks8995, buf, off, count);
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
ks8995_registers_write(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)309*4882a593Smuzhiyun static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj,
310*4882a593Smuzhiyun 	struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun 	struct device *dev;
313*4882a593Smuzhiyun 	struct ks8995_switch *ks8995;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	dev = kobj_to_dev(kobj);
316*4882a593Smuzhiyun 	ks8995 = dev_get_drvdata(dev);
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	return ks8995_write(ks8995, buf, off, count);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun /* ks8995_get_revision - get chip revision
322*4882a593Smuzhiyun  * @ks: pointer to switch instance
323*4882a593Smuzhiyun  *
324*4882a593Smuzhiyun  * Verify chip family and id and get chip revision.
325*4882a593Smuzhiyun  */
ks8995_get_revision(struct ks8995_switch * ks)326*4882a593Smuzhiyun static int ks8995_get_revision(struct ks8995_switch *ks)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun 	int err;
329*4882a593Smuzhiyun 	u8 id0, id1, ksz8864_id;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	/* read family id */
332*4882a593Smuzhiyun 	err = ks8995_read_reg(ks, KS8995_REG_ID0, &id0);
333*4882a593Smuzhiyun 	if (err) {
334*4882a593Smuzhiyun 		err = -EIO;
335*4882a593Smuzhiyun 		goto err_out;
336*4882a593Smuzhiyun 	}
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	/* verify family id */
339*4882a593Smuzhiyun 	if (id0 != ks->chip->family_id) {
340*4882a593Smuzhiyun 		dev_err(&ks->spi->dev, "chip family id mismatch: expected 0x%02x but 0x%02x read\n",
341*4882a593Smuzhiyun 			ks->chip->family_id, id0);
342*4882a593Smuzhiyun 		err = -ENODEV;
343*4882a593Smuzhiyun 		goto err_out;
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	switch (ks->chip->family_id) {
347*4882a593Smuzhiyun 	case FAMILY_KS8995:
348*4882a593Smuzhiyun 		/* try reading chip id at CHIP ID1 */
349*4882a593Smuzhiyun 		err = ks8995_read_reg(ks, KS8995_REG_ID1, &id1);
350*4882a593Smuzhiyun 		if (err) {
351*4882a593Smuzhiyun 			err = -EIO;
352*4882a593Smuzhiyun 			goto err_out;
353*4882a593Smuzhiyun 		}
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 		/* verify chip id */
356*4882a593Smuzhiyun 		if ((get_chip_id(id1) == CHIPID_M) &&
357*4882a593Smuzhiyun 		    (get_chip_id(id1) == ks->chip->chip_id)) {
358*4882a593Smuzhiyun 			/* KS8995MA */
359*4882a593Smuzhiyun 			ks->revision_id = get_chip_rev(id1);
360*4882a593Smuzhiyun 		} else if (get_chip_id(id1) != CHIPID_M) {
361*4882a593Smuzhiyun 			/* KSZ8864RMN */
362*4882a593Smuzhiyun 			err = ks8995_read_reg(ks, KS8995_REG_ID1, &ksz8864_id);
363*4882a593Smuzhiyun 			if (err) {
364*4882a593Smuzhiyun 				err = -EIO;
365*4882a593Smuzhiyun 				goto err_out;
366*4882a593Smuzhiyun 			}
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 			if ((ksz8864_id & 0x80) &&
369*4882a593Smuzhiyun 			    (ks->chip->chip_id == KSZ8864_CHIP_ID)) {
370*4882a593Smuzhiyun 				ks->revision_id = get_chip_rev(id1);
371*4882a593Smuzhiyun 			}
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 		} else {
374*4882a593Smuzhiyun 			dev_err(&ks->spi->dev, "unsupported chip id for KS8995 family: 0x%02x\n",
375*4882a593Smuzhiyun 				id1);
376*4882a593Smuzhiyun 			err = -ENODEV;
377*4882a593Smuzhiyun 		}
378*4882a593Smuzhiyun 		break;
379*4882a593Smuzhiyun 	case FAMILY_KSZ8795:
380*4882a593Smuzhiyun 		/* try reading chip id at CHIP ID1 */
381*4882a593Smuzhiyun 		err = ks8995_read_reg(ks, KS8995_REG_ID1, &id1);
382*4882a593Smuzhiyun 		if (err) {
383*4882a593Smuzhiyun 			err = -EIO;
384*4882a593Smuzhiyun 			goto err_out;
385*4882a593Smuzhiyun 		}
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 		if (get_chip_id(id1) == ks->chip->chip_id) {
388*4882a593Smuzhiyun 			ks->revision_id = get_chip_rev(id1);
389*4882a593Smuzhiyun 		} else {
390*4882a593Smuzhiyun 			dev_err(&ks->spi->dev, "unsupported chip id for KSZ8795 family: 0x%02x\n",
391*4882a593Smuzhiyun 				id1);
392*4882a593Smuzhiyun 			err = -ENODEV;
393*4882a593Smuzhiyun 		}
394*4882a593Smuzhiyun 		break;
395*4882a593Smuzhiyun 	default:
396*4882a593Smuzhiyun 		dev_err(&ks->spi->dev, "unsupported family id: 0x%02x\n", id0);
397*4882a593Smuzhiyun 		err = -ENODEV;
398*4882a593Smuzhiyun 		break;
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun err_out:
401*4882a593Smuzhiyun 	return err;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun /* ks8995_parse_dt - setup platform data from devicetree
405*4882a593Smuzhiyun  * @ks: pointer to switch instance
406*4882a593Smuzhiyun  *
407*4882a593Smuzhiyun  * Parses supported DT properties and sets up platform data
408*4882a593Smuzhiyun  * accordingly.
409*4882a593Smuzhiyun  */
ks8995_parse_dt(struct ks8995_switch * ks)410*4882a593Smuzhiyun static void ks8995_parse_dt(struct ks8995_switch *ks)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun 	struct device_node *np = ks->spi->dev.of_node;
413*4882a593Smuzhiyun 	struct ks8995_pdata *pdata = ks->pdata;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (!np)
416*4882a593Smuzhiyun 		return;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios", 0,
419*4882a593Smuzhiyun 		&pdata->reset_gpio_flags);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun static const struct bin_attribute ks8995_registers_attr = {
423*4882a593Smuzhiyun 	.attr = {
424*4882a593Smuzhiyun 		.name   = "registers",
425*4882a593Smuzhiyun 		.mode   = 0600,
426*4882a593Smuzhiyun 	},
427*4882a593Smuzhiyun 	.size   = KS8995_REGS_SIZE,
428*4882a593Smuzhiyun 	.read   = ks8995_registers_read,
429*4882a593Smuzhiyun 	.write  = ks8995_registers_write,
430*4882a593Smuzhiyun };
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
ks8995_probe(struct spi_device * spi)433*4882a593Smuzhiyun static int ks8995_probe(struct spi_device *spi)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	struct ks8995_switch *ks;
436*4882a593Smuzhiyun 	int err;
437*4882a593Smuzhiyun 	int variant = spi_get_device_id(spi)->driver_data;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	if (variant >= max_variant) {
440*4882a593Smuzhiyun 		dev_err(&spi->dev, "bad chip variant %d\n", variant);
441*4882a593Smuzhiyun 		return -ENODEV;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	ks = devm_kzalloc(&spi->dev, sizeof(*ks), GFP_KERNEL);
445*4882a593Smuzhiyun 	if (!ks)
446*4882a593Smuzhiyun 		return -ENOMEM;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	mutex_init(&ks->lock);
449*4882a593Smuzhiyun 	ks->spi = spi;
450*4882a593Smuzhiyun 	ks->chip = &ks8995_chip[variant];
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	if (ks->spi->dev.of_node) {
453*4882a593Smuzhiyun 		ks->pdata = devm_kzalloc(&spi->dev, sizeof(*ks->pdata),
454*4882a593Smuzhiyun 					 GFP_KERNEL);
455*4882a593Smuzhiyun 		if (!ks->pdata)
456*4882a593Smuzhiyun 			return -ENOMEM;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 		ks->pdata->reset_gpio = -1;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 		ks8995_parse_dt(ks);
461*4882a593Smuzhiyun 	}
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	if (!ks->pdata)
464*4882a593Smuzhiyun 		ks->pdata = spi->dev.platform_data;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	/* de-assert switch reset */
467*4882a593Smuzhiyun 	if (ks->pdata && gpio_is_valid(ks->pdata->reset_gpio)) {
468*4882a593Smuzhiyun 		unsigned long flags;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 		flags = (ks->pdata->reset_gpio_flags == OF_GPIO_ACTIVE_LOW ?
471*4882a593Smuzhiyun 			 GPIOF_ACTIVE_LOW : 0);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 		err = devm_gpio_request_one(&spi->dev,
474*4882a593Smuzhiyun 					    ks->pdata->reset_gpio,
475*4882a593Smuzhiyun 					    flags, "switch-reset");
476*4882a593Smuzhiyun 		if (err) {
477*4882a593Smuzhiyun 			dev_err(&spi->dev,
478*4882a593Smuzhiyun 				"failed to get reset-gpios: %d\n", err);
479*4882a593Smuzhiyun 			return -EIO;
480*4882a593Smuzhiyun 		}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 		gpiod_set_value(gpio_to_desc(ks->pdata->reset_gpio), 0);
483*4882a593Smuzhiyun 	}
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	spi_set_drvdata(spi, ks);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	spi->mode = SPI_MODE_0;
488*4882a593Smuzhiyun 	spi->bits_per_word = 8;
489*4882a593Smuzhiyun 	err = spi_setup(spi);
490*4882a593Smuzhiyun 	if (err) {
491*4882a593Smuzhiyun 		dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
492*4882a593Smuzhiyun 		return err;
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	err = ks8995_get_revision(ks);
496*4882a593Smuzhiyun 	if (err)
497*4882a593Smuzhiyun 		return err;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	memcpy(&ks->regs_attr, &ks8995_registers_attr, sizeof(ks->regs_attr));
500*4882a593Smuzhiyun 	ks->regs_attr.size = ks->chip->regs_size;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	err = ks8995_reset(ks);
503*4882a593Smuzhiyun 	if (err)
504*4882a593Smuzhiyun 		return err;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	sysfs_attr_init(&ks->regs_attr.attr);
507*4882a593Smuzhiyun 	err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr);
508*4882a593Smuzhiyun 	if (err) {
509*4882a593Smuzhiyun 		dev_err(&spi->dev, "unable to create sysfs file, err=%d\n",
510*4882a593Smuzhiyun 				    err);
511*4882a593Smuzhiyun 		return err;
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n",
515*4882a593Smuzhiyun 		 ks->chip->name, ks->chip->chip_id, ks->revision_id);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	return 0;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun 
ks8995_remove(struct spi_device * spi)520*4882a593Smuzhiyun static int ks8995_remove(struct spi_device *spi)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	struct ks8995_switch *ks = spi_get_drvdata(spi);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	sysfs_remove_bin_file(&spi->dev.kobj, &ks->regs_attr);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	/* assert reset */
527*4882a593Smuzhiyun 	if (ks->pdata && gpio_is_valid(ks->pdata->reset_gpio))
528*4882a593Smuzhiyun 		gpiod_set_value(gpio_to_desc(ks->pdata->reset_gpio), 1);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	return 0;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun /* ------------------------------------------------------------------------ */
534*4882a593Smuzhiyun static struct spi_driver ks8995_driver = {
535*4882a593Smuzhiyun 	.driver = {
536*4882a593Smuzhiyun 		.name	    = "spi-ks8995",
537*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(ks8895_spi_of_match),
538*4882a593Smuzhiyun 	},
539*4882a593Smuzhiyun 	.probe	  = ks8995_probe,
540*4882a593Smuzhiyun 	.remove	  = ks8995_remove,
541*4882a593Smuzhiyun 	.id_table = ks8995_id,
542*4882a593Smuzhiyun };
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun module_spi_driver(ks8995_driver);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun MODULE_DESCRIPTION(DRV_DESC);
547*4882a593Smuzhiyun MODULE_VERSION(DRV_VERSION);
548*4882a593Smuzhiyun MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
549*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
550