Blame view

drivers/rtc/rtc-v3020.c 8.75 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
362600fe6   Raphael Assenat   [PATCH] Add v3020...
2
3
4
5
6
  /* drivers/rtc/rtc-v3020.c
   *
   * Copyright (C) 2006 8D Technologies inc.
   * Copyright (C) 2004 Compulab Ltd.
   *
362600fe6   Raphael Assenat   [PATCH] Add v3020...
7
8
9
10
11
12
13
14
15
   * Driver for the V3020 RTC
   *
   * Changelog:
   *
   *  10-May-2006: Raphael Assenat <raph@8d.com>
   *				- Converted to platform driver
   *				- Use the generic rtc class
   *
   *  ??-???-2004: Someone at Compulab
de2edf32f   Sachin Kamat   drivers/rtc/rtc-v...
16
   *			- Initial driver creation.
362600fe6   Raphael Assenat   [PATCH] Add v3020...
17
18
19
20
21
22
23
   */
  #include <linux/platform_device.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/rtc.h>
  #include <linux/types.h>
  #include <linux/bcd.h>
cd9b518b9   Alexandre Belloni   rtc: v3020: move ...
24
  #include <linux/platform_data/rtc-v3020.h>
f3d79b20d   Mike Rapoport   RTC v3020 fixes
25
  #include <linux/delay.h>
96615841e   Mike Rapoport   rtc-v3020: add ab...
26
  #include <linux/gpio.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
362600fe6   Raphael Assenat   [PATCH] Add v3020...
28

c08cf9daf   Mike Rapoport   rtc-v3020: coding...
29
  #include <linux/io.h>
362600fe6   Raphael Assenat   [PATCH] Add v3020...
30
31
  
  #undef DEBUG
96615841e   Mike Rapoport   rtc-v3020: add ab...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  struct v3020;
  
  struct v3020_chip_ops {
  	int (*map_io)(struct v3020 *chip, struct platform_device *pdev,
  		      struct v3020_platform_data *pdata);
  	void (*unmap_io)(struct v3020 *chip);
  	unsigned char (*read_bit)(struct v3020 *chip);
  	void (*write_bit)(struct v3020 *chip, unsigned char bit);
  };
  
  #define V3020_CS	0
  #define V3020_WR	1
  #define V3020_RD	2
  #define V3020_IO	3
362600fe6   Raphael Assenat   [PATCH] Add v3020...
46
  struct v3020 {
96615841e   Mike Rapoport   rtc-v3020: add ab...
47
  	/* MMIO access */
362600fe6   Raphael Assenat   [PATCH] Add v3020...
48
49
  	void __iomem *ioaddress;
  	int leftshift;
96615841e   Mike Rapoport   rtc-v3020: add ab...
50
51
  
  	/* GPIO access */
6c95fa80e   Jingoo Han   rtc: rtc-v3020: u...
52
  	struct gpio *gpio;
96615841e   Mike Rapoport   rtc-v3020: add ab...
53

7432a850b   Julia Lawall   rtc: v3020: const...
54
  	const struct v3020_chip_ops *ops;
96615841e   Mike Rapoport   rtc-v3020: add ab...
55

362600fe6   Raphael Assenat   [PATCH] Add v3020...
56
57
  	struct rtc_device *rtc;
  };
96615841e   Mike Rapoport   rtc-v3020: add ab...
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
  
  static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev,
  			  struct v3020_platform_data *pdata)
  {
  	if (pdev->num_resources != 1)
  		return -EBUSY;
  
  	if (pdev->resource[0].flags != IORESOURCE_MEM)
  		return -EBUSY;
  
  	chip->leftshift = pdata->leftshift;
  	chip->ioaddress = ioremap(pdev->resource[0].start, 1);
  	if (chip->ioaddress == NULL)
  		return -EBUSY;
  
  	return 0;
  }
  
  static void v3020_mmio_unmap(struct v3020 *chip)
  {
  	iounmap(chip->ioaddress);
  }
  
  static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit)
  {
  	writel(bit << chip->leftshift, chip->ioaddress);
  }
  
  static unsigned char v3020_mmio_read_bit(struct v3020 *chip)
  {
bcb3a1676   Scott Valentine   rtc: v3020: fix v...
88
  	return !!(readl(chip->ioaddress) & (1 << chip->leftshift));
96615841e   Mike Rapoport   rtc-v3020: add ab...
89
  }
7432a850b   Julia Lawall   rtc: v3020: const...
90
  static const struct v3020_chip_ops v3020_mmio_ops = {
96615841e   Mike Rapoport   rtc-v3020: add ab...
91
92
93
94
95
  	.map_io		= v3020_mmio_map,
  	.unmap_io	= v3020_mmio_unmap,
  	.read_bit	= v3020_mmio_read_bit,
  	.write_bit	= v3020_mmio_write_bit,
  };
6c95fa80e   Jingoo Han   rtc: rtc-v3020: u...
96
97
98
99
100
  static struct gpio v3020_gpio[] = {
  	{ 0, GPIOF_OUT_INIT_HIGH, "RTC CS"},
  	{ 0, GPIOF_OUT_INIT_HIGH, "RTC WR"},
  	{ 0, GPIOF_OUT_INIT_HIGH, "RTC RD"},
  	{ 0, GPIOF_OUT_INIT_HIGH, "RTC IO"},
96615841e   Mike Rapoport   rtc-v3020: add ab...
101
102
103
104
105
  };
  
  static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev,
  			  struct v3020_platform_data *pdata)
  {
6c95fa80e   Jingoo Han   rtc: rtc-v3020: u...
106
  	int err;
96615841e   Mike Rapoport   rtc-v3020: add ab...
107
108
109
110
111
  
  	v3020_gpio[V3020_CS].gpio = pdata->gpio_cs;
  	v3020_gpio[V3020_WR].gpio = pdata->gpio_wr;
  	v3020_gpio[V3020_RD].gpio = pdata->gpio_rd;
  	v3020_gpio[V3020_IO].gpio = pdata->gpio_io;
6c95fa80e   Jingoo Han   rtc: rtc-v3020: u...
112
  	err = gpio_request_array(v3020_gpio, ARRAY_SIZE(v3020_gpio));
96615841e   Mike Rapoport   rtc-v3020: add ab...
113

6c95fa80e   Jingoo Han   rtc: rtc-v3020: u...
114
115
  	if (!err)
  		chip->gpio = v3020_gpio;
96615841e   Mike Rapoport   rtc-v3020: add ab...
116
117
118
119
120
121
  
  	return err;
  }
  
  static void v3020_gpio_unmap(struct v3020 *chip)
  {
6c95fa80e   Jingoo Han   rtc: rtc-v3020: u...
122
  	gpio_free_array(v3020_gpio, ARRAY_SIZE(v3020_gpio));
96615841e   Mike Rapoport   rtc-v3020: add ab...
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
  }
  
  static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit)
  {
  	gpio_direction_output(chip->gpio[V3020_IO].gpio, bit);
  	gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
  	gpio_set_value(chip->gpio[V3020_WR].gpio, 0);
  	udelay(1);
  	gpio_set_value(chip->gpio[V3020_WR].gpio, 1);
  	gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
  }
  
  static unsigned char v3020_gpio_read_bit(struct v3020 *chip)
  {
  	int bit;
  
  	gpio_direction_input(chip->gpio[V3020_IO].gpio);
  	gpio_set_value(chip->gpio[V3020_CS].gpio, 0);
  	gpio_set_value(chip->gpio[V3020_RD].gpio, 0);
  	udelay(1);
  	bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio);
  	udelay(1);
  	gpio_set_value(chip->gpio[V3020_RD].gpio, 1);
  	gpio_set_value(chip->gpio[V3020_CS].gpio, 1);
  
  	return bit;
  }
7432a850b   Julia Lawall   rtc: v3020: const...
150
  static const struct v3020_chip_ops v3020_gpio_ops = {
96615841e   Mike Rapoport   rtc-v3020: add ab...
151
152
153
154
155
  	.map_io		= v3020_gpio_map,
  	.unmap_io	= v3020_gpio_unmap,
  	.read_bit	= v3020_gpio_read_bit,
  	.write_bit	= v3020_gpio_write_bit,
  };
362600fe6   Raphael Assenat   [PATCH] Add v3020...
156
157
158
159
160
161
162
163
  static void v3020_set_reg(struct v3020 *chip, unsigned char address,
  			unsigned char data)
  {
  	int i;
  	unsigned char tmp;
  
  	tmp = address;
  	for (i = 0; i < 4; i++) {
96615841e   Mike Rapoport   rtc-v3020: add ab...
164
  		chip->ops->write_bit(chip, (tmp & 1));
362600fe6   Raphael Assenat   [PATCH] Add v3020...
165
  		tmp >>= 1;
f3d79b20d   Mike Rapoport   RTC v3020 fixes
166
  		udelay(1);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
167
168
169
170
171
  	}
  
  	/* Commands dont have data */
  	if (!V3020_IS_COMMAND(address)) {
  		for (i = 0; i < 8; i++) {
96615841e   Mike Rapoport   rtc-v3020: add ab...
172
  			chip->ops->write_bit(chip, (data & 1));
362600fe6   Raphael Assenat   [PATCH] Add v3020...
173
  			data >>= 1;
f3d79b20d   Mike Rapoport   RTC v3020 fixes
174
  			udelay(1);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
175
176
177
178
179
180
  		}
  	}
  }
  
  static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
  {
c08cf9daf   Mike Rapoport   rtc-v3020: coding...
181
  	unsigned int data = 0;
362600fe6   Raphael Assenat   [PATCH] Add v3020...
182
183
184
  	int i;
  
  	for (i = 0; i < 4; i++) {
96615841e   Mike Rapoport   rtc-v3020: add ab...
185
  		chip->ops->write_bit(chip, (address & 1));
362600fe6   Raphael Assenat   [PATCH] Add v3020...
186
  		address >>= 1;
f3d79b20d   Mike Rapoport   RTC v3020 fixes
187
  		udelay(1);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
188
189
190
191
  	}
  
  	for (i = 0; i < 8; i++) {
  		data >>= 1;
96615841e   Mike Rapoport   rtc-v3020: add ab...
192
  		if (chip->ops->read_bit(chip))
362600fe6   Raphael Assenat   [PATCH] Add v3020...
193
  			data |= 0x80;
f3d79b20d   Mike Rapoport   RTC v3020 fixes
194
  		udelay(1);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  	}
  
  	return data;
  }
  
  static int v3020_read_time(struct device *dev, struct rtc_time *dt)
  {
  	struct v3020 *chip = dev_get_drvdata(dev);
  	int tmp;
  
  	/* Copy the current time to ram... */
  	v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0);
  
  	/* ...and then read constant values. */
  	tmp = v3020_get_reg(chip, V3020_SECONDS);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
210
  	dt->tm_sec	= bcd2bin(tmp);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
211
  	tmp = v3020_get_reg(chip, V3020_MINUTES);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
212
  	dt->tm_min	= bcd2bin(tmp);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
213
  	tmp = v3020_get_reg(chip, V3020_HOURS);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
214
  	dt->tm_hour	= bcd2bin(tmp);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
215
  	tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
216
  	dt->tm_mday	= bcd2bin(tmp);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
217
  	tmp = v3020_get_reg(chip, V3020_MONTH);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
218
  	dt->tm_mon    = bcd2bin(tmp) - 1;
362600fe6   Raphael Assenat   [PATCH] Add v3020...
219
  	tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
220
  	dt->tm_wday	= bcd2bin(tmp);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
221
  	tmp = v3020_get_reg(chip, V3020_YEAR);
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
222
  	dt->tm_year = bcd2bin(tmp)+100;
362600fe6   Raphael Assenat   [PATCH] Add v3020...
223

c08cf9daf   Mike Rapoport   rtc-v3020: coding...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  	dev_dbg(dev, "
  %s : Read RTC values
  ", __func__);
  	dev_dbg(dev, "tm_hour: %i
  ", dt->tm_hour);
  	dev_dbg(dev, "tm_min : %i
  ", dt->tm_min);
  	dev_dbg(dev, "tm_sec : %i
  ", dt->tm_sec);
  	dev_dbg(dev, "tm_year: %i
  ", dt->tm_year);
  	dev_dbg(dev, "tm_mon : %i
  ", dt->tm_mon);
  	dev_dbg(dev, "tm_mday: %i
  ", dt->tm_mday);
  	dev_dbg(dev, "tm_wday: %i
  ", dt->tm_wday);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
241
242
243
244
245
246
247
248
  
  	return 0;
  }
  
  
  static int v3020_set_time(struct device *dev, struct rtc_time *dt)
  {
  	struct v3020 *chip = dev_get_drvdata(dev);
c08cf9daf   Mike Rapoport   rtc-v3020: coding...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  	dev_dbg(dev, "
  %s : Setting RTC values
  ", __func__);
  	dev_dbg(dev, "tm_sec : %i
  ", dt->tm_sec);
  	dev_dbg(dev, "tm_min : %i
  ", dt->tm_min);
  	dev_dbg(dev, "tm_hour: %i
  ", dt->tm_hour);
  	dev_dbg(dev, "tm_mday: %i
  ", dt->tm_mday);
  	dev_dbg(dev, "tm_wday: %i
  ", dt->tm_wday);
  	dev_dbg(dev, "tm_year: %i
  ", dt->tm_year);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
264
265
  
  	/* Write all the values to ram... */
de2edf32f   Sachin Kamat   drivers/rtc/rtc-v...
266
267
268
  	v3020_set_reg(chip, V3020_SECONDS,	bin2bcd(dt->tm_sec));
  	v3020_set_reg(chip, V3020_MINUTES,	bin2bcd(dt->tm_min));
  	v3020_set_reg(chip, V3020_HOURS,	bin2bcd(dt->tm_hour));
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
269
  	v3020_set_reg(chip, V3020_MONTH_DAY,	bin2bcd(dt->tm_mday));
de2edf32f   Sachin Kamat   drivers/rtc/rtc-v...
270
271
272
  	v3020_set_reg(chip, V3020_MONTH,	bin2bcd(dt->tm_mon + 1));
  	v3020_set_reg(chip, V3020_WEEK_DAY,	bin2bcd(dt->tm_wday));
  	v3020_set_reg(chip, V3020_YEAR,		bin2bcd(dt->tm_year % 100));
362600fe6   Raphael Assenat   [PATCH] Add v3020...
273
274
275
276
277
278
279
280
281
282
  
  	/* ...and set the clock. */
  	v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0);
  
  	/* Compulab used this delay here. I dont know why,
  	 * the datasheet does not specify a delay. */
  	/*mdelay(5);*/
  
  	return 0;
  }
ff8371ac9   David Brownell   [PATCH] constify ...
283
  static const struct rtc_class_ops v3020_rtc_ops = {
362600fe6   Raphael Assenat   [PATCH] Add v3020...
284
285
286
287
288
289
  	.read_time	= v3020_read_time,
  	.set_time	= v3020_set_time,
  };
  
  static int rtc_probe(struct platform_device *pdev)
  {
a65ddceba   Jingoo Han   drivers/rtc/rtc-v...
290
  	struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
291
  	struct v3020 *chip;
362600fe6   Raphael Assenat   [PATCH] Add v3020...
292
293
  	int retval = -EBUSY;
  	int i;
362600fe6   Raphael Assenat   [PATCH] Add v3020...
294

431c6c1df   Jingoo Han   rtc: rtc-v3020: u...
295
  	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
296
297
  	if (!chip)
  		return -ENOMEM;
96615841e   Mike Rapoport   rtc-v3020: add ab...
298
299
300
301
302
303
304
  	if (pdata->use_gpio)
  		chip->ops = &v3020_gpio_ops;
  	else
  		chip->ops = &v3020_mmio_ops;
  
  	retval = chip->ops->map_io(chip, pdev, pdata);
  	if (retval)
d8d5290a3   Sachin Kamat   drivers/rtc/rtc-v...
305
  		return retval;
362600fe6   Raphael Assenat   [PATCH] Add v3020...
306
307
308
309
  
  	/* Make sure the v3020 expects a communication cycle
  	 * by reading 8 times */
  	for (i = 0; i < 8; i++)
42397492f   Alexandre Belloni   rtc: v3020: remov...
310
  		chip->ops->read_bit(chip);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
311
312
313
314
  
  	/* Test chip by doing a write/read sequence
  	 * to the chip ram */
  	v3020_set_reg(chip, V3020_SECONDS, 0x33);
c08cf9daf   Mike Rapoport   rtc-v3020: coding...
315
  	if (v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
362600fe6   Raphael Assenat   [PATCH] Add v3020...
316
317
318
  		retval = -ENODEV;
  		goto err_io;
  	}
af901ca18   AndrĂ© Goddard Rosa   tree-wide: fix as...
319
  	/* Make sure frequency measurement mode, test modes, and lock
362600fe6   Raphael Assenat   [PATCH] Add v3020...
320
321
  	 * are all disabled */
  	v3020_set_reg(chip, V3020_STATUS_0, 0x0);
96615841e   Mike Rapoport   rtc-v3020: add ab...
322
323
324
325
326
327
328
329
330
331
332
333
334
  	if (pdata->use_gpio)
  		dev_info(&pdev->dev, "Chip available at GPIOs "
  			 "%d, %d, %d, %d
  ",
  			 chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio,
  			 chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio);
  	else
  		dev_info(&pdev->dev, "Chip available at "
  			 "physical address 0x%llx,"
  			 "data connected to D%d
  ",
  			 (unsigned long long)pdev->resource[0].start,
  			 chip->leftshift);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
335
336
  
  	platform_set_drvdata(pdev, chip);
431c6c1df   Jingoo Han   rtc: rtc-v3020: u...
337
338
  	chip->rtc = devm_rtc_device_register(&pdev->dev, "v3020",
  					&v3020_rtc_ops, THIS_MODULE);
b74d2caa6   Alessandro Zummo   rtc: fix driver d...
339
340
  	if (IS_ERR(chip->rtc)) {
  		retval = PTR_ERR(chip->rtc);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
341
342
  		goto err_io;
  	}
362600fe6   Raphael Assenat   [PATCH] Add v3020...
343
344
345
346
  
  	return 0;
  
  err_io:
96615841e   Mike Rapoport   rtc-v3020: add ab...
347
  	chip->ops->unmap_io(chip);
d8d5290a3   Sachin Kamat   drivers/rtc/rtc-v...
348

362600fe6   Raphael Assenat   [PATCH] Add v3020...
349
350
351
352
353
354
  	return retval;
  }
  
  static int rtc_remove(struct platform_device *dev)
  {
  	struct v3020 *chip = platform_get_drvdata(dev);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
355

96615841e   Mike Rapoport   rtc-v3020: add ab...
356
  	chip->ops->unmap_io(chip);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
357
358
359
360
361
362
363
364
365
  
  	return 0;
  }
  
  static struct platform_driver rtc_device_driver = {
  	.probe	= rtc_probe,
  	.remove = rtc_remove,
  	.driver = {
  		.name	= "v3020",
362600fe6   Raphael Assenat   [PATCH] Add v3020...
366
367
  	},
  };
0c4eae665   Axel Lin   rtc: convert driv...
368
  module_platform_driver(rtc_device_driver);
362600fe6   Raphael Assenat   [PATCH] Add v3020...
369
370
371
372
  
  MODULE_DESCRIPTION("V3020 RTC");
  MODULE_AUTHOR("Raphael Assenat");
  MODULE_LICENSE("GPL");
ad28a07bc   Kay Sievers   rtc: fix platform...
373
  MODULE_ALIAS("platform:v3020");