Commit | Line | Data |
---|---|---|
362600fe RA |
1 | /* drivers/rtc/rtc-v3020.c |
2 | * | |
3 | * Copyright (C) 2006 8D Technologies inc. | |
4 | * Copyright (C) 2004 Compulab Ltd. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | * Driver for the V3020 RTC | |
11 | * | |
12 | * Changelog: | |
13 | * | |
14 | * 10-May-2006: Raphael Assenat <raph@8d.com> | |
15 | * - Converted to platform driver | |
16 | * - Use the generic rtc class | |
17 | * | |
18 | * ??-???-2004: Someone at Compulab | |
de2edf32 | 19 | * - Initial driver creation. |
362600fe RA |
20 | * |
21 | */ | |
22 | #include <linux/platform_device.h> | |
23 | #include <linux/module.h> | |
24 | #include <linux/init.h> | |
25 | #include <linux/rtc.h> | |
26 | #include <linux/types.h> | |
27 | #include <linux/bcd.h> | |
28 | #include <linux/rtc-v3020.h> | |
f3d79b20 | 29 | #include <linux/delay.h> |
96615841 | 30 | #include <linux/gpio.h> |
5a0e3ad6 | 31 | #include <linux/slab.h> |
362600fe | 32 | |
c08cf9da | 33 | #include <linux/io.h> |
362600fe RA |
34 | |
35 | #undef DEBUG | |
36 | ||
96615841 MR |
37 | struct v3020; |
38 | ||
39 | struct v3020_chip_ops { | |
40 | int (*map_io)(struct v3020 *chip, struct platform_device *pdev, | |
41 | struct v3020_platform_data *pdata); | |
42 | void (*unmap_io)(struct v3020 *chip); | |
43 | unsigned char (*read_bit)(struct v3020 *chip); | |
44 | void (*write_bit)(struct v3020 *chip, unsigned char bit); | |
45 | }; | |
46 | ||
47 | #define V3020_CS 0 | |
48 | #define V3020_WR 1 | |
49 | #define V3020_RD 2 | |
50 | #define V3020_IO 3 | |
51 | ||
362600fe | 52 | struct v3020 { |
96615841 | 53 | /* MMIO access */ |
362600fe RA |
54 | void __iomem *ioaddress; |
55 | int leftshift; | |
96615841 MR |
56 | |
57 | /* GPIO access */ | |
6c95fa80 | 58 | struct gpio *gpio; |
96615841 | 59 | |
7432a850 | 60 | const struct v3020_chip_ops *ops; |
96615841 | 61 | |
362600fe RA |
62 | struct rtc_device *rtc; |
63 | }; | |
64 | ||
96615841 MR |
65 | |
66 | static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev, | |
67 | struct v3020_platform_data *pdata) | |
68 | { | |
69 | if (pdev->num_resources != 1) | |
70 | return -EBUSY; | |
71 | ||
72 | if (pdev->resource[0].flags != IORESOURCE_MEM) | |
73 | return -EBUSY; | |
74 | ||
75 | chip->leftshift = pdata->leftshift; | |
76 | chip->ioaddress = ioremap(pdev->resource[0].start, 1); | |
77 | if (chip->ioaddress == NULL) | |
78 | return -EBUSY; | |
79 | ||
80 | return 0; | |
81 | } | |
82 | ||
83 | static void v3020_mmio_unmap(struct v3020 *chip) | |
84 | { | |
85 | iounmap(chip->ioaddress); | |
86 | } | |
87 | ||
88 | static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit) | |
89 | { | |
90 | writel(bit << chip->leftshift, chip->ioaddress); | |
91 | } | |
92 | ||
93 | static unsigned char v3020_mmio_read_bit(struct v3020 *chip) | |
94 | { | |
bcb3a167 | 95 | return !!(readl(chip->ioaddress) & (1 << chip->leftshift)); |
96615841 MR |
96 | } |
97 | ||
7432a850 | 98 | static const struct v3020_chip_ops v3020_mmio_ops = { |
96615841 MR |
99 | .map_io = v3020_mmio_map, |
100 | .unmap_io = v3020_mmio_unmap, | |
101 | .read_bit = v3020_mmio_read_bit, | |
102 | .write_bit = v3020_mmio_write_bit, | |
103 | }; | |
104 | ||
6c95fa80 JH |
105 | static struct gpio v3020_gpio[] = { |
106 | { 0, GPIOF_OUT_INIT_HIGH, "RTC CS"}, | |
107 | { 0, GPIOF_OUT_INIT_HIGH, "RTC WR"}, | |
108 | { 0, GPIOF_OUT_INIT_HIGH, "RTC RD"}, | |
109 | { 0, GPIOF_OUT_INIT_HIGH, "RTC IO"}, | |
96615841 MR |
110 | }; |
111 | ||
112 | static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev, | |
113 | struct v3020_platform_data *pdata) | |
114 | { | |
6c95fa80 | 115 | int err; |
96615841 MR |
116 | |
117 | v3020_gpio[V3020_CS].gpio = pdata->gpio_cs; | |
118 | v3020_gpio[V3020_WR].gpio = pdata->gpio_wr; | |
119 | v3020_gpio[V3020_RD].gpio = pdata->gpio_rd; | |
120 | v3020_gpio[V3020_IO].gpio = pdata->gpio_io; | |
121 | ||
6c95fa80 | 122 | err = gpio_request_array(v3020_gpio, ARRAY_SIZE(v3020_gpio)); |
96615841 | 123 | |
6c95fa80 JH |
124 | if (!err) |
125 | chip->gpio = v3020_gpio; | |
96615841 MR |
126 | |
127 | return err; | |
128 | } | |
129 | ||
130 | static void v3020_gpio_unmap(struct v3020 *chip) | |
131 | { | |
6c95fa80 | 132 | gpio_free_array(v3020_gpio, ARRAY_SIZE(v3020_gpio)); |
96615841 MR |
133 | } |
134 | ||
135 | static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit) | |
136 | { | |
137 | gpio_direction_output(chip->gpio[V3020_IO].gpio, bit); | |
138 | gpio_set_value(chip->gpio[V3020_CS].gpio, 0); | |
139 | gpio_set_value(chip->gpio[V3020_WR].gpio, 0); | |
140 | udelay(1); | |
141 | gpio_set_value(chip->gpio[V3020_WR].gpio, 1); | |
142 | gpio_set_value(chip->gpio[V3020_CS].gpio, 1); | |
143 | } | |
144 | ||
145 | static unsigned char v3020_gpio_read_bit(struct v3020 *chip) | |
146 | { | |
147 | int bit; | |
148 | ||
149 | gpio_direction_input(chip->gpio[V3020_IO].gpio); | |
150 | gpio_set_value(chip->gpio[V3020_CS].gpio, 0); | |
151 | gpio_set_value(chip->gpio[V3020_RD].gpio, 0); | |
152 | udelay(1); | |
153 | bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio); | |
154 | udelay(1); | |
155 | gpio_set_value(chip->gpio[V3020_RD].gpio, 1); | |
156 | gpio_set_value(chip->gpio[V3020_CS].gpio, 1); | |
157 | ||
158 | return bit; | |
159 | } | |
160 | ||
7432a850 | 161 | static const struct v3020_chip_ops v3020_gpio_ops = { |
96615841 MR |
162 | .map_io = v3020_gpio_map, |
163 | .unmap_io = v3020_gpio_unmap, | |
164 | .read_bit = v3020_gpio_read_bit, | |
165 | .write_bit = v3020_gpio_write_bit, | |
166 | }; | |
167 | ||
362600fe RA |
168 | static void v3020_set_reg(struct v3020 *chip, unsigned char address, |
169 | unsigned char data) | |
170 | { | |
171 | int i; | |
172 | unsigned char tmp; | |
173 | ||
174 | tmp = address; | |
175 | for (i = 0; i < 4; i++) { | |
96615841 | 176 | chip->ops->write_bit(chip, (tmp & 1)); |
362600fe | 177 | tmp >>= 1; |
f3d79b20 | 178 | udelay(1); |
362600fe RA |
179 | } |
180 | ||
181 | /* Commands dont have data */ | |
182 | if (!V3020_IS_COMMAND(address)) { | |
183 | for (i = 0; i < 8; i++) { | |
96615841 | 184 | chip->ops->write_bit(chip, (data & 1)); |
362600fe | 185 | data >>= 1; |
f3d79b20 | 186 | udelay(1); |
362600fe RA |
187 | } |
188 | } | |
189 | } | |
190 | ||
191 | static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address) | |
192 | { | |
c08cf9da | 193 | unsigned int data = 0; |
362600fe RA |
194 | int i; |
195 | ||
196 | for (i = 0; i < 4; i++) { | |
96615841 | 197 | chip->ops->write_bit(chip, (address & 1)); |
362600fe | 198 | address >>= 1; |
f3d79b20 | 199 | udelay(1); |
362600fe RA |
200 | } |
201 | ||
202 | for (i = 0; i < 8; i++) { | |
203 | data >>= 1; | |
96615841 | 204 | if (chip->ops->read_bit(chip)) |
362600fe | 205 | data |= 0x80; |
f3d79b20 | 206 | udelay(1); |
362600fe RA |
207 | } |
208 | ||
209 | return data; | |
210 | } | |
211 | ||
212 | static int v3020_read_time(struct device *dev, struct rtc_time *dt) | |
213 | { | |
214 | struct v3020 *chip = dev_get_drvdata(dev); | |
215 | int tmp; | |
216 | ||
217 | /* Copy the current time to ram... */ | |
218 | v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0); | |
219 | ||
220 | /* ...and then read constant values. */ | |
221 | tmp = v3020_get_reg(chip, V3020_SECONDS); | |
fe20ba70 | 222 | dt->tm_sec = bcd2bin(tmp); |
362600fe | 223 | tmp = v3020_get_reg(chip, V3020_MINUTES); |
fe20ba70 | 224 | dt->tm_min = bcd2bin(tmp); |
362600fe | 225 | tmp = v3020_get_reg(chip, V3020_HOURS); |
fe20ba70 | 226 | dt->tm_hour = bcd2bin(tmp); |
362600fe | 227 | tmp = v3020_get_reg(chip, V3020_MONTH_DAY); |
fe20ba70 | 228 | dt->tm_mday = bcd2bin(tmp); |
362600fe | 229 | tmp = v3020_get_reg(chip, V3020_MONTH); |
fe20ba70 | 230 | dt->tm_mon = bcd2bin(tmp) - 1; |
362600fe | 231 | tmp = v3020_get_reg(chip, V3020_WEEK_DAY); |
fe20ba70 | 232 | dt->tm_wday = bcd2bin(tmp); |
362600fe | 233 | tmp = v3020_get_reg(chip, V3020_YEAR); |
fe20ba70 | 234 | dt->tm_year = bcd2bin(tmp)+100; |
362600fe | 235 | |
c08cf9da MR |
236 | dev_dbg(dev, "\n%s : Read RTC values\n", __func__); |
237 | dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); | |
238 | dev_dbg(dev, "tm_min : %i\n", dt->tm_min); | |
239 | dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); | |
240 | dev_dbg(dev, "tm_year: %i\n", dt->tm_year); | |
241 | dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); | |
242 | dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); | |
243 | dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); | |
362600fe RA |
244 | |
245 | return 0; | |
246 | } | |
247 | ||
248 | ||
249 | static int v3020_set_time(struct device *dev, struct rtc_time *dt) | |
250 | { | |
251 | struct v3020 *chip = dev_get_drvdata(dev); | |
252 | ||
c08cf9da MR |
253 | dev_dbg(dev, "\n%s : Setting RTC values\n", __func__); |
254 | dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); | |
255 | dev_dbg(dev, "tm_min : %i\n", dt->tm_min); | |
256 | dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); | |
257 | dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); | |
258 | dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); | |
259 | dev_dbg(dev, "tm_year: %i\n", dt->tm_year); | |
362600fe RA |
260 | |
261 | /* Write all the values to ram... */ | |
de2edf32 SK |
262 | v3020_set_reg(chip, V3020_SECONDS, bin2bcd(dt->tm_sec)); |
263 | v3020_set_reg(chip, V3020_MINUTES, bin2bcd(dt->tm_min)); | |
264 | v3020_set_reg(chip, V3020_HOURS, bin2bcd(dt->tm_hour)); | |
fe20ba70 | 265 | v3020_set_reg(chip, V3020_MONTH_DAY, bin2bcd(dt->tm_mday)); |
de2edf32 SK |
266 | v3020_set_reg(chip, V3020_MONTH, bin2bcd(dt->tm_mon + 1)); |
267 | v3020_set_reg(chip, V3020_WEEK_DAY, bin2bcd(dt->tm_wday)); | |
268 | v3020_set_reg(chip, V3020_YEAR, bin2bcd(dt->tm_year % 100)); | |
362600fe RA |
269 | |
270 | /* ...and set the clock. */ | |
271 | v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0); | |
272 | ||
273 | /* Compulab used this delay here. I dont know why, | |
274 | * the datasheet does not specify a delay. */ | |
275 | /*mdelay(5);*/ | |
276 | ||
277 | return 0; | |
278 | } | |
279 | ||
ff8371ac | 280 | static const struct rtc_class_ops v3020_rtc_ops = { |
362600fe RA |
281 | .read_time = v3020_read_time, |
282 | .set_time = v3020_set_time, | |
283 | }; | |
284 | ||
285 | static int rtc_probe(struct platform_device *pdev) | |
286 | { | |
a65ddceb | 287 | struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev); |
362600fe | 288 | struct v3020 *chip; |
362600fe RA |
289 | int retval = -EBUSY; |
290 | int i; | |
291 | int temp; | |
292 | ||
431c6c1d | 293 | chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); |
362600fe RA |
294 | if (!chip) |
295 | return -ENOMEM; | |
296 | ||
96615841 MR |
297 | if (pdata->use_gpio) |
298 | chip->ops = &v3020_gpio_ops; | |
299 | else | |
300 | chip->ops = &v3020_mmio_ops; | |
301 | ||
302 | retval = chip->ops->map_io(chip, pdev, pdata); | |
303 | if (retval) | |
d8d5290a | 304 | return retval; |
362600fe RA |
305 | |
306 | /* Make sure the v3020 expects a communication cycle | |
307 | * by reading 8 times */ | |
308 | for (i = 0; i < 8; i++) | |
96615841 | 309 | temp = chip->ops->read_bit(chip); |
362600fe RA |
310 | |
311 | /* Test chip by doing a write/read sequence | |
312 | * to the chip ram */ | |
313 | v3020_set_reg(chip, V3020_SECONDS, 0x33); | |
c08cf9da | 314 | if (v3020_get_reg(chip, V3020_SECONDS) != 0x33) { |
362600fe RA |
315 | retval = -ENODEV; |
316 | goto err_io; | |
317 | } | |
318 | ||
af901ca1 | 319 | /* Make sure frequency measurement mode, test modes, and lock |
362600fe RA |
320 | * are all disabled */ |
321 | v3020_set_reg(chip, V3020_STATUS_0, 0x0); | |
322 | ||
96615841 MR |
323 | if (pdata->use_gpio) |
324 | dev_info(&pdev->dev, "Chip available at GPIOs " | |
325 | "%d, %d, %d, %d\n", | |
326 | chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio, | |
327 | chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio); | |
328 | else | |
329 | dev_info(&pdev->dev, "Chip available at " | |
330 | "physical address 0x%llx," | |
331 | "data connected to D%d\n", | |
332 | (unsigned long long)pdev->resource[0].start, | |
333 | chip->leftshift); | |
362600fe RA |
334 | |
335 | platform_set_drvdata(pdev, chip); | |
336 | ||
431c6c1d JH |
337 | chip->rtc = devm_rtc_device_register(&pdev->dev, "v3020", |
338 | &v3020_rtc_ops, THIS_MODULE); | |
b74d2caa AZ |
339 | if (IS_ERR(chip->rtc)) { |
340 | retval = PTR_ERR(chip->rtc); | |
362600fe RA |
341 | goto err_io; |
342 | } | |
362600fe RA |
343 | |
344 | return 0; | |
345 | ||
346 | err_io: | |
96615841 | 347 | chip->ops->unmap_io(chip); |
d8d5290a | 348 | |
362600fe RA |
349 | return retval; |
350 | } | |
351 | ||
352 | static int rtc_remove(struct platform_device *dev) | |
353 | { | |
354 | struct v3020 *chip = platform_get_drvdata(dev); | |
362600fe | 355 | |
96615841 | 356 | chip->ops->unmap_io(chip); |
362600fe RA |
357 | |
358 | return 0; | |
359 | } | |
360 | ||
361 | static struct platform_driver rtc_device_driver = { | |
362 | .probe = rtc_probe, | |
363 | .remove = rtc_remove, | |
364 | .driver = { | |
365 | .name = "v3020", | |
362600fe RA |
366 | }, |
367 | }; | |
368 | ||
0c4eae66 | 369 | module_platform_driver(rtc_device_driver); |
362600fe RA |
370 | |
371 | MODULE_DESCRIPTION("V3020 RTC"); | |
372 | MODULE_AUTHOR("Raphael Assenat"); | |
373 | MODULE_LICENSE("GPL"); | |
ad28a07b | 374 | MODULE_ALIAS("platform:v3020"); |