at master 5.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (C) 2012 Sven Schnelle <svens@stackframe.org> 3 4#include <linux/platform_device.h> 5#include <linux/module.h> 6#include <linux/init.h> 7#include <linux/rtc.h> 8#include <linux/types.h> 9#include <linux/bcd.h> 10#include <linux/delay.h> 11#include <linux/gpio/consumer.h> 12#include <linux/slab.h> 13 14#include <linux/io.h> 15 16#define DS2404_STATUS_REG 0x200 17#define DS2404_CONTROL_REG 0x201 18#define DS2404_RTC_REG 0x202 19 20#define DS2404_WRITE_SCRATCHPAD_CMD 0x0f 21#define DS2404_READ_SCRATCHPAD_CMD 0xaa 22#define DS2404_COPY_SCRATCHPAD_CMD 0x55 23#define DS2404_READ_MEMORY_CMD 0xf0 24 25#define DS2404_RST 0 26#define DS2404_CLK 1 27#define DS2404_DQ 2 28 29struct ds2404 { 30 struct device *dev; 31 struct gpio_desc *rst_gpiod; 32 struct gpio_desc *clk_gpiod; 33 struct gpio_desc *dq_gpiod; 34}; 35 36static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev) 37{ 38 struct device *dev = &pdev->dev; 39 40 /* This will de-assert RESET, declare this GPIO as GPIOD_ACTIVE_LOW */ 41 chip->rst_gpiod = devm_gpiod_get(dev, "rst", GPIOD_OUT_LOW); 42 if (IS_ERR(chip->rst_gpiod)) 43 return PTR_ERR(chip->rst_gpiod); 44 45 chip->clk_gpiod = devm_gpiod_get(dev, "clk", GPIOD_OUT_HIGH); 46 if (IS_ERR(chip->clk_gpiod)) 47 return PTR_ERR(chip->clk_gpiod); 48 49 chip->dq_gpiod = devm_gpiod_get(dev, "dq", GPIOD_ASIS); 50 if (IS_ERR(chip->dq_gpiod)) 51 return PTR_ERR(chip->dq_gpiod); 52 53 return 0; 54} 55 56static void ds2404_reset(struct ds2404 *chip) 57{ 58 gpiod_set_value(chip->rst_gpiod, 1); 59 udelay(1000); 60 gpiod_set_value(chip->rst_gpiod, 0); 61 gpiod_set_value(chip->clk_gpiod, 0); 62 gpiod_direction_output(chip->dq_gpiod, 0); 63 udelay(10); 64} 65 66static void ds2404_write_byte(struct ds2404 *chip, u8 byte) 67{ 68 int i; 69 70 gpiod_direction_output(chip->dq_gpiod, 1); 71 for (i = 0; i < 8; i++) { 72 gpiod_set_value(chip->dq_gpiod, byte & (1 << i)); 73 udelay(10); 74 gpiod_set_value(chip->clk_gpiod, 1); 75 udelay(10); 76 gpiod_set_value(chip->clk_gpiod, 0); 77 udelay(10); 78 } 79} 80 81static u8 ds2404_read_byte(struct ds2404 *chip) 82{ 83 int i; 84 u8 ret = 0; 85 86 gpiod_direction_input(chip->dq_gpiod); 87 88 for (i = 0; i < 8; i++) { 89 gpiod_set_value(chip->clk_gpiod, 0); 90 udelay(10); 91 if (gpiod_get_value(chip->dq_gpiod)) 92 ret |= 1 << i; 93 gpiod_set_value(chip->clk_gpiod, 1); 94 udelay(10); 95 } 96 return ret; 97} 98 99static void ds2404_read_memory(struct ds2404 *chip, u16 offset, 100 int length, u8 *out) 101{ 102 ds2404_reset(chip); 103 ds2404_write_byte(chip, DS2404_READ_MEMORY_CMD); 104 ds2404_write_byte(chip, offset & 0xff); 105 ds2404_write_byte(chip, (offset >> 8) & 0xff); 106 while (length--) 107 *out++ = ds2404_read_byte(chip); 108} 109 110static void ds2404_write_memory(struct ds2404 *chip, u16 offset, 111 int length, u8 *out) 112{ 113 int i; 114 u8 ta01, ta02, es; 115 116 ds2404_reset(chip); 117 ds2404_write_byte(chip, DS2404_WRITE_SCRATCHPAD_CMD); 118 ds2404_write_byte(chip, offset & 0xff); 119 ds2404_write_byte(chip, (offset >> 8) & 0xff); 120 121 for (i = 0; i < length; i++) 122 ds2404_write_byte(chip, out[i]); 123 124 ds2404_reset(chip); 125 ds2404_write_byte(chip, DS2404_READ_SCRATCHPAD_CMD); 126 127 ta01 = ds2404_read_byte(chip); 128 ta02 = ds2404_read_byte(chip); 129 es = ds2404_read_byte(chip); 130 131 for (i = 0; i < length; i++) { 132 if (out[i] != ds2404_read_byte(chip)) { 133 dev_err(chip->dev, "read invalid data\n"); 134 return; 135 } 136 } 137 138 ds2404_reset(chip); 139 ds2404_write_byte(chip, DS2404_COPY_SCRATCHPAD_CMD); 140 ds2404_write_byte(chip, ta01); 141 ds2404_write_byte(chip, ta02); 142 ds2404_write_byte(chip, es); 143 144 while (gpiod_get_value(chip->dq_gpiod)) 145 ; 146} 147 148static void ds2404_enable_osc(struct ds2404 *chip) 149{ 150 u8 in[1] = { 0x10 }; /* enable oscillator */ 151 152 ds2404_write_memory(chip, 0x201, 1, in); 153} 154 155static int ds2404_read_time(struct device *dev, struct rtc_time *dt) 156{ 157 struct ds2404 *chip = dev_get_drvdata(dev); 158 unsigned long time = 0; 159 __le32 hw_time = 0; 160 161 ds2404_read_memory(chip, 0x203, 4, (u8 *)&hw_time); 162 time = le32_to_cpu(hw_time); 163 164 rtc_time64_to_tm(time, dt); 165 return 0; 166} 167 168static int ds2404_set_time(struct device *dev, struct rtc_time *dt) 169{ 170 struct ds2404 *chip = dev_get_drvdata(dev); 171 u32 time = cpu_to_le32(rtc_tm_to_time64(dt)); 172 ds2404_write_memory(chip, 0x203, 4, (u8 *)&time); 173 return 0; 174} 175 176static const struct rtc_class_ops ds2404_rtc_ops = { 177 .read_time = ds2404_read_time, 178 .set_time = ds2404_set_time, 179}; 180 181static int rtc_probe(struct platform_device *pdev) 182{ 183 struct ds2404 *chip; 184 struct rtc_device *rtc; 185 int retval = -EBUSY; 186 187 chip = devm_kzalloc(&pdev->dev, sizeof(struct ds2404), GFP_KERNEL); 188 if (!chip) 189 return -ENOMEM; 190 191 chip->dev = &pdev->dev; 192 193 rtc = devm_rtc_allocate_device(&pdev->dev); 194 if (IS_ERR(rtc)) 195 return PTR_ERR(rtc); 196 197 retval = ds2404_gpio_map(chip, pdev); 198 if (retval) 199 return retval; 200 201 platform_set_drvdata(pdev, chip); 202 203 rtc->ops = &ds2404_rtc_ops; 204 rtc->range_max = U32_MAX; 205 206 retval = devm_rtc_register_device(rtc); 207 if (retval) 208 return retval; 209 210 ds2404_enable_osc(chip); 211 return 0; 212} 213 214static struct platform_driver rtc_device_driver = { 215 .probe = rtc_probe, 216 .driver = { 217 .name = "ds2404", 218 }, 219}; 220module_platform_driver(rtc_device_driver); 221 222MODULE_DESCRIPTION("DS2404 RTC"); 223MODULE_AUTHOR("Sven Schnelle"); 224MODULE_LICENSE("GPL"); 225MODULE_ALIAS("platform:ds2404");