Blame view

drivers/spi/spi-sc18is602.c 8.49 KB
3ce8859e2   Guenter Roeck   spi: Master drive...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * NXP SC18IS602/603 SPI driver
   *
   * Copyright (C) Guenter Roeck <linux@roeck-us.net>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
3ce8859e2   Guenter Roeck   spi: Master drive...
15
16
17
18
19
20
21
22
23
   */
  
  #include <linux/kernel.h>
  #include <linux/err.h>
  #include <linux/module.h>
  #include <linux/spi/spi.h>
  #include <linux/i2c.h>
  #include <linux/delay.h>
  #include <linux/pm_runtime.h>
68c97b92c   Javier Martinez Canillas   spi: sc18is602: A...
24
  #include <linux/of_device.h>
3ce8859e2   Guenter Roeck   spi: Master drive...
25
26
  #include <linux/of.h>
  #include <linux/platform_data/sc18is602.h>
f99008013   Phil Reid   spi: sc18is602: A...
27
  #include <linux/gpio/consumer.h>
3ce8859e2   Guenter Roeck   spi: Master drive...
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
  
  enum chips { sc18is602, sc18is602b, sc18is603 };
  
  #define SC18IS602_BUFSIZ		200
  #define SC18IS602_CLOCK			7372000
  
  #define SC18IS602_MODE_CPHA		BIT(2)
  #define SC18IS602_MODE_CPOL		BIT(3)
  #define SC18IS602_MODE_LSB_FIRST	BIT(5)
  #define SC18IS602_MODE_CLOCK_DIV_4	0x0
  #define SC18IS602_MODE_CLOCK_DIV_16	0x1
  #define SC18IS602_MODE_CLOCK_DIV_64	0x2
  #define SC18IS602_MODE_CLOCK_DIV_128	0x3
  
  struct sc18is602 {
  	struct spi_master	*master;
  	struct device		*dev;
  	u8			ctrl;
  	u32			freq;
  	u32			speed;
  
  	/* I2C data */
  	struct i2c_client	*client;
  	enum chips		id;
  	u8			buffer[SC18IS602_BUFSIZ + 1];
  	int			tlen;	/* Data queued for tx in buffer */
  	int			rindex;	/* Receive data index in buffer */
f99008013   Phil Reid   spi: sc18is602: A...
55
56
  
  	struct gpio_desc	*reset;
3ce8859e2   Guenter Roeck   spi: Master drive...
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  };
  
  static int sc18is602_wait_ready(struct sc18is602 *hw, int len)
  {
  	int i, err;
  	int usecs = 1000000 * len / hw->speed + 1;
  	u8 dummy[1];
  
  	for (i = 0; i < 10; i++) {
  		err = i2c_master_recv(hw->client, dummy, 1);
  		if (err >= 0)
  			return 0;
  		usleep_range(usecs, usecs * 2);
  	}
  	return -ETIMEDOUT;
  }
  
  static int sc18is602_txrx(struct sc18is602 *hw, struct spi_message *msg,
  			  struct spi_transfer *t, bool do_transfer)
  {
  	unsigned int len = t->len;
  	int ret;
  
  	if (hw->tlen == 0) {
  		/* First byte (I2C command) is chip select */
  		hw->buffer[0] = 1 << msg->spi->chip_select;
  		hw->tlen = 1;
  		hw->rindex = 0;
  	}
  	/*
  	 * We can not immediately send data to the chip, since each I2C message
  	 * resembles a full SPI message (from CS active to CS inactive).
  	 * Enqueue messages up to the first read or until do_transfer is true.
  	 */
  	if (t->tx_buf) {
  		memcpy(&hw->buffer[hw->tlen], t->tx_buf, len);
  		hw->tlen += len;
  		if (t->rx_buf)
  			do_transfer = true;
  		else
  			hw->rindex = hw->tlen - 1;
  	} else if (t->rx_buf) {
  		/*
  		 * For receive-only transfers we still need to perform a dummy
  		 * write to receive data from the SPI chip.
  		 * Read data starts at the end of transmit data (minus 1 to
  		 * account for CS).
  		 */
  		hw->rindex = hw->tlen - 1;
  		memset(&hw->buffer[hw->tlen], 0, len);
  		hw->tlen += len;
  		do_transfer = true;
  	}
  
  	if (do_transfer && hw->tlen > 1) {
  		ret = sc18is602_wait_ready(hw, SC18IS602_BUFSIZ);
  		if (ret < 0)
  			return ret;
  		ret = i2c_master_send(hw->client, hw->buffer, hw->tlen);
  		if (ret < 0)
  			return ret;
  		if (ret != hw->tlen)
  			return -EIO;
  
  		if (t->rx_buf) {
  			int rlen = hw->rindex + len;
  
  			ret = sc18is602_wait_ready(hw, hw->tlen);
  			if (ret < 0)
  				return ret;
  			ret = i2c_master_recv(hw->client, hw->buffer, rlen);
  			if (ret < 0)
  				return ret;
  			if (ret != rlen)
  				return -EIO;
  			memcpy(t->rx_buf, &hw->buffer[hw->rindex], len);
  		}
  		hw->tlen = 0;
  	}
  	return len;
  }
  
  static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode)
  {
  	u8 ctrl = 0;
  	int ret;
  
  	if (mode & SPI_CPHA)
  		ctrl |= SC18IS602_MODE_CPHA;
  	if (mode & SPI_CPOL)
  		ctrl |= SC18IS602_MODE_CPOL;
  	if (mode & SPI_LSB_FIRST)
  		ctrl |= SC18IS602_MODE_LSB_FIRST;
  
  	/* Find the closest clock speed */
  	if (hz >= hw->freq / 4) {
  		ctrl |= SC18IS602_MODE_CLOCK_DIV_4;
  		hw->speed = hw->freq / 4;
  	} else if (hz >= hw->freq / 16) {
  		ctrl |= SC18IS602_MODE_CLOCK_DIV_16;
  		hw->speed = hw->freq / 16;
  	} else if (hz >= hw->freq / 64) {
  		ctrl |= SC18IS602_MODE_CLOCK_DIV_64;
  		hw->speed = hw->freq / 64;
  	} else {
  		ctrl |= SC18IS602_MODE_CLOCK_DIV_128;
  		hw->speed = hw->freq / 128;
  	}
  
  	/*
  	 * Don't do anything if the control value did not change. The initial
  	 * value of 0xff for hw->ctrl ensures that the correct mode will be set
  	 * with the first call to this function.
  	 */
  	if (ctrl == hw->ctrl)
  		return 0;
  
  	ret = i2c_smbus_write_byte_data(hw->client, 0xf0, ctrl);
  	if (ret < 0)
  		return ret;
  
  	hw->ctrl = ctrl;
  
  	return 0;
  }
  
  static int sc18is602_check_transfer(struct spi_device *spi,
  				    struct spi_transfer *t, int tlen)
  {
3ce8859e2   Guenter Roeck   spi: Master drive...
186
187
  	if (t && t->len + tlen > SC18IS602_BUFSIZ)
  		return -EINVAL;
3ce8859e2   Guenter Roeck   spi: Master drive...
188
189
190
191
192
193
194
195
196
197
  	return 0;
  }
  
  static int sc18is602_transfer_one(struct spi_master *master,
  				  struct spi_message *m)
  {
  	struct sc18is602 *hw = spi_master_get_devdata(master);
  	struct spi_device *spi = m->spi;
  	struct spi_transfer *t;
  	int status = 0;
3ce8859e2   Guenter Roeck   spi: Master drive...
198
199
  	hw->tlen = 0;
  	list_for_each_entry(t, &m->transfers, transfer_list) {
3ce8859e2   Guenter Roeck   spi: Master drive...
200
201
202
203
204
  		bool do_transfer;
  
  		status = sc18is602_check_transfer(spi, t, hw->tlen);
  		if (status < 0)
  			break;
09e99bca8   Axel Lin   spi: sc18is602: C...
205
  		status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode);
3ce8859e2   Guenter Roeck   spi: Master drive...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  		if (status < 0)
  			break;
  
  		do_transfer = t->cs_change || list_is_last(&t->transfer_list,
  							   &m->transfers);
  
  		if (t->len) {
  			status = sc18is602_txrx(hw, m, t, do_transfer);
  			if (status < 0)
  				break;
  			m->actual_length += status;
  		}
  		status = 0;
  
  		if (t->delay_usecs)
  			udelay(t->delay_usecs);
  	}
3ce8859e2   Guenter Roeck   spi: Master drive...
223
224
225
226
227
  	m->status = status;
  	spi_finalize_current_message(master);
  
  	return status;
  }
c5c67e31b   Axel Lin   spi: sc18is602: M...
228
229
230
231
232
233
234
235
236
237
  static int sc18is602_setup(struct spi_device *spi)
  {
  	struct sc18is602 *hw = spi_master_get_devdata(spi->master);
  
  	/* SC18IS602 does not support CS2 */
  	if (hw->id == sc18is602 && spi->chip_select == 2)
  		return -ENXIO;
  
  	return 0;
  }
3ce8859e2   Guenter Roeck   spi: Master drive...
238
239
240
241
242
243
244
245
246
247
248
249
  static int sc18is602_probe(struct i2c_client *client,
  			   const struct i2c_device_id *id)
  {
  	struct device *dev = &client->dev;
  	struct device_node *np = dev->of_node;
  	struct sc18is602_platform_data *pdata = dev_get_platdata(dev);
  	struct sc18is602 *hw;
  	struct spi_master *master;
  	int error;
  
  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
  				     I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
58ed90de3   Guenter Roeck   spi/sc18is602: Re...
250
  		return -EINVAL;
3ce8859e2   Guenter Roeck   spi: Master drive...
251
252
253
254
255
256
257
  
  	master = spi_alloc_master(dev, sizeof(struct sc18is602));
  	if (!master)
  		return -ENOMEM;
  
  	hw = spi_master_get_devdata(master);
  	i2c_set_clientdata(client, hw);
f99008013   Phil Reid   spi: sc18is602: A...
258
259
260
261
  	/* assert reset and then release */
  	hw->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
  	if (IS_ERR(hw->reset))
  		return PTR_ERR(hw->reset);
76cce7e3a   Phil Reid   spi: sc18is602: C...
262
  	gpiod_set_value_cansleep(hw->reset, 0);
f99008013   Phil Reid   spi: sc18is602: A...
263

3ce8859e2   Guenter Roeck   spi: Master drive...
264
265
266
267
  	hw->master = master;
  	hw->client = client;
  	hw->dev = dev;
  	hw->ctrl = 0xff;
68c97b92c   Javier Martinez Canillas   spi: sc18is602: A...
268
269
270
271
  	if (client->dev.of_node)
  		hw->id = (enum chips)of_device_get_match_data(&client->dev);
  	else
  		hw->id = id->driver_data;
3ce8859e2   Guenter Roeck   spi: Master drive...
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  
  	switch (hw->id) {
  	case sc18is602:
  	case sc18is602b:
  		master->num_chipselect = 4;
  		hw->freq = SC18IS602_CLOCK;
  		break;
  	case sc18is603:
  		master->num_chipselect = 2;
  		if (pdata) {
  			hw->freq = pdata->clock_frequency;
  		} else {
  			const __be32 *val;
  			int len;
  
  			val = of_get_property(np, "clock-frequency", &len);
  			if (val && len >= sizeof(__be32))
  				hw->freq = be32_to_cpup(val);
  		}
  		if (!hw->freq)
  			hw->freq = SC18IS602_CLOCK;
  		break;
  	}
b4e275452   Guenter Roeck   spi: sc18is602: S...
295
  	master->bus_num = np ? -1 : client->adapter->nr;
3ce8859e2   Guenter Roeck   spi: Master drive...
296
  	master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
463654cec   Axel Lin   spi: sc18is602: C...
297
  	master->bits_per_word_mask = SPI_BPW_MASK(8);
c5c67e31b   Axel Lin   spi: sc18is602: M...
298
  	master->setup = sc18is602_setup;
3ce8859e2   Guenter Roeck   spi: Master drive...
299
300
  	master->transfer_one_message = sc18is602_transfer_one;
  	master->dev.of_node = np;
09e99bca8   Axel Lin   spi: sc18is602: C...
301
302
  	master->min_speed_hz = hw->freq / 128;
  	master->max_speed_hz = hw->freq / 4;
3ce8859e2   Guenter Roeck   spi: Master drive...
303

15e0964dc   Jingoo Han   spi: sc18is602: U...
304
  	error = devm_spi_register_master(dev, master);
3ce8859e2   Guenter Roeck   spi: Master drive...
305
306
307
308
309
310
311
312
313
  	if (error)
  		goto error_reg;
  
  	return 0;
  
  error_reg:
  	spi_master_put(master);
  	return error;
  }
3ce8859e2   Guenter Roeck   spi: Master drive...
314
315
316
317
318
319
320
  static const struct i2c_device_id sc18is602_id[] = {
  	{ "sc18is602", sc18is602 },
  	{ "sc18is602b", sc18is602b },
  	{ "sc18is603", sc18is603 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, sc18is602_id);
68c97b92c   Javier Martinez Canillas   spi: sc18is602: A...
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  static const struct of_device_id sc18is602_of_match[] = {
  	{
  		.compatible = "nxp,sc18is602",
  		.data = (void *)sc18is602
  	},
  	{
  		.compatible = "nxp,sc18is602b",
  		.data = (void *)sc18is602b
  	},
  	{
  		.compatible = "nxp,sc18is603",
  		.data = (void *)sc18is603
  	},
  	{ },
  };
  MODULE_DEVICE_TABLE(of, sc18is602_of_match);
3ce8859e2   Guenter Roeck   spi: Master drive...
337
338
339
  static struct i2c_driver sc18is602_driver = {
  	.driver = {
  		.name = "sc18is602",
68c97b92c   Javier Martinez Canillas   spi: sc18is602: A...
340
  		.of_match_table = of_match_ptr(sc18is602_of_match),
3ce8859e2   Guenter Roeck   spi: Master drive...
341
342
  	},
  	.probe = sc18is602_probe,
3ce8859e2   Guenter Roeck   spi: Master drive...
343
344
345
346
347
348
349
350
  	.id_table = sc18is602_id,
  };
  
  module_i2c_driver(sc18is602_driver);
  
  MODULE_DESCRIPTION("SC18IC602/603 SPI Master Driver");
  MODULE_AUTHOR("Guenter Roeck");
  MODULE_LICENSE("GPL");