1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2f803f0d0SThierry Reding /* 3f803f0d0SThierry Reding * Copyright (C) 2012 Avionic Design GmbH 4f803f0d0SThierry Reding */ 5f803f0d0SThierry Reding 6f803f0d0SThierry Reding #include <linux/bcd.h> 7f803f0d0SThierry Reding #include <linux/i2c.h> 8f803f0d0SThierry Reding #include <linux/module.h> 9f803f0d0SThierry Reding #include <linux/rtc.h> 10f803f0d0SThierry Reding #include <linux/of.h> 11f803f0d0SThierry Reding 12f803f0d0SThierry Reding #define DRIVER_NAME "rtc-pcf8523" 13f803f0d0SThierry Reding 14f803f0d0SThierry Reding #define REG_CONTROL1 0x00 15f803f0d0SThierry Reding #define REG_CONTROL1_CAP_SEL (1 << 7) 16f803f0d0SThierry Reding #define REG_CONTROL1_STOP (1 << 5) 17f803f0d0SThierry Reding 18f803f0d0SThierry Reding #define REG_CONTROL3 0x02 19f803f0d0SThierry Reding #define REG_CONTROL3_PM_BLD (1 << 7) /* battery low detection disabled */ 20f803f0d0SThierry Reding #define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */ 21f803f0d0SThierry Reding #define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */ 22f803f0d0SThierry Reding #define REG_CONTROL3_PM_MASK 0xe0 23f32bc70dSJesper Nilsson #define REG_CONTROL3_BLF (1 << 2) /* battery low bit, read-only */ 24f803f0d0SThierry Reding 25f803f0d0SThierry Reding #define REG_SECONDS 0x03 26f803f0d0SThierry Reding #define REG_SECONDS_OS (1 << 7) 27f803f0d0SThierry Reding 28f803f0d0SThierry Reding #define REG_MINUTES 0x04 29f803f0d0SThierry Reding #define REG_HOURS 0x05 30f803f0d0SThierry Reding #define REG_DAYS 0x06 31f803f0d0SThierry Reding #define REG_WEEKDAYS 0x07 32f803f0d0SThierry Reding #define REG_MONTHS 0x08 33f803f0d0SThierry Reding #define REG_YEARS 0x09 34f803f0d0SThierry Reding 35bc3bee02SRussell King #define REG_OFFSET 0x0e 36bc3bee02SRussell King #define REG_OFFSET_MODE BIT(7) 37bc3bee02SRussell King 38f803f0d0SThierry Reding static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep) 39f803f0d0SThierry Reding { 40f803f0d0SThierry Reding struct i2c_msg msgs[2]; 41f803f0d0SThierry Reding u8 value = 0; 42f803f0d0SThierry Reding int err; 43f803f0d0SThierry Reding 44f803f0d0SThierry Reding msgs[0].addr = client->addr; 45f803f0d0SThierry Reding msgs[0].flags = 0; 46f803f0d0SThierry Reding msgs[0].len = sizeof(reg); 47f803f0d0SThierry Reding msgs[0].buf = ® 48f803f0d0SThierry Reding 49f803f0d0SThierry Reding msgs[1].addr = client->addr; 50f803f0d0SThierry Reding msgs[1].flags = I2C_M_RD; 51f803f0d0SThierry Reding msgs[1].len = sizeof(value); 52f803f0d0SThierry Reding msgs[1].buf = &value; 53f803f0d0SThierry Reding 54f803f0d0SThierry Reding err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 55f803f0d0SThierry Reding if (err < 0) 56f803f0d0SThierry Reding return err; 57f803f0d0SThierry Reding 58f803f0d0SThierry Reding *valuep = value; 59f803f0d0SThierry Reding 60f803f0d0SThierry Reding return 0; 61f803f0d0SThierry Reding } 62f803f0d0SThierry Reding 63f803f0d0SThierry Reding static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) 64f803f0d0SThierry Reding { 65f803f0d0SThierry Reding u8 buffer[2] = { reg, value }; 66f803f0d0SThierry Reding struct i2c_msg msg; 67f803f0d0SThierry Reding int err; 68f803f0d0SThierry Reding 69f803f0d0SThierry Reding msg.addr = client->addr; 70f803f0d0SThierry Reding msg.flags = 0; 71f803f0d0SThierry Reding msg.len = sizeof(buffer); 72f803f0d0SThierry Reding msg.buf = buffer; 73f803f0d0SThierry Reding 74f803f0d0SThierry Reding err = i2c_transfer(client->adapter, &msg, 1); 75f803f0d0SThierry Reding if (err < 0) 76f803f0d0SThierry Reding return err; 77f803f0d0SThierry Reding 78f803f0d0SThierry Reding return 0; 79f803f0d0SThierry Reding } 80f803f0d0SThierry Reding 81ecb4a353SBaruch Siach static int pcf8523_voltage_low(struct i2c_client *client) 82ecb4a353SBaruch Siach { 83ecb4a353SBaruch Siach u8 value; 84ecb4a353SBaruch Siach int err; 85ecb4a353SBaruch Siach 86ecb4a353SBaruch Siach err = pcf8523_read(client, REG_CONTROL3, &value); 87ecb4a353SBaruch Siach if (err < 0) 88ecb4a353SBaruch Siach return err; 89ecb4a353SBaruch Siach 90ecb4a353SBaruch Siach return !!(value & REG_CONTROL3_BLF); 91ecb4a353SBaruch Siach } 92ecb4a353SBaruch Siach 93189927e7SSam Ravnborg static int pcf8523_load_capacitance(struct i2c_client *client) 94f803f0d0SThierry Reding { 95189927e7SSam Ravnborg u32 load; 96f803f0d0SThierry Reding u8 value; 97f803f0d0SThierry Reding int err; 98f803f0d0SThierry Reding 99f803f0d0SThierry Reding err = pcf8523_read(client, REG_CONTROL1, &value); 100f803f0d0SThierry Reding if (err < 0) 101f803f0d0SThierry Reding return err; 102f803f0d0SThierry Reding 103189927e7SSam Ravnborg load = 12500; 104189927e7SSam Ravnborg of_property_read_u32(client->dev.of_node, "quartz-load-femtofarads", 105189927e7SSam Ravnborg &load); 106189927e7SSam Ravnborg 107189927e7SSam Ravnborg switch (load) { 108189927e7SSam Ravnborg default: 109189927e7SSam Ravnborg dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500", 110189927e7SSam Ravnborg load); 111189927e7SSam Ravnborg /* fall through */ 112189927e7SSam Ravnborg case 12500: 113f803f0d0SThierry Reding value |= REG_CONTROL1_CAP_SEL; 114189927e7SSam Ravnborg break; 115189927e7SSam Ravnborg case 7000: 116189927e7SSam Ravnborg value &= ~REG_CONTROL1_CAP_SEL; 117189927e7SSam Ravnborg break; 118189927e7SSam Ravnborg } 119f803f0d0SThierry Reding 120f803f0d0SThierry Reding err = pcf8523_write(client, REG_CONTROL1, value); 121f803f0d0SThierry Reding 122f803f0d0SThierry Reding return err; 123f803f0d0SThierry Reding } 124f803f0d0SThierry Reding 125f803f0d0SThierry Reding static int pcf8523_set_pm(struct i2c_client *client, u8 pm) 126f803f0d0SThierry Reding { 127f803f0d0SThierry Reding u8 value; 128f803f0d0SThierry Reding int err; 129f803f0d0SThierry Reding 130f803f0d0SThierry Reding err = pcf8523_read(client, REG_CONTROL3, &value); 131f803f0d0SThierry Reding if (err < 0) 132f803f0d0SThierry Reding return err; 133f803f0d0SThierry Reding 134f803f0d0SThierry Reding value = (value & ~REG_CONTROL3_PM_MASK) | pm; 135f803f0d0SThierry Reding 136f803f0d0SThierry Reding err = pcf8523_write(client, REG_CONTROL3, value); 137f803f0d0SThierry Reding if (err < 0) 138f803f0d0SThierry Reding return err; 139f803f0d0SThierry Reding 140f803f0d0SThierry Reding return 0; 141f803f0d0SThierry Reding } 142f803f0d0SThierry Reding 143f803f0d0SThierry Reding static int pcf8523_stop_rtc(struct i2c_client *client) 144f803f0d0SThierry Reding { 145f803f0d0SThierry Reding u8 value; 146f803f0d0SThierry Reding int err; 147f803f0d0SThierry Reding 148f803f0d0SThierry Reding err = pcf8523_read(client, REG_CONTROL1, &value); 149f803f0d0SThierry Reding if (err < 0) 150f803f0d0SThierry Reding return err; 151f803f0d0SThierry Reding 152f803f0d0SThierry Reding value |= REG_CONTROL1_STOP; 153f803f0d0SThierry Reding 154f803f0d0SThierry Reding err = pcf8523_write(client, REG_CONTROL1, value); 155f803f0d0SThierry Reding if (err < 0) 156f803f0d0SThierry Reding return err; 157f803f0d0SThierry Reding 158f803f0d0SThierry Reding return 0; 159f803f0d0SThierry Reding } 160f803f0d0SThierry Reding 161f803f0d0SThierry Reding static int pcf8523_start_rtc(struct i2c_client *client) 162f803f0d0SThierry Reding { 163f803f0d0SThierry Reding u8 value; 164f803f0d0SThierry Reding int err; 165f803f0d0SThierry Reding 166f803f0d0SThierry Reding err = pcf8523_read(client, REG_CONTROL1, &value); 167f803f0d0SThierry Reding if (err < 0) 168f803f0d0SThierry Reding return err; 169f803f0d0SThierry Reding 170f803f0d0SThierry Reding value &= ~REG_CONTROL1_STOP; 171f803f0d0SThierry Reding 172f803f0d0SThierry Reding err = pcf8523_write(client, REG_CONTROL1, value); 173f803f0d0SThierry Reding if (err < 0) 174f803f0d0SThierry Reding return err; 175f803f0d0SThierry Reding 176f803f0d0SThierry Reding return 0; 177f803f0d0SThierry Reding } 178f803f0d0SThierry Reding 179f803f0d0SThierry Reding static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) 180f803f0d0SThierry Reding { 181f803f0d0SThierry Reding struct i2c_client *client = to_i2c_client(dev); 182f803f0d0SThierry Reding u8 start = REG_SECONDS, regs[7]; 183f803f0d0SThierry Reding struct i2c_msg msgs[2]; 184f803f0d0SThierry Reding int err; 185f803f0d0SThierry Reding 186ecb4a353SBaruch Siach err = pcf8523_voltage_low(client); 187ecb4a353SBaruch Siach if (err < 0) { 188ecb4a353SBaruch Siach return err; 189ecb4a353SBaruch Siach } else if (err > 0) { 190ecb4a353SBaruch Siach dev_err(dev, "low voltage detected, time is unreliable\n"); 191ecb4a353SBaruch Siach return -EINVAL; 192ecb4a353SBaruch Siach } 193ecb4a353SBaruch Siach 194f803f0d0SThierry Reding msgs[0].addr = client->addr; 195f803f0d0SThierry Reding msgs[0].flags = 0; 196f803f0d0SThierry Reding msgs[0].len = 1; 197f803f0d0SThierry Reding msgs[0].buf = &start; 198f803f0d0SThierry Reding 199f803f0d0SThierry Reding msgs[1].addr = client->addr; 200f803f0d0SThierry Reding msgs[1].flags = I2C_M_RD; 201f803f0d0SThierry Reding msgs[1].len = sizeof(regs); 202f803f0d0SThierry Reding msgs[1].buf = regs; 203f803f0d0SThierry Reding 204f803f0d0SThierry Reding err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 205f803f0d0SThierry Reding if (err < 0) 206f803f0d0SThierry Reding return err; 207f803f0d0SThierry Reding 208f803f0d0SThierry Reding if (regs[0] & REG_SECONDS_OS) 209ede44c90SAlexandre Belloni return -EINVAL; 210f803f0d0SThierry Reding 211f803f0d0SThierry Reding tm->tm_sec = bcd2bin(regs[0] & 0x7f); 212f803f0d0SThierry Reding tm->tm_min = bcd2bin(regs[1] & 0x7f); 213f803f0d0SThierry Reding tm->tm_hour = bcd2bin(regs[2] & 0x3f); 214f803f0d0SThierry Reding tm->tm_mday = bcd2bin(regs[3] & 0x3f); 215f803f0d0SThierry Reding tm->tm_wday = regs[4] & 0x7; 21635738392SChris Cui tm->tm_mon = bcd2bin(regs[5] & 0x1f) - 1; 217f803f0d0SThierry Reding tm->tm_year = bcd2bin(regs[6]) + 100; 218f803f0d0SThierry Reding 21922652ba7SAlexandre Belloni return 0; 220f803f0d0SThierry Reding } 221f803f0d0SThierry Reding 222f803f0d0SThierry Reding static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) 223f803f0d0SThierry Reding { 224f803f0d0SThierry Reding struct i2c_client *client = to_i2c_client(dev); 225f803f0d0SThierry Reding struct i2c_msg msg; 226f803f0d0SThierry Reding u8 regs[8]; 227f803f0d0SThierry Reding int err; 228f803f0d0SThierry Reding 229fbbf53f7SUwe Kleine-König /* 230fbbf53f7SUwe Kleine-König * The hardware can only store values between 0 and 99 in it's YEAR 231fbbf53f7SUwe Kleine-König * register (with 99 overflowing to 0 on increment). 232fbbf53f7SUwe Kleine-König * After 2100-02-28 we could start interpreting the year to be in the 233fbbf53f7SUwe Kleine-König * interval [2100, 2199], but there is no path to switch in a smooth way 234fbbf53f7SUwe Kleine-König * because the chip handles YEAR=0x00 (and the out-of-spec 235fbbf53f7SUwe Kleine-König * YEAR=0xa0) as a leap year, but 2100 isn't. 236fbbf53f7SUwe Kleine-König */ 237fbbf53f7SUwe Kleine-König if (tm->tm_year < 100 || tm->tm_year >= 200) 238fbbf53f7SUwe Kleine-König return -EINVAL; 239fbbf53f7SUwe Kleine-König 240f803f0d0SThierry Reding err = pcf8523_stop_rtc(client); 241f803f0d0SThierry Reding if (err < 0) 242f803f0d0SThierry Reding return err; 243f803f0d0SThierry Reding 244f803f0d0SThierry Reding regs[0] = REG_SECONDS; 245ede44c90SAlexandre Belloni /* This will purposely overwrite REG_SECONDS_OS */ 246f803f0d0SThierry Reding regs[1] = bin2bcd(tm->tm_sec); 247f803f0d0SThierry Reding regs[2] = bin2bcd(tm->tm_min); 248f803f0d0SThierry Reding regs[3] = bin2bcd(tm->tm_hour); 249f803f0d0SThierry Reding regs[4] = bin2bcd(tm->tm_mday); 250f803f0d0SThierry Reding regs[5] = tm->tm_wday; 25135738392SChris Cui regs[6] = bin2bcd(tm->tm_mon + 1); 252f803f0d0SThierry Reding regs[7] = bin2bcd(tm->tm_year - 100); 253f803f0d0SThierry Reding 254f803f0d0SThierry Reding msg.addr = client->addr; 255f803f0d0SThierry Reding msg.flags = 0; 256f803f0d0SThierry Reding msg.len = sizeof(regs); 257f803f0d0SThierry Reding msg.buf = regs; 258f803f0d0SThierry Reding 259f803f0d0SThierry Reding err = i2c_transfer(client->adapter, &msg, 1); 260f803f0d0SThierry Reding if (err < 0) { 261f803f0d0SThierry Reding /* 262f803f0d0SThierry Reding * If the time cannot be set, restart the RTC anyway. Note 263f803f0d0SThierry Reding * that errors are ignored if the RTC cannot be started so 264f803f0d0SThierry Reding * that we have a chance to propagate the original error. 265f803f0d0SThierry Reding */ 266f803f0d0SThierry Reding pcf8523_start_rtc(client); 267f803f0d0SThierry Reding return err; 268f803f0d0SThierry Reding } 269f803f0d0SThierry Reding 270f803f0d0SThierry Reding return pcf8523_start_rtc(client); 271f803f0d0SThierry Reding } 272f803f0d0SThierry Reding 273f32bc70dSJesper Nilsson #ifdef CONFIG_RTC_INTF_DEV 274f32bc70dSJesper Nilsson static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, 275f32bc70dSJesper Nilsson unsigned long arg) 276f32bc70dSJesper Nilsson { 277f32bc70dSJesper Nilsson struct i2c_client *client = to_i2c_client(dev); 278ecb4a353SBaruch Siach int ret; 279f32bc70dSJesper Nilsson 280f32bc70dSJesper Nilsson switch (cmd) { 281f32bc70dSJesper Nilsson case RTC_VL_READ: 282ecb4a353SBaruch Siach ret = pcf8523_voltage_low(client); 283ecb4a353SBaruch Siach if (ret < 0) 284ecb4a353SBaruch Siach return ret; 285f32bc70dSJesper Nilsson 286f32bc70dSJesper Nilsson if (copy_to_user((void __user *)arg, &ret, sizeof(int))) 287f32bc70dSJesper Nilsson return -EFAULT; 288f32bc70dSJesper Nilsson 289f32bc70dSJesper Nilsson return 0; 290f32bc70dSJesper Nilsson default: 291f32bc70dSJesper Nilsson return -ENOIOCTLCMD; 292f32bc70dSJesper Nilsson } 293f32bc70dSJesper Nilsson } 294f32bc70dSJesper Nilsson #else 295f32bc70dSJesper Nilsson #define pcf8523_rtc_ioctl NULL 296f32bc70dSJesper Nilsson #endif 297f32bc70dSJesper Nilsson 298bc3bee02SRussell King static int pcf8523_rtc_read_offset(struct device *dev, long *offset) 299bc3bee02SRussell King { 300bc3bee02SRussell King struct i2c_client *client = to_i2c_client(dev); 301bc3bee02SRussell King int err; 302bc3bee02SRussell King u8 value; 303bc3bee02SRussell King s8 val; 304bc3bee02SRussell King 305bc3bee02SRussell King err = pcf8523_read(client, REG_OFFSET, &value); 306bc3bee02SRussell King if (err < 0) 307bc3bee02SRussell King return err; 308bc3bee02SRussell King 309bc3bee02SRussell King /* sign extend the 7-bit offset value */ 310bc3bee02SRussell King val = value << 1; 311bc3bee02SRussell King *offset = (value & REG_OFFSET_MODE ? 4069 : 4340) * (val >> 1); 312bc3bee02SRussell King 313bc3bee02SRussell King return 0; 314bc3bee02SRussell King } 315bc3bee02SRussell King 316bc3bee02SRussell King static int pcf8523_rtc_set_offset(struct device *dev, long offset) 317bc3bee02SRussell King { 318bc3bee02SRussell King struct i2c_client *client = to_i2c_client(dev); 319bc3bee02SRussell King long reg_m0, reg_m1; 320bc3bee02SRussell King u8 value; 321bc3bee02SRussell King 322bc3bee02SRussell King reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L); 323bc3bee02SRussell King reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L); 324bc3bee02SRussell King 325bc3bee02SRussell King if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset)) 326bc3bee02SRussell King value = reg_m0 & 0x7f; 327bc3bee02SRussell King else 328bc3bee02SRussell King value = (reg_m1 & 0x7f) | REG_OFFSET_MODE; 329bc3bee02SRussell King 330bc3bee02SRussell King return pcf8523_write(client, REG_OFFSET, value); 331bc3bee02SRussell King } 332bc3bee02SRussell King 333f803f0d0SThierry Reding static const struct rtc_class_ops pcf8523_rtc_ops = { 334f803f0d0SThierry Reding .read_time = pcf8523_rtc_read_time, 335f803f0d0SThierry Reding .set_time = pcf8523_rtc_set_time, 336f32bc70dSJesper Nilsson .ioctl = pcf8523_rtc_ioctl, 337bc3bee02SRussell King .read_offset = pcf8523_rtc_read_offset, 338bc3bee02SRussell King .set_offset = pcf8523_rtc_set_offset, 339f803f0d0SThierry Reding }; 340f803f0d0SThierry Reding 341f803f0d0SThierry Reding static int pcf8523_probe(struct i2c_client *client, 342f803f0d0SThierry Reding const struct i2c_device_id *id) 343f803f0d0SThierry Reding { 344*93966243SNobuhiro Iwamatsu struct rtc_device *rtc; 345f803f0d0SThierry Reding int err; 346f803f0d0SThierry Reding 347f803f0d0SThierry Reding if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 348f803f0d0SThierry Reding return -ENODEV; 349f803f0d0SThierry Reding 350189927e7SSam Ravnborg err = pcf8523_load_capacitance(client); 351f803f0d0SThierry Reding if (err < 0) 352189927e7SSam Ravnborg dev_warn(&client->dev, "failed to set xtal load capacitance: %d", 353189927e7SSam Ravnborg err); 354f803f0d0SThierry Reding 355f803f0d0SThierry Reding err = pcf8523_set_pm(client, 0); 356f803f0d0SThierry Reding if (err < 0) 357f803f0d0SThierry Reding return err; 358f803f0d0SThierry Reding 359*93966243SNobuhiro Iwamatsu rtc = devm_rtc_device_register(&client->dev, DRIVER_NAME, 360f803f0d0SThierry Reding &pcf8523_rtc_ops, THIS_MODULE); 361*93966243SNobuhiro Iwamatsu if (IS_ERR(rtc)) 362*93966243SNobuhiro Iwamatsu return PTR_ERR(rtc); 363f803f0d0SThierry Reding 364f803f0d0SThierry Reding return 0; 365f803f0d0SThierry Reding } 366f803f0d0SThierry Reding 367f803f0d0SThierry Reding static const struct i2c_device_id pcf8523_id[] = { 368f803f0d0SThierry Reding { "pcf8523", 0 }, 369f803f0d0SThierry Reding { } 370f803f0d0SThierry Reding }; 371f803f0d0SThierry Reding MODULE_DEVICE_TABLE(i2c, pcf8523_id); 372f803f0d0SThierry Reding 373f803f0d0SThierry Reding #ifdef CONFIG_OF 374f803f0d0SThierry Reding static const struct of_device_id pcf8523_of_match[] = { 375f803f0d0SThierry Reding { .compatible = "nxp,pcf8523" }, 3767c617e0cSAlexandre Belloni { .compatible = "microcrystal,rv8523" }, 377f803f0d0SThierry Reding { } 378f803f0d0SThierry Reding }; 379f803f0d0SThierry Reding MODULE_DEVICE_TABLE(of, pcf8523_of_match); 380f803f0d0SThierry Reding #endif 381f803f0d0SThierry Reding 382f803f0d0SThierry Reding static struct i2c_driver pcf8523_driver = { 383f803f0d0SThierry Reding .driver = { 384f803f0d0SThierry Reding .name = DRIVER_NAME, 385f803f0d0SThierry Reding .of_match_table = of_match_ptr(pcf8523_of_match), 386f803f0d0SThierry Reding }, 387f803f0d0SThierry Reding .probe = pcf8523_probe, 388f803f0d0SThierry Reding .id_table = pcf8523_id, 389f803f0d0SThierry Reding }; 390f803f0d0SThierry Reding module_i2c_driver(pcf8523_driver); 391f803f0d0SThierry Reding 392f803f0d0SThierry Reding MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 393f803f0d0SThierry Reding MODULE_DESCRIPTION("NXP PCF8523 RTC driver"); 394f803f0d0SThierry Reding MODULE_LICENSE("GPL v2"); 395