17418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle/*
27418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle * Copyright (C) 2012 Sven Schnelle <svens@stackframe.org>
37418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle *
47418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle * This program is free software; you can redistribute it and/or modify
57418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle * it under the terms of the GNU General Public License version 2 as
67418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle * published by the Free Software Foundation.
77418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle *
87418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle */
97418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
107418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/platform_device.h>
117418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/module.h>
127418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/init.h>
137418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/rtc.h>
147418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/types.h>
157418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/bcd.h>
167418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/rtc-ds2404.h>
177418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/delay.h>
187418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/gpio.h>
197418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/slab.h>
207418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
217418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#include <linux/io.h>
227418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
237418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_STATUS_REG 0x200
247418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_CONTROL_REG 0x201
257418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_RTC_REG 0x202
267418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
277418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_WRITE_SCRATCHPAD_CMD 0x0f
287418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_READ_SCRATCHPAD_CMD 0xaa
297418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_COPY_SCRATCHPAD_CMD 0x55
307418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_READ_MEMORY_CMD 0xf0
317418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
327418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestruct ds2404;
337418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
347418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestruct ds2404_chip_ops {
357418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	int (*map_io)(struct ds2404 *chip, struct platform_device *pdev,
367418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		      struct ds2404_platform_data *pdata);
377418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	void (*unmap_io)(struct ds2404 *chip);
387418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle};
397418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
407418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_RST	0
417418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_CLK	1
427418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle#define DS2404_DQ	2
437418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
447418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestruct ds2404_gpio {
457418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	const char *name;
467418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	unsigned int gpio;
477418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle};
487418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
497418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestruct ds2404 {
507418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	struct ds2404_gpio *gpio;
517418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	struct ds2404_chip_ops *ops;
527418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	struct rtc_device *rtc;
537418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle};
547418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
557418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic struct ds2404_gpio ds2404_gpio[] = {
567418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	{ "RTC RST", 0 },
577418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	{ "RTC CLK", 0 },
587418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	{ "RTC DQ", 0 },
597418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle};
607418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
617418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev,
627418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle			  struct ds2404_platform_data *pdata)
637418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
647418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	int i, err;
657418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
667418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_gpio[DS2404_RST].gpio = pdata->gpio_rst;
677418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_gpio[DS2404_CLK].gpio = pdata->gpio_clk;
687418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_gpio[DS2404_DQ].gpio = pdata->gpio_dq;
697418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
707418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
717418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
727418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		if (err) {
730fae82378ad55a7dfd03f5f6fb092798d8019bc3Jingoo Han			dev_err(&pdev->dev, "error mapping gpio %s: %d\n",
747418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle				ds2404_gpio[i].name, err);
757418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle			goto err_request;
767418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		}
777418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		if (i != DS2404_DQ)
787418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle			gpio_direction_output(ds2404_gpio[i].gpio, 1);
797418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	}
807418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
817418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	chip->gpio = ds2404_gpio;
827418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	return 0;
837418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
847418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelleerr_request:
857418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	while (--i >= 0)
867418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		gpio_free(ds2404_gpio[i].gpio);
877418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	return err;
887418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
897418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
907418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic void ds2404_gpio_unmap(struct ds2404 *chip)
917418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
927418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	int i;
937418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
947418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++)
957418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		gpio_free(ds2404_gpio[i].gpio);
967418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
977418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
987418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic struct ds2404_chip_ops ds2404_gpio_ops = {
997418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	.map_io		= ds2404_gpio_map,
1007418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	.unmap_io	= ds2404_gpio_unmap,
1017418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle};
1027418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1037418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic void ds2404_reset(struct device *dev)
1047418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
1057418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0);
1067418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	udelay(1000);
1077418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1);
1087418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
1097418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0);
1107418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	udelay(10);
1117418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
1127418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1137418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic void ds2404_write_byte(struct device *dev, u8 byte)
1147418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
1157418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	int i;
1167418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1177418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1);
1187418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	for (i = 0; i < 8; i++) {
1197418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		gpio_set_value(ds2404_gpio[DS2404_DQ].gpio, byte & (1 << i));
1207418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		udelay(10);
1217418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
1227418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		udelay(10);
1237418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
1247418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		udelay(10);
1257418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	}
1267418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
1277418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1287418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic u8 ds2404_read_byte(struct device *dev)
1297418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
1307418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	int i;
1317418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	u8 ret = 0;
1327418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1337418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
1347418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1357418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	for (i = 0; i < 8; i++) {
1367418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
1377418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		udelay(10);
1387418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
1397418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle			ret |= 1 << i;
1407418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
1417418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		udelay(10);
1427418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	}
1437418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	return ret;
1447418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
1457418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1467418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic void ds2404_read_memory(struct device *dev, u16 offset,
1477418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle			       int length, u8 *out)
1487418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
1497418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_reset(dev);
1507418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD);
1517418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, offset & 0xff);
1527418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, (offset >> 8) & 0xff);
1537418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	while (length--)
1547418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		*out++ = ds2404_read_byte(dev);
1557418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
1567418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1577418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic void ds2404_write_memory(struct device *dev, u16 offset,
1587418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle				int length, u8 *out)
1597418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
1607418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	int i;
1617418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	u8 ta01, ta02, es;
1627418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1637418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_reset(dev);
1647418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD);
1657418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, offset & 0xff);
1667418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, (offset >> 8) & 0xff);
1677418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1687418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	for (i = 0; i < length; i++)
1697418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		ds2404_write_byte(dev, out[i]);
1707418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1717418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_reset(dev);
1727418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD);
1737418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1747418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ta01 = ds2404_read_byte(dev);
1757418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ta02 = ds2404_read_byte(dev);
1767418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	es = ds2404_read_byte(dev);
1777418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1787418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	for (i = 0; i < length; i++) {
1797418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		if (out[i] != ds2404_read_byte(dev)) {
1800fae82378ad55a7dfd03f5f6fb092798d8019bc3Jingoo Han			dev_err(dev, "read invalid data\n");
1817418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle			return;
1827418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		}
1837418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	}
1847418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1857418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_reset(dev);
1867418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD);
1877418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, ta01);
1887418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, ta02);
1897418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_byte(dev, es);
1907418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1917418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
1927418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
1937418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		;
1947418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
1957418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
1967418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic void ds2404_enable_osc(struct device *dev)
1977418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
1987418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	u8 in[1] = { 0x10 }; /* enable oscillator */
1997418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_memory(dev, 0x201, 1, in);
2007418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
2017418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2027418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic int ds2404_read_time(struct device *dev, struct rtc_time *dt)
2037418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
2047418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	unsigned long time = 0;
2057418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2067418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_read_memory(dev, 0x203, 4, (u8 *)&time);
2077418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	time = le32_to_cpu(time);
2087418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2097418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	rtc_time_to_tm(time, dt);
2107418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	return rtc_valid_tm(dt);
2117418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
2127418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2137418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic int ds2404_set_mmss(struct device *dev, unsigned long secs)
2147418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
2157418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	u32 time = cpu_to_le32(secs);
2167418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_write_memory(dev, 0x203, 4, (u8 *)&time);
2177418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	return 0;
2187418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
2197418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2207418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic const struct rtc_class_ops ds2404_rtc_ops = {
2217418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	.read_time	= ds2404_read_time,
2227418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	.set_mmss	= ds2404_set_mmss,
2237418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle};
2247418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2257418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic int rtc_probe(struct platform_device *pdev)
2267418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
22777bf38223c0bf51bb303bc074881b403be3c09b4Jingoo Han	struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev);
2287418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	struct ds2404 *chip;
2297418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	int retval = -EBUSY;
2307418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2312a444cf77cb584485aea4f1ee5538a5dee705e99Jingoo Han	chip = devm_kzalloc(&pdev->dev, sizeof(struct ds2404), GFP_KERNEL);
2327418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	if (!chip)
2337418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		return -ENOMEM;
2347418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2357418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	chip->ops = &ds2404_gpio_ops;
2367418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2377418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	retval = chip->ops->map_io(chip, pdev, pdata);
2387418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	if (retval)
2397418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		goto err_chip;
2407418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2417418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n",
2427418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		 chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio,
2437418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		 chip->gpio[DS2404_DQ].gpio);
2447418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2457418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	platform_set_drvdata(pdev, chip);
2467418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2472a444cf77cb584485aea4f1ee5538a5dee705e99Jingoo Han	chip->rtc = devm_rtc_device_register(&pdev->dev, "ds2404",
2482a444cf77cb584485aea4f1ee5538a5dee705e99Jingoo Han					&ds2404_rtc_ops, THIS_MODULE);
2497418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	if (IS_ERR(chip->rtc)) {
2507418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		retval = PTR_ERR(chip->rtc);
2517418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		goto err_io;
2527418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	}
2537418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2547418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	ds2404_enable_osc(&pdev->dev);
2557418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	return 0;
2567418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2577418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelleerr_io:
2587418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	chip->ops->unmap_io(chip);
2597418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelleerr_chip:
2607418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	return retval;
2617418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
2627418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2637418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic int rtc_remove(struct platform_device *dev)
2647418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle{
2657418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	struct ds2404 *chip = platform_get_drvdata(dev);
2667418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2677418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	chip->ops->unmap_io(chip);
2687418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2697418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	return 0;
2707418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle}
2717418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2727418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnellestatic struct platform_driver rtc_device_driver = {
2737418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	.probe	= rtc_probe,
2747418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	.remove = rtc_remove,
2757418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	.driver = {
2767418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		.name	= "ds2404",
2777418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle		.owner	= THIS_MODULE,
2787418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle	},
2797418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle};
28056ae1b8e420015f1428bf9443f1b3321ad789b02Srinivas Kandagatlamodule_platform_driver(rtc_device_driver);
2817418a1198991beb5bf6656b2ac0bcbde378c5539Sven Schnelle
2827418a1198991beb5bf6656b2ac0bcbde378c5539Sven SchnelleMODULE_DESCRIPTION("DS2404 RTC");
2837418a1198991beb5bf6656b2ac0bcbde378c5539Sven SchnelleMODULE_AUTHOR("Sven Schnelle");
2847418a1198991beb5bf6656b2ac0bcbde378c5539Sven SchnelleMODULE_LICENSE("GPL");
2857418a1198991beb5bf6656b2ac0bcbde378c5539Sven SchnelleMODULE_ALIAS("platform:ds2404");
286