diff options
author | Uwe Kleine-König <u.kleine-koenig@pengutronix.de> | 2018-05-20 09:37:23 -0400 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@bootlin.com> | 2018-07-11 14:41:22 -0400 |
commit | d6c3029f32f72db7ba7b4183b0423cce2267ca3d (patch) | |
tree | f5d0bea6e73a4a4de1a4292a3c1f07806489f711 | |
parent | cd7f3a249dbed2858e6c2f30e5be7f1f7a709ee2 (diff) |
rtc: pcf2127: add support for accessing internal static RAM
The PCF2127 has 512 bytes of internal static RAM and this patch expands
the driver to access this memory.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
-rw-r--r-- | drivers/rtc/rtc-pcf2127.c | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index e83be1852c2f..9f99a0966550 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c | |||
@@ -36,6 +36,11 @@ | |||
36 | #define PCF2127_REG_MO (0x08) | 36 | #define PCF2127_REG_MO (0x08) |
37 | #define PCF2127_REG_YR (0x09) | 37 | #define PCF2127_REG_YR (0x09) |
38 | 38 | ||
39 | /* the pcf2127 has 512 bytes nvmem, pcf2129 doesn't */ | ||
40 | #define PCF2127_REG_RAM_addr_MSB 0x1a | ||
41 | #define PCF2127_REG_RAM_wrt_cmd 0x1c | ||
42 | #define PCF2127_REG_RAM_rd_cmd 0x1d | ||
43 | |||
39 | #define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ | 44 | #define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ |
40 | 45 | ||
41 | struct pcf2127 { | 46 | struct pcf2127 { |
@@ -183,10 +188,47 @@ static const struct rtc_class_ops pcf2127_rtc_ops = { | |||
183 | .set_time = pcf2127_rtc_set_time, | 188 | .set_time = pcf2127_rtc_set_time, |
184 | }; | 189 | }; |
185 | 190 | ||
191 | static int pcf2127_nvmem_read(void *priv, unsigned int offset, | ||
192 | void *val, size_t bytes) | ||
193 | { | ||
194 | struct pcf2127 *pcf2127 = priv; | ||
195 | int ret; | ||
196 | unsigned char offsetbuf[] = { offset >> 8, offset }; | ||
197 | |||
198 | ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB, | ||
199 | offsetbuf, 2); | ||
200 | if (ret) | ||
201 | return ret; | ||
202 | |||
203 | ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_RAM_rd_cmd, | ||
204 | val, bytes); | ||
205 | |||
206 | return ret ?: bytes; | ||
207 | } | ||
208 | |||
209 | static int pcf2127_nvmem_write(void *priv, unsigned int offset, | ||
210 | void *val, size_t bytes) | ||
211 | { | ||
212 | struct pcf2127 *pcf2127 = priv; | ||
213 | int ret; | ||
214 | unsigned char offsetbuf[] = { offset >> 8, offset }; | ||
215 | |||
216 | ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_addr_MSB, | ||
217 | offsetbuf, 2); | ||
218 | if (ret) | ||
219 | return ret; | ||
220 | |||
221 | ret = regmap_bulk_write(pcf2127->regmap, PCF2127_REG_RAM_wrt_cmd, | ||
222 | val, bytes); | ||
223 | |||
224 | return ret ?: bytes; | ||
225 | } | ||
226 | |||
186 | static int pcf2127_probe(struct device *dev, struct regmap *regmap, | 227 | static int pcf2127_probe(struct device *dev, struct regmap *regmap, |
187 | const char *name) | 228 | const char *name, bool has_nvmem) |
188 | { | 229 | { |
189 | struct pcf2127 *pcf2127; | 230 | struct pcf2127 *pcf2127; |
231 | int ret = 0; | ||
190 | 232 | ||
191 | dev_dbg(dev, "%s\n", __func__); | 233 | dev_dbg(dev, "%s\n", __func__); |
192 | 234 | ||
@@ -200,8 +242,21 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, | |||
200 | 242 | ||
201 | pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops, | 243 | pcf2127->rtc = devm_rtc_device_register(dev, name, &pcf2127_rtc_ops, |
202 | THIS_MODULE); | 244 | THIS_MODULE); |
245 | if (IS_ERR(pcf2127->rtc)) | ||
246 | return PTR_ERR(pcf2127->rtc); | ||
247 | |||
248 | if (has_nvmem) { | ||
249 | struct nvmem_config nvmem_cfg = { | ||
250 | .priv = pcf2127, | ||
251 | .reg_read = pcf2127_nvmem_read, | ||
252 | .reg_write = pcf2127_nvmem_write, | ||
253 | .size = 512, | ||
254 | }; | ||
255 | |||
256 | ret = rtc_nvmem_register(pcf2127->rtc, &nvmem_cfg); | ||
257 | } | ||
203 | 258 | ||
204 | return PTR_ERR_OR_ZERO(pcf2127->rtc); | 259 | return ret; |
205 | } | 260 | } |
206 | 261 | ||
207 | #ifdef CONFIG_OF | 262 | #ifdef CONFIG_OF |
@@ -309,11 +364,11 @@ static int pcf2127_i2c_probe(struct i2c_client *client, | |||
309 | } | 364 | } |
310 | 365 | ||
311 | return pcf2127_probe(&client->dev, regmap, | 366 | return pcf2127_probe(&client->dev, regmap, |
312 | pcf2127_i2c_driver.driver.name); | 367 | pcf2127_i2c_driver.driver.name, id->driver_data); |
313 | } | 368 | } |
314 | 369 | ||
315 | static const struct i2c_device_id pcf2127_i2c_id[] = { | 370 | static const struct i2c_device_id pcf2127_i2c_id[] = { |
316 | { "pcf2127", 0 }, | 371 | { "pcf2127", 1 }, |
317 | { "pcf2129", 0 }, | 372 | { "pcf2129", 0 }, |
318 | { } | 373 | { } |
319 | }; | 374 | }; |
@@ -372,11 +427,12 @@ static int pcf2127_spi_probe(struct spi_device *spi) | |||
372 | return PTR_ERR(regmap); | 427 | return PTR_ERR(regmap); |
373 | } | 428 | } |
374 | 429 | ||
375 | return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name); | 430 | return pcf2127_probe(&spi->dev, regmap, pcf2127_spi_driver.driver.name, |
431 | spi_get_device_id(spi)->driver_data); | ||
376 | } | 432 | } |
377 | 433 | ||
378 | static const struct spi_device_id pcf2127_spi_id[] = { | 434 | static const struct spi_device_id pcf2127_spi_id[] = { |
379 | { "pcf2127", 0 }, | 435 | { "pcf2127", 1 }, |
380 | { "pcf2129", 0 }, | 436 | { "pcf2129", 0 }, |
381 | { } | 437 | { } |
382 | }; | 438 | }; |