Blame view

drivers/fsi/fsi-master-gpio.c 20.8 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
2
3
4
5
6
7
8
9
10
11
  /*
   * A FSI master controller, using a simple GPIO bit-banging interface
   */
  
  #include <linux/crc4.h>
  #include <linux/delay.h>
  #include <linux/device.h>
  #include <linux/fsi.h>
  #include <linux/gpio/consumer.h>
  #include <linux/io.h>
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
12
  #include <linux/irqflags.h>
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
13
  #include <linux/module.h>
f6a2f8eb7   Jeremy Kerr   fsi: Match fsi sl...
14
  #include <linux/of.h>
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
15
16
  #include <linux/platform_device.h>
  #include <linux/slab.h>
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
17
18
19
20
  
  #include "fsi-master.h"
  
  #define	FSI_GPIO_STD_DLY	1	/* Standard pin delay in nS */
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
21
  #define LAST_ADDR_INVALID		0x1
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
22
23
24
  struct fsi_master_gpio {
  	struct fsi_master	master;
  	struct device		*dev;
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
25
  	struct mutex		cmd_lock;	/* mutex for command ordering */
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
26
27
28
29
30
  	struct gpio_desc	*gpio_clk;
  	struct gpio_desc	*gpio_data;
  	struct gpio_desc	*gpio_trans;	/* Voltage translator */
  	struct gpio_desc	*gpio_enable;	/* FSI enable */
  	struct gpio_desc	*gpio_mux;	/* Mux control */
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
31
  	bool			external_mode;
bc1099d2b   Benjamin Herrenschmidt   fsi/fsi-master-gp...
32
  	bool			no_delays;
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
33
  	uint32_t		last_addr;
75854c148   Benjamin Herrenschmidt   fsi: master-gpio:...
34
35
  	uint8_t			t_send_delay;
  	uint8_t			t_echo_delay;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
36
  };
1247cf7ab   Jeremy Kerr   drivers/fsi/gpio:...
37
38
  #define CREATE_TRACE_POINTS
  #include <trace/events/fsi_master_gpio.h>
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
39
40
41
42
43
44
45
46
47
48
49
50
  #define to_fsi_master_gpio(m) container_of(m, struct fsi_master_gpio, master)
  
  struct fsi_gpio_msg {
  	uint64_t	msg;
  	uint8_t		bits;
  };
  
  static void clock_toggle(struct fsi_master_gpio *master, int count)
  {
  	int i;
  
  	for (i = 0; i < count; i++) {
bc1099d2b   Benjamin Herrenschmidt   fsi/fsi-master-gp...
51
52
  		if (!master->no_delays)
  			ndelay(FSI_GPIO_STD_DLY);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
53
  		gpiod_set_value(master->gpio_clk, 0);
bc1099d2b   Benjamin Herrenschmidt   fsi/fsi-master-gp...
54
55
  		if (!master->no_delays)
  			ndelay(FSI_GPIO_STD_DLY);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
56
57
58
  		gpiod_set_value(master->gpio_clk, 1);
  	}
  }
5d0d16f13   Benjamin Herrenschmidt   fsi/fsi-master-gp...
59
  static int sda_clock_in(struct fsi_master_gpio *master)
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
60
61
  {
  	int in;
bc1099d2b   Benjamin Herrenschmidt   fsi/fsi-master-gp...
62
63
  	if (!master->no_delays)
  		ndelay(FSI_GPIO_STD_DLY);
5d0d16f13   Benjamin Herrenschmidt   fsi/fsi-master-gp...
64
  	gpiod_set_value(master->gpio_clk, 0);
f3ca4834a   Benjamin Herrenschmidt   fsi/fsi-master-gp...
65
66
67
68
69
  
  	/* Dummy read to feed the synchronizers */
  	gpiod_get_value(master->gpio_data);
  
  	/* Actual data read */
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
70
  	in = gpiod_get_value(master->gpio_data);
bc1099d2b   Benjamin Herrenschmidt   fsi/fsi-master-gp...
71
72
  	if (!master->no_delays)
  		ndelay(FSI_GPIO_STD_DLY);
5d0d16f13   Benjamin Herrenschmidt   fsi/fsi-master-gp...
73
  	gpiod_set_value(master->gpio_clk, 1);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  	return in ? 1 : 0;
  }
  
  static void sda_out(struct fsi_master_gpio *master, int value)
  {
  	gpiod_set_value(master->gpio_data, value);
  }
  
  static void set_sda_input(struct fsi_master_gpio *master)
  {
  	gpiod_direction_input(master->gpio_data);
  	gpiod_set_value(master->gpio_trans, 0);
  }
  
  static void set_sda_output(struct fsi_master_gpio *master, int value)
  {
  	gpiod_set_value(master->gpio_trans, 1);
  	gpiod_direction_output(master->gpio_data, value);
  }
  
  static void clock_zeros(struct fsi_master_gpio *master, int count)
  {
777fd524b   Benjamin Herrenschmidt   fsi: master-gpio:...
96
  	trace_fsi_master_gpio_clock_zeros(master, count);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
97
98
99
  	set_sda_output(master, 1);
  	clock_toggle(master, count);
  }
777fd524b   Benjamin Herrenschmidt   fsi: master-gpio:...
100
101
102
103
  static void echo_delay(struct fsi_master_gpio *master)
  {
  	clock_zeros(master, master->t_echo_delay);
  }
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
104
105
106
107
108
109
110
111
  static void serial_in(struct fsi_master_gpio *master, struct fsi_gpio_msg *msg,
  			uint8_t num_bits)
  {
  	uint8_t bit, in_bit;
  
  	set_sda_input(master);
  
  	for (bit = 0; bit < num_bits; bit++) {
5d0d16f13   Benjamin Herrenschmidt   fsi/fsi-master-gp...
112
  		in_bit = sda_clock_in(master);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
113
114
115
116
  		msg->msg <<= 1;
  		msg->msg |= ~in_bit & 0x1;	/* Data is active low */
  	}
  	msg->bits += num_bits;
1247cf7ab   Jeremy Kerr   drivers/fsi/gpio:...
117
118
  
  	trace_fsi_master_gpio_in(master, num_bits, msg->msg);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
119
120
121
122
123
124
125
126
127
128
  }
  
  static void serial_out(struct fsi_master_gpio *master,
  			const struct fsi_gpio_msg *cmd)
  {
  	uint8_t bit;
  	uint64_t msg = ~cmd->msg;	/* Data is active low */
  	uint64_t sda_mask = 0x1ULL << (cmd->bits - 1);
  	uint64_t last_bit = ~0;
  	int next_bit;
1247cf7ab   Jeremy Kerr   drivers/fsi/gpio:...
129
  	trace_fsi_master_gpio_out(master, cmd->bits, cmd->msg);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
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
170
171
172
173
174
  	if (!cmd->bits) {
  		dev_warn(master->dev, "trying to output 0 bits
  ");
  		return;
  	}
  	set_sda_output(master, 0);
  
  	/* Send the start bit */
  	sda_out(master, 0);
  	clock_toggle(master, 1);
  
  	/* Send the message */
  	for (bit = 0; bit < cmd->bits; bit++) {
  		next_bit = (msg & sda_mask) >> (cmd->bits - 1);
  		if (last_bit ^ next_bit) {
  			sda_out(master, next_bit);
  			last_bit = next_bit;
  		}
  		clock_toggle(master, 1);
  		msg <<= 1;
  	}
  }
  
  static void msg_push_bits(struct fsi_gpio_msg *msg, uint64_t data, int bits)
  {
  	msg->msg <<= bits;
  	msg->msg |= data & ((1ull << bits) - 1);
  	msg->bits += bits;
  }
  
  static void msg_push_crc(struct fsi_gpio_msg *msg)
  {
  	uint8_t crc;
  	int top;
  
  	top = msg->bits & 0x3;
  
  	/* start bit, and any non-aligned top bits */
  	crc = crc4(0, 1 << top | msg->msg >> (msg->bits - top), top + 1);
  
  	/* aligned bits */
  	crc = crc4(crc, msg->msg, msg->bits - top);
  
  	msg_push_bits(msg, crc, 4);
  }
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  static bool check_same_address(struct fsi_master_gpio *master, int id,
  		uint32_t addr)
  {
  	/* this will also handle LAST_ADDR_INVALID */
  	return master->last_addr == (((id & 0x3) << 21) | (addr & ~0x3));
  }
  
  static bool check_relative_address(struct fsi_master_gpio *master, int id,
  		uint32_t addr, uint32_t *rel_addrp)
  {
  	uint32_t last_addr = master->last_addr;
  	int32_t rel_addr;
  
  	if (last_addr == LAST_ADDR_INVALID)
  		return false;
  
  	/* We may be in 23-bit addressing mode, which uses the id as the
  	 * top two address bits. So, if we're referencing a different ID,
  	 * use absolute addresses.
  	 */
  	if (((last_addr >> 21) & 0x3) != id)
  		return false;
  
  	/* remove the top two bits from any 23-bit addressing */
  	last_addr &= (1 << 21) - 1;
  
  	/* We know that the addresses are limited to 21 bits, so this won't
  	 * overflow the signed rel_addr */
  	rel_addr = addr - last_addr;
  	if (rel_addr > 255 || rel_addr < -256)
  		return false;
  
  	*rel_addrp = (uint32_t)rel_addr;
  
  	return true;
  }
  
  static void last_address_update(struct fsi_master_gpio *master,
  		int id, bool valid, uint32_t addr)
  {
  	if (!valid)
  		master->last_addr = LAST_ADDR_INVALID;
  	else
  		master->last_addr = ((id & 0x3) << 21) | (addr & ~0x3);
  }
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
220
  /*
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
221
   * Encode an Absolute/Relative/Same Address command
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
222
   */
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
223
224
225
  static void build_ar_command(struct fsi_master_gpio *master,
  		struct fsi_gpio_msg *cmd, uint8_t id,
  		uint32_t addr, size_t size, const void *data)
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
226
  {
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
227
  	int i, addr_bits, opcode_bits;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
228
  	bool write = !!data;
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
229
230
  	uint8_t ds, opcode;
  	uint32_t rel_addr;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
231
232
233
  
  	cmd->bits = 0;
  	cmd->msg = 0;
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
234
235
236
237
238
239
240
241
242
243
  	/* we have 21 bits of address max */
  	addr &= ((1 << 21) - 1);
  
  	/* cmd opcodes are variable length - SAME_AR is only two bits */
  	opcode_bits = 3;
  
  	if (check_same_address(master, id, addr)) {
  		/* we still address the byte offset within the word */
  		addr_bits = 2;
  		opcode_bits = 2;
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
244
  		opcode = FSI_CMD_SAME_AR;
777fd524b   Benjamin Herrenschmidt   fsi: master-gpio:...
245
  		trace_fsi_master_gpio_cmd_same_addr(master);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
246
247
248
249
250
  
  	} else if (check_relative_address(master, id, addr, &rel_addr)) {
  		/* 8 bits plus sign */
  		addr_bits = 9;
  		addr = rel_addr;
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
251
  		opcode = FSI_CMD_REL_AR;
777fd524b   Benjamin Herrenschmidt   fsi: master-gpio:...
252
  		trace_fsi_master_gpio_cmd_rel_addr(master, rel_addr);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
253
254
255
  
  	} else {
  		addr_bits = 21;
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
256
  		opcode = FSI_CMD_ABS_AR;
777fd524b   Benjamin Herrenschmidt   fsi: master-gpio:...
257
  		trace_fsi_master_gpio_cmd_abs_addr(master, addr);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
258
  	}
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  
  	/*
  	 * The read/write size is encoded in the lower bits of the address
  	 * (as it must be naturally-aligned), and the following ds bit.
  	 *
  	 *	size	addr:1	addr:0	ds
  	 *	1	x	x	0
  	 *	2	x	0	1
  	 *	4	0	1	1
  	 *
  	 */
  	ds = size > 1 ? 1 : 0;
  	addr &= ~(size - 1);
  	if (size == 4)
  		addr |= 1;
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
274
275
276
277
  	msg_push_bits(cmd, id, 2);
  	msg_push_bits(cmd, opcode, opcode_bits);
  	msg_push_bits(cmd, write ? 0 : 1, 1);
  	msg_push_bits(cmd, addr, addr_bits);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
278
279
280
281
282
283
284
285
286
287
288
289
290
  	msg_push_bits(cmd, ds, 1);
  	for (i = 0; write && i < size; i++)
  		msg_push_bits(cmd, ((uint8_t *)data)[i], 8);
  
  	msg_push_crc(cmd);
  }
  
  static void build_dpoll_command(struct fsi_gpio_msg *cmd, uint8_t slave_id)
  {
  	cmd->bits = 0;
  	cmd->msg = 0;
  
  	msg_push_bits(cmd, slave_id, 2);
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
291
  	msg_push_bits(cmd, FSI_CMD_DPOLL, 3);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
292
293
  	msg_push_crc(cmd);
  }
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
294
295
296
297
298
299
  static void build_epoll_command(struct fsi_gpio_msg *cmd, uint8_t slave_id)
  {
  	cmd->bits = 0;
  	cmd->msg = 0;
  
  	msg_push_bits(cmd, slave_id, 2);
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
300
  	msg_push_bits(cmd, FSI_CMD_EPOLL, 3);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
301
302
  	msg_push_crc(cmd);
  }
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
303
304
305
306
307
308
  static void build_term_command(struct fsi_gpio_msg *cmd, uint8_t slave_id)
  {
  	cmd->bits = 0;
  	cmd->msg = 0;
  
  	msg_push_bits(cmd, slave_id, 2);
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
309
  	msg_push_bits(cmd, FSI_CMD_TERM, 6);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
310
311
312
313
  	msg_push_crc(cmd);
  }
  
  /*
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
314
315
316
317
318
   * Note: callers rely specifically on this returning -EAGAIN for
   * a CRC error detected in the response. Use other error code
   * for other situations. It will be converted to something else
   * higher up the stack before it reaches userspace.
   */
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
319
320
321
322
  static int read_one_response(struct fsi_master_gpio *master,
  		uint8_t data_size, struct fsi_gpio_msg *msgp, uint8_t *tagp)
  {
  	struct fsi_gpio_msg msg;
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
323
  	unsigned long flags;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
324
  	uint32_t crc;
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
325
  	uint8_t tag;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
326
  	int i;
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
327
  	local_irq_save(flags);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
328

ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
329
  	/* wait for the start bit */
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
330
  	for (i = 0; i < FSI_MASTER_MTOE_COUNT; i++) {
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
331
332
333
334
335
336
  		msg.bits = 0;
  		msg.msg = 0;
  		serial_in(master, &msg, 1);
  		if (msg.msg)
  			break;
  	}
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
337
  	if (i == FSI_MASTER_MTOE_COUNT) {
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
338
339
340
  		dev_dbg(master->dev,
  			"Master time out waiting for response
  ");
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
341
  		local_irq_restore(flags);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
342
  		return -ETIMEDOUT;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
343
344
345
346
347
348
349
  	}
  
  	msg.bits = 0;
  	msg.msg = 0;
  
  	/* Read slave ID & response tag */
  	serial_in(master, &msg, 4);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
350
351
352
  	tag = msg.msg & 0x3;
  
  	/* If we have an ACK and we're expecting data, clock the data in too */
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
353
  	if (tag == FSI_RESP_ACK && data_size)
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
354
355
356
  		serial_in(master, &msg, data_size * 8);
  
  	/* read CRC */
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
357
  	serial_in(master, &msg, FSI_CRC_SIZE);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
358

26d79b272   Jeremy Kerr   fsi/master-gpio: ...
359
  	local_irq_restore(flags);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
360

ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
361
362
363
364
  	/* we have a whole message now; check CRC */
  	crc = crc4(0, 1, 1);
  	crc = crc4(crc, msg.msg, msg.bits);
  	if (crc) {
c49e34401   Benjamin Herrenschmidt   fsi/fsi-master-gp...
365
366
367
368
369
370
  		/* Check if it's all 1's, that probably means the host is off */
  		if (((~msg.msg) & ((1ull << msg.bits) - 1)) == 0)
  			return -ENODEV;
  		dev_dbg(master->dev, "ERR response CRC msg: 0x%016llx (%d bits)
  ",
  			msg.msg, msg.bits);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
371
  		return -EAGAIN;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
372
373
374
375
376
377
378
379
380
381
382
383
384
  	}
  
  	if (msgp)
  		*msgp = msg;
  	if (tagp)
  		*tagp = tag;
  
  	return 0;
  }
  
  static int issue_term(struct fsi_master_gpio *master, uint8_t slave)
  {
  	struct fsi_gpio_msg cmd;
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
385
  	unsigned long flags;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
386
387
388
389
  	uint8_t tag;
  	int rc;
  
  	build_term_command(&cmd, slave);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
390

26d79b272   Jeremy Kerr   fsi/master-gpio: ...
391
  	local_irq_save(flags);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
392
393
  	serial_out(master, &cmd);
  	echo_delay(master);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
394
  	local_irq_restore(flags);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
395
396
397
398
399
400
401
  
  	rc = read_one_response(master, 0, NULL, &tag);
  	if (rc < 0) {
  		dev_err(master->dev,
  				"TERM failed; lost communication with slave
  ");
  		return -EIO;
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
402
  	} else if (tag != FSI_RESP_ACK) {
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
403
404
405
406
407
408
409
410
411
412
413
414
415
  		dev_err(master->dev, "TERM failed; response %d
  ", tag);
  		return -EIO;
  	}
  
  	return 0;
  }
  
  static int poll_for_response(struct fsi_master_gpio *master,
  		uint8_t slave, uint8_t size, void *data)
  {
  	struct fsi_gpio_msg response, cmd;
  	int busy_count = 0, rc, i;
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
416
  	unsigned long flags;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
417
418
  	uint8_t tag;
  	uint8_t *data_byte = data;
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
419
  	int crc_err_retries = 0;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
420
421
  retry:
  	rc = read_one_response(master, size, &response, &tag);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  
  	/* Handle retries on CRC errors */
  	if (rc == -EAGAIN) {
  		/* Too many retries ? */
  		if (crc_err_retries++ > FSI_CRC_ERR_RETRIES) {
  			/*
  			 * Pass it up as a -EIO otherwise upper level will retry
  			 * the whole command which isn't what we want here.
  			 */
  			rc = -EIO;
  			goto fail;
  		}
  		dev_dbg(master->dev,
  			 "CRC error retry %d
  ", crc_err_retries);
  		trace_fsi_master_gpio_crc_rsp_error(master);
  		build_epoll_command(&cmd, slave);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
439
  		local_irq_save(flags);
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
440
  		clock_zeros(master, FSI_MASTER_EPOLL_CLOCKS);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
441
442
  		serial_out(master, &cmd);
  		echo_delay(master);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
443
  		local_irq_restore(flags);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
444
445
446
  		goto retry;
  	} else if (rc)
  		goto fail;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
447
448
  
  	switch (tag) {
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
449
  	case FSI_RESP_ACK:
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
450
451
452
453
454
455
456
457
458
459
460
461
  		if (size && data) {
  			uint64_t val = response.msg;
  			/* clear crc & mask */
  			val >>= 4;
  			val &= (1ull << (size * 8)) - 1;
  
  			for (i = 0; i < size; i++) {
  				data_byte[size-i-1] = val;
  				val >>= 8;
  			}
  		}
  		break;
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
462
  	case FSI_RESP_BUSY:
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
463
464
465
466
467
  		/*
  		 * Its necessary to clock slave before issuing
  		 * d-poll, not indicated in the hardware protocol
  		 * spec. < 20 clocks causes slave to hang, 21 ok.
  		 */
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
468
  		if (busy_count++ < FSI_MASTER_MAX_BUSY) {
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
469
  			build_dpoll_command(&cmd, slave);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
470
  			local_irq_save(flags);
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
471
  			clock_zeros(master, FSI_MASTER_DPOLL_CLOCKS);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
472
473
  			serial_out(master, &cmd);
  			echo_delay(master);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
474
  			local_irq_restore(flags);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
475
476
477
478
479
  			goto retry;
  		}
  		dev_warn(master->dev,
  			"ERR slave is stuck in busy state, issuing TERM
  ");
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
480
  		local_irq_save(flags);
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
481
  		clock_zeros(master, FSI_MASTER_DPOLL_CLOCKS);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
482
  		local_irq_restore(flags);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
483
484
485
  		issue_term(master, slave);
  		rc = -EIO;
  		break;
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
486
  	case FSI_RESP_ERRA:
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
487
488
  		dev_dbg(master->dev, "ERRA received: 0x%x
  ", (int)response.msg);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
489
490
  		rc = -EIO;
  		break;
55382d301   Benjamin Herrenschmidt   fsi: master-gpio:...
491
  	case FSI_RESP_ERRC:
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
492
493
  		dev_dbg(master->dev, "ERRC received: 0x%x
  ", (int)response.msg);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
494
495
496
  		trace_fsi_master_gpio_crc_cmd_error(master);
  		rc = -EAGAIN;
  		break;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
497
  	}
918da9517   Andrew Jeffery   fsi: gpio: Trace ...
498
499
  	if (busy_count > 0)
  		trace_fsi_master_gpio_poll_response_busy(master, busy_count);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
500
   fail:
edc248514   Benjamin Herrenschmidt   fsi: master-gpio:...
501
502
503
504
  	/*
  	 * tSendDelay clocks, avoids signal reflections when switching
  	 * from receive of response back to send of data.
  	 */
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
505
  	local_irq_save(flags);
75854c148   Benjamin Herrenschmidt   fsi: master-gpio:...
506
  	clock_zeros(master, master->t_send_delay);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
507
  	local_irq_restore(flags);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
508
509
  	return rc;
  }
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
510
511
  static int send_request(struct fsi_master_gpio *master,
  		struct fsi_gpio_msg *cmd)
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
512
513
  {
  	unsigned long flags;
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
514

26d79b272   Jeremy Kerr   fsi/master-gpio: ...
515
  	if (master->external_mode)
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
516
  		return -EBUSY;
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
517

26d79b272   Jeremy Kerr   fsi/master-gpio: ...
518
  	local_irq_save(flags);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
519
520
  	serial_out(master, cmd);
  	echo_delay(master);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
521
  	local_irq_restore(flags);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
522
523
524
525
526
527
528
  
  	return 0;
  }
  
  static int fsi_master_gpio_xfer(struct fsi_master_gpio *master, uint8_t slave,
  		struct fsi_gpio_msg *cmd, size_t resp_len, void *resp)
  {
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
529
  	int rc = -EAGAIN, retries = 0;
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
530

4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
531
532
533
534
  	while ((retries++) < FSI_CRC_ERR_RETRIES) {
  		rc = send_request(master, cmd);
  		if (rc)
  			break;
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
535
  		rc = poll_for_response(master, slave, resp_len, resp);
4e56828a5   Benjamin Herrenschmidt   fsi/fsi-master-gp...
536
537
538
539
540
541
542
543
544
  		if (rc != -EAGAIN)
  			break;
  		rc = -EIO;
  		dev_warn(master->dev, "ECRC retry %d
  ", retries);
  
  		/* Pace it a bit before retry */
  		msleep(1);
  	}
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
545

ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
546
547
548
549
550
551
552
553
  	return rc;
  }
  
  static int fsi_master_gpio_read(struct fsi_master *_master, int link,
  		uint8_t id, uint32_t addr, void *val, size_t size)
  {
  	struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
  	struct fsi_gpio_msg cmd;
8193fb445   Jeremy Kerr   fsi/gpio: Include...
554
  	int rc;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
555
556
557
  
  	if (link != 0)
  		return -ENODEV;
8193fb445   Jeremy Kerr   fsi/gpio: Include...
558
  	mutex_lock(&master->cmd_lock);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
559
  	build_ar_command(master, &cmd, id, addr, size, NULL);
8193fb445   Jeremy Kerr   fsi/gpio: Include...
560
  	rc = fsi_master_gpio_xfer(master, id, &cmd, size, val);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
561
  	last_address_update(master, id, rc == 0, addr);
8193fb445   Jeremy Kerr   fsi/gpio: Include...
562
563
564
  	mutex_unlock(&master->cmd_lock);
  
  	return rc;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
565
566
567
568
569
570
571
  }
  
  static int fsi_master_gpio_write(struct fsi_master *_master, int link,
  		uint8_t id, uint32_t addr, const void *val, size_t size)
  {
  	struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
  	struct fsi_gpio_msg cmd;
8193fb445   Jeremy Kerr   fsi/gpio: Include...
572
  	int rc;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
573
574
575
  
  	if (link != 0)
  		return -ENODEV;
8193fb445   Jeremy Kerr   fsi/gpio: Include...
576
  	mutex_lock(&master->cmd_lock);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
577
  	build_ar_command(master, &cmd, id, addr, size, val);
8193fb445   Jeremy Kerr   fsi/gpio: Include...
578
  	rc = fsi_master_gpio_xfer(master, id, &cmd, 0, NULL);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
579
  	last_address_update(master, id, rc == 0, addr);
8193fb445   Jeremy Kerr   fsi/gpio: Include...
580
581
582
  	mutex_unlock(&master->cmd_lock);
  
  	return rc;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
583
584
585
586
587
588
589
  }
  
  static int fsi_master_gpio_term(struct fsi_master *_master,
  		int link, uint8_t id)
  {
  	struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
  	struct fsi_gpio_msg cmd;
8193fb445   Jeremy Kerr   fsi/gpio: Include...
590
  	int rc;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
591
592
593
  
  	if (link != 0)
  		return -ENODEV;
8193fb445   Jeremy Kerr   fsi/gpio: Include...
594
  	mutex_lock(&master->cmd_lock);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
595
  	build_term_command(&cmd, id);
8193fb445   Jeremy Kerr   fsi/gpio: Include...
596
  	rc = fsi_master_gpio_xfer(master, id, &cmd, 0, NULL);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
597
  	last_address_update(master, id, false, 0);
8193fb445   Jeremy Kerr   fsi/gpio: Include...
598
599
600
  	mutex_unlock(&master->cmd_lock);
  
  	return rc;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
601
602
603
604
605
  }
  
  static int fsi_master_gpio_break(struct fsi_master *_master, int link)
  {
  	struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
29d9b9271   Jeremy Kerr   fsi: master-gpio:...
606
  	unsigned long flags;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
607
608
609
  
  	if (link != 0)
  		return -ENODEV;
1247cf7ab   Jeremy Kerr   drivers/fsi/gpio:...
610
  	trace_fsi_master_gpio_break(master);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
611
  	mutex_lock(&master->cmd_lock);
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
612
  	if (master->external_mode) {
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
613
  		mutex_unlock(&master->cmd_lock);
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
614
615
  		return -EBUSY;
  	}
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
616

26d79b272   Jeremy Kerr   fsi/master-gpio: ...
617
  	local_irq_save(flags);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
618

ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
619
620
621
622
623
624
625
626
  	set_sda_output(master, 1);
  	sda_out(master, 1);
  	clock_toggle(master, FSI_PRE_BREAK_CLOCKS);
  	sda_out(master, 0);
  	clock_toggle(master, FSI_BREAK_CLOCKS);
  	echo_delay(master);
  	sda_out(master, 1);
  	clock_toggle(master, FSI_POST_BREAK_CLOCKS);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
627

26d79b272   Jeremy Kerr   fsi/master-gpio: ...
628
  	local_irq_restore(flags);
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
629
  	last_address_update(master, 0, false, 0);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
630
  	mutex_unlock(&master->cmd_lock);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
631
632
633
634
635
636
637
638
639
  
  	/* Wait for logic reset to take effect */
  	udelay(200);
  
  	return 0;
  }
  
  static void fsi_master_gpio_init(struct fsi_master_gpio *master)
  {
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
640
  	unsigned long flags;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
641
642
643
644
645
646
647
  	gpiod_direction_output(master->gpio_mux, 1);
  	gpiod_direction_output(master->gpio_trans, 1);
  	gpiod_direction_output(master->gpio_enable, 1);
  	gpiod_direction_output(master->gpio_clk, 1);
  	gpiod_direction_output(master->gpio_data, 1);
  
  	/* todo: evaluate if clocks can be reduced */
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
648
  	local_irq_save(flags);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
649
  	clock_zeros(master, FSI_INIT_CLOCKS);
26d79b272   Jeremy Kerr   fsi/master-gpio: ...
650
  	local_irq_restore(flags);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
651
  }
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
652
653
654
655
656
657
658
659
  static void fsi_master_gpio_init_external(struct fsi_master_gpio *master)
  {
  	gpiod_direction_output(master->gpio_mux, 0);
  	gpiod_direction_output(master->gpio_trans, 0);
  	gpiod_direction_output(master->gpio_enable, 1);
  	gpiod_direction_input(master->gpio_clk);
  	gpiod_direction_input(master->gpio_data);
  }
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
660
661
662
  static int fsi_master_gpio_link_enable(struct fsi_master *_master, int link)
  {
  	struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
663
  	int rc = -EBUSY;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
664
665
666
  
  	if (link != 0)
  		return -ENODEV;
29d9b9271   Jeremy Kerr   fsi: master-gpio:...
667

e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
668
  	mutex_lock(&master->cmd_lock);
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
669
670
671
672
  	if (!master->external_mode) {
  		gpiod_set_value(master->gpio_enable, 1);
  		rc = 0;
  	}
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
673
  	mutex_unlock(&master->cmd_lock);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
674

b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
675
676
  	return rc;
  }
75854c148   Benjamin Herrenschmidt   fsi: master-gpio:...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
  static int fsi_master_gpio_link_config(struct fsi_master *_master, int link,
  				       u8 t_send_delay, u8 t_echo_delay)
  {
  	struct fsi_master_gpio *master = to_fsi_master_gpio(_master);
  
  	if (link != 0)
  		return -ENODEV;
  
  	mutex_lock(&master->cmd_lock);
  	master->t_send_delay = t_send_delay;
  	master->t_echo_delay = t_echo_delay;
  	mutex_unlock(&master->cmd_lock);
  
  	return 0;
  }
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  static ssize_t external_mode_show(struct device *dev,
  		struct device_attribute *attr, char *buf)
  {
  	struct fsi_master_gpio *master = dev_get_drvdata(dev);
  
  	return snprintf(buf, PAGE_SIZE - 1, "%u
  ",
  			master->external_mode ? 1 : 0);
  }
  
  static ssize_t external_mode_store(struct device *dev,
  		struct device_attribute *attr, const char *buf, size_t count)
  {
  	struct fsi_master_gpio *master = dev_get_drvdata(dev);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
706
  	unsigned long val;
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
707
708
709
710
711
712
713
714
  	bool external_mode;
  	int err;
  
  	err = kstrtoul(buf, 0, &val);
  	if (err)
  		return err;
  
  	external_mode = !!val;
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
715
  	mutex_lock(&master->cmd_lock);
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
716
717
  
  	if (external_mode == master->external_mode) {
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
718
  		mutex_unlock(&master->cmd_lock);
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
719
720
721
722
723
724
725
726
  		return count;
  	}
  
  	master->external_mode = external_mode;
  	if (master->external_mode)
  		fsi_master_gpio_init_external(master);
  	else
  		fsi_master_gpio_init(master);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
727
728
  
  	mutex_unlock(&master->cmd_lock);
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
729
730
731
732
  
  	fsi_master_rescan(&master->master);
  
  	return count;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
733
  }
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
734
735
  static DEVICE_ATTR(external_mode, 0664,
  		external_mode_show, external_mode_store);
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
736
737
738
739
740
741
742
743
  static void fsi_master_gpio_release(struct device *dev)
  {
  	struct fsi_master_gpio *master = to_fsi_master_gpio(dev_to_fsi_master(dev));
  
  	of_node_put(dev_of_node(master->dev));
  
  	kfree(master);
  }
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
744
745
746
747
  static int fsi_master_gpio_probe(struct platform_device *pdev)
  {
  	struct fsi_master_gpio *master;
  	struct gpio_desc *gpio;
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
748
  	int rc;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
749

8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
750
  	master = kzalloc(sizeof(*master), GFP_KERNEL);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
751
752
753
754
755
  	if (!master)
  		return -ENOMEM;
  
  	master->dev = &pdev->dev;
  	master->master.dev.parent = master->dev;
f6a2f8eb7   Jeremy Kerr   fsi: Match fsi sl...
756
  	master->master.dev.of_node = of_node_get(dev_of_node(master->dev));
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
757
  	master->master.dev.release = fsi_master_gpio_release;
0e82e5c1f   Jeremy Kerr   fsi/gpio: Use rel...
758
  	master->last_addr = LAST_ADDR_INVALID;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
759
760
761
762
763
  
  	gpio = devm_gpiod_get(&pdev->dev, "clock", 0);
  	if (IS_ERR(gpio)) {
  		dev_err(&pdev->dev, "failed to get clock gpio
  ");
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
764
765
  		rc = PTR_ERR(gpio);
  		goto err_free;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
766
767
768
769
770
771
772
  	}
  	master->gpio_clk = gpio;
  
  	gpio = devm_gpiod_get(&pdev->dev, "data", 0);
  	if (IS_ERR(gpio)) {
  		dev_err(&pdev->dev, "failed to get data gpio
  ");
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
773
774
  		rc = PTR_ERR(gpio);
  		goto err_free;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
775
776
777
778
779
780
781
782
  	}
  	master->gpio_data = gpio;
  
  	/* Optional GPIOs */
  	gpio = devm_gpiod_get_optional(&pdev->dev, "trans", 0);
  	if (IS_ERR(gpio)) {
  		dev_err(&pdev->dev, "failed to get trans gpio
  ");
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
783
784
  		rc = PTR_ERR(gpio);
  		goto err_free;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
785
786
787
788
789
790
791
  	}
  	master->gpio_trans = gpio;
  
  	gpio = devm_gpiod_get_optional(&pdev->dev, "enable", 0);
  	if (IS_ERR(gpio)) {
  		dev_err(&pdev->dev, "failed to get enable gpio
  ");
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
792
793
  		rc = PTR_ERR(gpio);
  		goto err_free;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
794
795
796
797
798
799
800
  	}
  	master->gpio_enable = gpio;
  
  	gpio = devm_gpiod_get_optional(&pdev->dev, "mux", 0);
  	if (IS_ERR(gpio)) {
  		dev_err(&pdev->dev, "failed to get mux gpio
  ");
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
801
802
  		rc = PTR_ERR(gpio);
  		goto err_free;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
803
804
  	}
  	master->gpio_mux = gpio;
bc1099d2b   Benjamin Herrenschmidt   fsi/fsi-master-gp...
805
806
807
808
809
810
  	/*
  	 * Check if GPIO block is slow enought that no extra delays
  	 * are necessary. This improves performance on ast2500 by
  	 * an order of magnitude.
  	 */
  	master->no_delays = device_property_present(&pdev->dev, "no-gpio-delays");
75854c148   Benjamin Herrenschmidt   fsi: master-gpio:...
811
812
813
  	/* Default FSI command delays */
  	master->t_send_delay = FSI_SEND_DELAY_CLOCKS;
  	master->t_echo_delay = FSI_ECHO_DELAY_CLOCKS;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
814
  	master->master.n_links = 1;
4af889b0f   Jeremy Kerr   drivers/fsi: Use ...
815
  	master->master.flags = FSI_MASTER_FLAG_SWCLOCK;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
816
817
818
819
820
  	master->master.read = fsi_master_gpio_read;
  	master->master.write = fsi_master_gpio_write;
  	master->master.term = fsi_master_gpio_term;
  	master->master.send_break = fsi_master_gpio_break;
  	master->master.link_enable = fsi_master_gpio_link_enable;
75854c148   Benjamin Herrenschmidt   fsi: master-gpio:...
821
  	master->master.link_config = fsi_master_gpio_link_config;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
822
  	platform_set_drvdata(pdev, master);
e5538139e   Jeremy Kerr   fsi: gpio: Use a ...
823
  	mutex_init(&master->cmd_lock);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
824
825
  
  	fsi_master_gpio_init(master);
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
826
827
  	rc = device_create_file(&pdev->dev, &dev_attr_external_mode);
  	if (rc)
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
828
  		goto err_free;
b8bd146d3   Jeremy Kerr   fsi: master-gpio:...
829

8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
830
831
832
833
834
835
836
837
838
839
  	rc = fsi_master_register(&master->master);
  	if (rc) {
  		device_remove_file(&pdev->dev, &dev_attr_external_mode);
  		put_device(&master->master.dev);
  		return rc;
  	}
  	return 0;
   err_free:
  	kfree(master);
  	return rc;
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
840
  }
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
841

ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
842
843
844
  static int fsi_master_gpio_remove(struct platform_device *pdev)
  {
  	struct fsi_master_gpio *master = platform_get_drvdata(pdev);
8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
845
  	device_remove_file(&pdev->dev, &dev_attr_external_mode);
ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
846

8ef9ccf81   Benjamin Herrenschmidt   fsi: master-gpio:...
847
  	fsi_master_unregister(&master->master);
f6a2f8eb7   Jeremy Kerr   fsi: Match fsi sl...
848

ac0385d9f   Christopher Bostic   drivers/fsi: Add ...
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
  	return 0;
  }
  
  static const struct of_device_id fsi_master_gpio_match[] = {
  	{ .compatible = "fsi-master-gpio" },
  	{ },
  };
  
  static struct platform_driver fsi_master_gpio_driver = {
  	.driver = {
  		.name		= "fsi-master-gpio",
  		.of_match_table	= fsi_master_gpio_match,
  	},
  	.probe	= fsi_master_gpio_probe,
  	.remove = fsi_master_gpio_remove,
  };
  
  module_platform_driver(fsi_master_gpio_driver);
  MODULE_LICENSE("GPL");