.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * An I2C driver for the Epson RX8581 RTC |
---|
3 | 4 | * |
---|
4 | 5 | * Author: Martyn Welch <martyn.welch@ge.com> |
---|
5 | 6 | * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License version 2 as |
---|
9 | | - * published by the Free Software Foundation. |
---|
10 | 7 | * |
---|
11 | 8 | * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC) |
---|
12 | 9 | * Copyright 2005-06 Tower Technologies |
---|
.. | .. |
---|
15 | 12 | #include <linux/module.h> |
---|
16 | 13 | #include <linux/i2c.h> |
---|
17 | 14 | #include <linux/bcd.h> |
---|
| 15 | +#include <linux/of.h> |
---|
| 16 | +#include <linux/of_device.h> |
---|
18 | 17 | #include <linux/regmap.h> |
---|
19 | 18 | #include <linux/rtc.h> |
---|
20 | 19 | #include <linux/log2.h> |
---|
.. | .. |
---|
51 | 50 | #define RX8581_CTRL_STOP 0x02 /* STOP bit */ |
---|
52 | 51 | #define RX8581_CTRL_RESET 0x01 /* RESET bit */ |
---|
53 | 52 | |
---|
| 53 | +#define RX8571_USER_RAM 0x10 |
---|
| 54 | +#define RX8571_NVRAM_SIZE 0x10 |
---|
| 55 | + |
---|
54 | 56 | struct rx8581 { |
---|
55 | 57 | struct regmap *regmap; |
---|
56 | 58 | struct rtc_device *rtc; |
---|
| 59 | +}; |
---|
| 60 | + |
---|
| 61 | +struct rx85x1_config { |
---|
| 62 | + struct regmap_config regmap; |
---|
| 63 | + unsigned int num_nvram; |
---|
57 | 64 | }; |
---|
58 | 65 | |
---|
59 | 66 | /* |
---|
.. | .. |
---|
181 | 188 | .set_time = rx8581_rtc_set_time, |
---|
182 | 189 | }; |
---|
183 | 190 | |
---|
184 | | -static int rx8581_probe(struct i2c_client *client, |
---|
185 | | - const struct i2c_device_id *id) |
---|
| 191 | +static int rx8571_nvram_read(void *priv, unsigned int offset, void *val, |
---|
| 192 | + size_t bytes) |
---|
186 | 193 | { |
---|
187 | | - struct rx8581 *rx8581; |
---|
188 | | - static const struct regmap_config config = { |
---|
| 194 | + struct rx8581 *rx8581 = priv; |
---|
| 195 | + |
---|
| 196 | + return regmap_bulk_read(rx8581->regmap, RX8571_USER_RAM + offset, |
---|
| 197 | + val, bytes); |
---|
| 198 | +} |
---|
| 199 | + |
---|
| 200 | +static int rx8571_nvram_write(void *priv, unsigned int offset, void *val, |
---|
| 201 | + size_t bytes) |
---|
| 202 | +{ |
---|
| 203 | + struct rx8581 *rx8581 = priv; |
---|
| 204 | + |
---|
| 205 | + return regmap_bulk_write(rx8581->regmap, RX8571_USER_RAM + offset, |
---|
| 206 | + val, bytes); |
---|
| 207 | +} |
---|
| 208 | + |
---|
| 209 | +static int rx85x1_nvram_read(void *priv, unsigned int offset, void *val, |
---|
| 210 | + size_t bytes) |
---|
| 211 | +{ |
---|
| 212 | + struct rx8581 *rx8581 = priv; |
---|
| 213 | + unsigned int tmp_val; |
---|
| 214 | + int ret; |
---|
| 215 | + |
---|
| 216 | + ret = regmap_read(rx8581->regmap, RX8581_REG_RAM, &tmp_val); |
---|
| 217 | + (*(unsigned char *)val) = (unsigned char) tmp_val; |
---|
| 218 | + |
---|
| 219 | + return ret; |
---|
| 220 | +} |
---|
| 221 | + |
---|
| 222 | +static int rx85x1_nvram_write(void *priv, unsigned int offset, void *val, |
---|
| 223 | + size_t bytes) |
---|
| 224 | +{ |
---|
| 225 | + struct rx8581 *rx8581 = priv; |
---|
| 226 | + unsigned char tmp_val; |
---|
| 227 | + |
---|
| 228 | + tmp_val = *((unsigned char *)val); |
---|
| 229 | + return regmap_write(rx8581->regmap, RX8581_REG_RAM, |
---|
| 230 | + (unsigned int)tmp_val); |
---|
| 231 | +} |
---|
| 232 | + |
---|
| 233 | +static const struct rx85x1_config rx8581_config = { |
---|
| 234 | + .regmap = { |
---|
189 | 235 | .reg_bits = 8, |
---|
190 | 236 | .val_bits = 8, |
---|
191 | 237 | .max_register = 0xf, |
---|
| 238 | + }, |
---|
| 239 | + .num_nvram = 1 |
---|
| 240 | +}; |
---|
| 241 | + |
---|
| 242 | +static const struct rx85x1_config rx8571_config = { |
---|
| 243 | + .regmap = { |
---|
| 244 | + .reg_bits = 8, |
---|
| 245 | + .val_bits = 8, |
---|
| 246 | + .max_register = 0x1f, |
---|
| 247 | + }, |
---|
| 248 | + .num_nvram = 2 |
---|
| 249 | +}; |
---|
| 250 | + |
---|
| 251 | +static int rx8581_probe(struct i2c_client *client, |
---|
| 252 | + const struct i2c_device_id *id) |
---|
| 253 | +{ |
---|
| 254 | + struct rx8581 *rx8581; |
---|
| 255 | + const struct rx85x1_config *config = &rx8581_config; |
---|
| 256 | + const void *data = of_device_get_match_data(&client->dev); |
---|
| 257 | + static struct nvmem_config nvmem_cfg[] = { |
---|
| 258 | + { |
---|
| 259 | + .name = "rx85x1-", |
---|
| 260 | + .word_size = 1, |
---|
| 261 | + .stride = 1, |
---|
| 262 | + .size = 1, |
---|
| 263 | + .reg_read = rx85x1_nvram_read, |
---|
| 264 | + .reg_write = rx85x1_nvram_write, |
---|
| 265 | + }, { |
---|
| 266 | + .name = "rx8571-", |
---|
| 267 | + .word_size = 1, |
---|
| 268 | + .stride = 1, |
---|
| 269 | + .size = RX8571_NVRAM_SIZE, |
---|
| 270 | + .reg_read = rx8571_nvram_read, |
---|
| 271 | + .reg_write = rx8571_nvram_write, |
---|
| 272 | + }, |
---|
192 | 273 | }; |
---|
| 274 | + int ret, i; |
---|
193 | 275 | |
---|
194 | 276 | dev_dbg(&client->dev, "%s\n", __func__); |
---|
| 277 | + |
---|
| 278 | + if (data) |
---|
| 279 | + config = data; |
---|
195 | 280 | |
---|
196 | 281 | rx8581 = devm_kzalloc(&client->dev, sizeof(struct rx8581), GFP_KERNEL); |
---|
197 | 282 | if (!rx8581) |
---|
.. | .. |
---|
199 | 284 | |
---|
200 | 285 | i2c_set_clientdata(client, rx8581); |
---|
201 | 286 | |
---|
202 | | - rx8581->regmap = devm_regmap_init_i2c(client, &config); |
---|
| 287 | + rx8581->regmap = devm_regmap_init_i2c(client, &config->regmap); |
---|
203 | 288 | if (IS_ERR(rx8581->regmap)) |
---|
204 | 289 | return PTR_ERR(rx8581->regmap); |
---|
205 | 290 | |
---|
.. | .. |
---|
213 | 298 | rx8581->rtc->start_secs = 0; |
---|
214 | 299 | rx8581->rtc->set_start_time = true; |
---|
215 | 300 | |
---|
216 | | - return rtc_register_device(rx8581->rtc); |
---|
| 301 | + ret = rtc_register_device(rx8581->rtc); |
---|
| 302 | + |
---|
| 303 | + for (i = 0; i < config->num_nvram; i++) { |
---|
| 304 | + nvmem_cfg[i].priv = rx8581; |
---|
| 305 | + rtc_nvmem_register(rx8581->rtc, &nvmem_cfg[i]); |
---|
| 306 | + } |
---|
| 307 | + |
---|
| 308 | + return ret; |
---|
217 | 309 | } |
---|
218 | 310 | |
---|
219 | 311 | static const struct i2c_device_id rx8581_id[] = { |
---|
.. | .. |
---|
223 | 315 | MODULE_DEVICE_TABLE(i2c, rx8581_id); |
---|
224 | 316 | |
---|
225 | 317 | static const struct of_device_id rx8581_of_match[] = { |
---|
226 | | - { .compatible = "epson,rx8581" }, |
---|
227 | | - { } |
---|
| 318 | + { .compatible = "epson,rx8571", .data = &rx8571_config }, |
---|
| 319 | + { .compatible = "epson,rx8581", .data = &rx8581_config }, |
---|
| 320 | + { /* sentinel */ } |
---|
228 | 321 | }; |
---|
229 | 322 | MODULE_DEVICE_TABLE(of, rx8581_of_match); |
---|
230 | 323 | |
---|
.. | .. |
---|
240 | 333 | module_i2c_driver(rx8581_driver); |
---|
241 | 334 | |
---|
242 | 335 | MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>"); |
---|
243 | | -MODULE_DESCRIPTION("Epson RX-8581 RTC driver"); |
---|
| 336 | +MODULE_DESCRIPTION("Epson RX-8571/RX-8581 RTC driver"); |
---|
244 | 337 | MODULE_LICENSE("GPL"); |
---|