rtc-ds2404.c revision 0fae82378ad55a7dfd03f5f6fb092798d8019bc3
1/*
2 * Copyright (C) 2012 Sven Schnelle <svens@stackframe.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9
10#include <linux/platform_device.h>
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/rtc.h>
14#include <linux/types.h>
15#include <linux/bcd.h>
16#include <linux/rtc-ds2404.h>
17#include <linux/delay.h>
18#include <linux/gpio.h>
19#include <linux/slab.h>
20
21#include <linux/io.h>
22
23#define DS2404_STATUS_REG 0x200
24#define DS2404_CONTROL_REG 0x201
25#define DS2404_RTC_REG 0x202
26
27#define DS2404_WRITE_SCRATCHPAD_CMD 0x0f
28#define DS2404_READ_SCRATCHPAD_CMD 0xaa
29#define DS2404_COPY_SCRATCHPAD_CMD 0x55
30#define DS2404_READ_MEMORY_CMD 0xf0
31
32struct ds2404;
33
34struct ds2404_chip_ops {
35	int (*map_io)(struct ds2404 *chip, struct platform_device *pdev,
36		      struct ds2404_platform_data *pdata);
37	void (*unmap_io)(struct ds2404 *chip);
38};
39
40#define DS2404_RST	0
41#define DS2404_CLK	1
42#define DS2404_DQ	2
43
44struct ds2404_gpio {
45	const char *name;
46	unsigned int gpio;
47};
48
49struct ds2404 {
50	struct ds2404_gpio *gpio;
51	struct ds2404_chip_ops *ops;
52	struct rtc_device *rtc;
53};
54
55static struct ds2404_gpio ds2404_gpio[] = {
56	{ "RTC RST", 0 },
57	{ "RTC CLK", 0 },
58	{ "RTC DQ", 0 },
59};
60
61static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev,
62			  struct ds2404_platform_data *pdata)
63{
64	int i, err;
65
66	ds2404_gpio[DS2404_RST].gpio = pdata->gpio_rst;
67	ds2404_gpio[DS2404_CLK].gpio = pdata->gpio_clk;
68	ds2404_gpio[DS2404_DQ].gpio = pdata->gpio_dq;
69
70	for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
71		err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
72		if (err) {
73			dev_err(&pdev->dev, "error mapping gpio %s: %d\n",
74				ds2404_gpio[i].name, err);
75			goto err_request;
76		}
77		if (i != DS2404_DQ)
78			gpio_direction_output(ds2404_gpio[i].gpio, 1);
79	}
80
81	chip->gpio = ds2404_gpio;
82	return 0;
83
84err_request:
85	while (--i >= 0)
86		gpio_free(ds2404_gpio[i].gpio);
87	return err;
88}
89
90static void ds2404_gpio_unmap(struct ds2404 *chip)
91{
92	int i;
93
94	for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++)
95		gpio_free(ds2404_gpio[i].gpio);
96}
97
98static struct ds2404_chip_ops ds2404_gpio_ops = {
99	.map_io		= ds2404_gpio_map,
100	.unmap_io	= ds2404_gpio_unmap,
101};
102
103static void ds2404_reset(struct device *dev)
104{
105	gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0);
106	udelay(1000);
107	gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1);
108	gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
109	gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0);
110	udelay(10);
111}
112
113static void ds2404_write_byte(struct device *dev, u8 byte)
114{
115	int i;
116
117	gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1);
118	for (i = 0; i < 8; i++) {
119		gpio_set_value(ds2404_gpio[DS2404_DQ].gpio, byte & (1 << i));
120		udelay(10);
121		gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
122		udelay(10);
123		gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
124		udelay(10);
125	}
126}
127
128static u8 ds2404_read_byte(struct device *dev)
129{
130	int i;
131	u8 ret = 0;
132
133	gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
134
135	for (i = 0; i < 8; i++) {
136		gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
137		udelay(10);
138		if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
139			ret |= 1 << i;
140		gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
141		udelay(10);
142	}
143	return ret;
144}
145
146static void ds2404_read_memory(struct device *dev, u16 offset,
147			       int length, u8 *out)
148{
149	ds2404_reset(dev);
150	ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD);
151	ds2404_write_byte(dev, offset & 0xff);
152	ds2404_write_byte(dev, (offset >> 8) & 0xff);
153	while (length--)
154		*out++ = ds2404_read_byte(dev);
155}
156
157static void ds2404_write_memory(struct device *dev, u16 offset,
158				int length, u8 *out)
159{
160	int i;
161	u8 ta01, ta02, es;
162
163	ds2404_reset(dev);
164	ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD);
165	ds2404_write_byte(dev, offset & 0xff);
166	ds2404_write_byte(dev, (offset >> 8) & 0xff);
167
168	for (i = 0; i < length; i++)
169		ds2404_write_byte(dev, out[i]);
170
171	ds2404_reset(dev);
172	ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD);
173
174	ta01 = ds2404_read_byte(dev);
175	ta02 = ds2404_read_byte(dev);
176	es = ds2404_read_byte(dev);
177
178	for (i = 0; i < length; i++) {
179		if (out[i] != ds2404_read_byte(dev)) {
180			dev_err(dev, "read invalid data\n");
181			return;
182		}
183	}
184
185	ds2404_reset(dev);
186	ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD);
187	ds2404_write_byte(dev, ta01);
188	ds2404_write_byte(dev, ta02);
189	ds2404_write_byte(dev, es);
190
191	gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
192	while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
193		;
194}
195
196static void ds2404_enable_osc(struct device *dev)
197{
198	u8 in[1] = { 0x10 }; /* enable oscillator */
199	ds2404_write_memory(dev, 0x201, 1, in);
200}
201
202static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
203{
204	unsigned long time = 0;
205
206	ds2404_read_memory(dev, 0x203, 4, (u8 *)&time);
207	time = le32_to_cpu(time);
208
209	rtc_time_to_tm(time, dt);
210	return rtc_valid_tm(dt);
211}
212
213static int ds2404_set_mmss(struct device *dev, unsigned long secs)
214{
215	u32 time = cpu_to_le32(secs);
216	ds2404_write_memory(dev, 0x203, 4, (u8 *)&time);
217	return 0;
218}
219
220static const struct rtc_class_ops ds2404_rtc_ops = {
221	.read_time	= ds2404_read_time,
222	.set_mmss	= ds2404_set_mmss,
223};
224
225static int rtc_probe(struct platform_device *pdev)
226{
227	struct ds2404_platform_data *pdata = pdev->dev.platform_data;
228	struct ds2404 *chip;
229	int retval = -EBUSY;
230
231	chip = kzalloc(sizeof(struct ds2404), GFP_KERNEL);
232	if (!chip)
233		return -ENOMEM;
234
235	chip->ops = &ds2404_gpio_ops;
236
237	retval = chip->ops->map_io(chip, pdev, pdata);
238	if (retval)
239		goto err_chip;
240
241	dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n",
242		 chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio,
243		 chip->gpio[DS2404_DQ].gpio);
244
245	platform_set_drvdata(pdev, chip);
246
247	chip->rtc = rtc_device_register("ds2404",
248				&pdev->dev, &ds2404_rtc_ops, THIS_MODULE);
249	if (IS_ERR(chip->rtc)) {
250		retval = PTR_ERR(chip->rtc);
251		goto err_io;
252	}
253
254	ds2404_enable_osc(&pdev->dev);
255	return 0;
256
257err_io:
258	chip->ops->unmap_io(chip);
259err_chip:
260	kfree(chip);
261	return retval;
262}
263
264static int rtc_remove(struct platform_device *dev)
265{
266	struct ds2404 *chip = platform_get_drvdata(dev);
267	struct rtc_device *rtc = chip->rtc;
268
269	if (rtc)
270		rtc_device_unregister(rtc);
271
272	chip->ops->unmap_io(chip);
273	kfree(chip);
274
275	return 0;
276}
277
278static struct platform_driver rtc_device_driver = {
279	.probe	= rtc_probe,
280	.remove = rtc_remove,
281	.driver = {
282		.name	= "ds2404",
283		.owner	= THIS_MODULE,
284	},
285};
286module_platform_driver(rtc_device_driver);
287
288MODULE_DESCRIPTION("DS2404 RTC");
289MODULE_AUTHOR("Sven Schnelle");
290MODULE_LICENSE("GPL");
291MODULE_ALIAS("platform:ds2404");
292