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 REG_CONTROL1 0x00 13673536ccSAlexandre Belloni #define REG_CONTROL1_CAP_SEL BIT(7) 14673536ccSAlexandre Belloni #define REG_CONTROL1_STOP BIT(5) 15f803f0d0SThierry Reding 16f803f0d0SThierry Reding #define REG_CONTROL3 0x02 17673536ccSAlexandre Belloni #define REG_CONTROL3_PM_BLD BIT(7) /* battery low detection disabled */ 18673536ccSAlexandre Belloni #define REG_CONTROL3_PM_VDD BIT(6) /* switch-over disabled */ 19673536ccSAlexandre Belloni #define REG_CONTROL3_PM_DSM BIT(5) /* direct switching mode */ 20f803f0d0SThierry Reding #define REG_CONTROL3_PM_MASK 0xe0 21673536ccSAlexandre Belloni #define REG_CONTROL3_BLF BIT(2) /* battery low bit, read-only */ 22f803f0d0SThierry Reding 23f803f0d0SThierry Reding #define REG_SECONDS 0x03 24673536ccSAlexandre Belloni #define REG_SECONDS_OS BIT(7) 25f803f0d0SThierry Reding 26f803f0d0SThierry Reding #define REG_MINUTES 0x04 27f803f0d0SThierry Reding #define REG_HOURS 0x05 28f803f0d0SThierry Reding #define REG_DAYS 0x06 29f803f0d0SThierry Reding #define REG_WEEKDAYS 0x07 30f803f0d0SThierry Reding #define REG_MONTHS 0x08 31f803f0d0SThierry Reding #define REG_YEARS 0x09 32f803f0d0SThierry Reding 33bc3bee02SRussell King #define REG_OFFSET 0x0e 34bc3bee02SRussell King #define REG_OFFSET_MODE BIT(7) 35bc3bee02SRussell King 36f803f0d0SThierry Reding static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep) 37f803f0d0SThierry Reding { 38f803f0d0SThierry Reding struct i2c_msg msgs[2]; 39f803f0d0SThierry Reding u8 value = 0; 40f803f0d0SThierry Reding int err; 41f803f0d0SThierry Reding 42f803f0d0SThierry Reding msgs[0].addr = client->addr; 43f803f0d0SThierry Reding msgs[0].flags = 0; 44f803f0d0SThierry Reding msgs[0].len = sizeof(reg); 45f803f0d0SThierry Reding msgs[0].buf = ® 46f803f0d0SThierry Reding 47f803f0d0SThierry Reding msgs[1].addr = client->addr; 48f803f0d0SThierry Reding msgs[1].flags = I2C_M_RD; 49f803f0d0SThierry Reding msgs[1].len = sizeof(value); 50f803f0d0SThierry Reding msgs[1].buf = &value; 51f803f0d0SThierry Reding 52f803f0d0SThierry Reding err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 53f803f0d0SThierry Reding if (err < 0) 54f803f0d0SThierry Reding return err; 55f803f0d0SThierry Reding 56f803f0d0SThierry Reding *valuep = value; 57f803f0d0SThierry Reding 58f803f0d0SThierry Reding return 0; 59f803f0d0SThierry Reding } 60f803f0d0SThierry Reding 61f803f0d0SThierry Reding static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) 62f803f0d0SThierry Reding { 63f803f0d0SThierry Reding u8 buffer[2] = { reg, value }; 64f803f0d0SThierry Reding struct i2c_msg msg; 65f803f0d0SThierry Reding int err; 66f803f0d0SThierry Reding 67f803f0d0SThierry Reding msg.addr = client->addr; 68f803f0d0SThierry Reding msg.flags = 0; 69f803f0d0SThierry Reding msg.len = sizeof(buffer); 70f803f0d0SThierry Reding msg.buf = buffer; 71f803f0d0SThierry Reding 72f803f0d0SThierry Reding err = i2c_transfer(client->adapter, &msg, 1); 73f803f0d0SThierry Reding if (err < 0) 74f803f0d0SThierry Reding return err; 75f803f0d0SThierry Reding 76f803f0d0SThierry Reding return 0; 77f803f0d0SThierry Reding } 78f803f0d0SThierry Reding 79ecb4a353SBaruch Siach static int pcf8523_voltage_low(struct i2c_client *client) 80ecb4a353SBaruch Siach { 81ecb4a353SBaruch Siach u8 value; 82ecb4a353SBaruch Siach int err; 83ecb4a353SBaruch Siach 84ecb4a353SBaruch Siach err = pcf8523_read(client, REG_CONTROL3, &value); 85ecb4a353SBaruch Siach if (err < 0) 86ecb4a353SBaruch Siach return err; 87ecb4a353SBaruch Siach 88ecb4a353SBaruch Siach return !!(value & REG_CONTROL3_BLF); 89ecb4a353SBaruch Siach } 90ecb4a353SBaruch Siach 91189927e7SSam Ravnborg static int pcf8523_load_capacitance(struct i2c_client *client) 92f803f0d0SThierry Reding { 93189927e7SSam Ravnborg u32 load; 94f803f0d0SThierry Reding u8 value; 95f803f0d0SThierry Reding int err; 96f803f0d0SThierry Reding 97f803f0d0SThierry Reding err = pcf8523_read(client, REG_CONTROL1, &value); 98f803f0d0SThierry Reding if (err < 0) 99f803f0d0SThierry Reding return err; 100f803f0d0SThierry Reding 101189927e7SSam Ravnborg load = 12500; 102189927e7SSam Ravnborg of_property_read_u32(client->dev.of_node, "quartz-load-femtofarads", 103189927e7SSam Ravnborg &load); 104189927e7SSam Ravnborg 105189927e7SSam Ravnborg switch (load) { 106189927e7SSam Ravnborg default: 107189927e7SSam Ravnborg dev_warn(&client->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 12500", 108189927e7SSam Ravnborg load); 109df561f66SGustavo A. R. Silva fallthrough; 110189927e7SSam Ravnborg case 12500: 111f803f0d0SThierry Reding value |= REG_CONTROL1_CAP_SEL; 112189927e7SSam Ravnborg break; 113189927e7SSam Ravnborg case 7000: 114189927e7SSam Ravnborg value &= ~REG_CONTROL1_CAP_SEL; 115189927e7SSam Ravnborg break; 116189927e7SSam Ravnborg } 117f803f0d0SThierry Reding 118f803f0d0SThierry Reding err = pcf8523_write(client, REG_CONTROL1, value); 119f803f0d0SThierry Reding 120f803f0d0SThierry Reding return err; 121f803f0d0SThierry Reding } 122f803f0d0SThierry Reding 123f803f0d0SThierry Reding static int pcf8523_set_pm(struct i2c_client *client, u8 pm) 124f803f0d0SThierry Reding { 125f803f0d0SThierry Reding u8 value; 126f803f0d0SThierry Reding int err; 127f803f0d0SThierry Reding 128f803f0d0SThierry Reding err = pcf8523_read(client, REG_CONTROL3, &value); 129f803f0d0SThierry Reding if (err < 0) 130f803f0d0SThierry Reding return err; 131f803f0d0SThierry Reding 132f803f0d0SThierry Reding value = (value & ~REG_CONTROL3_PM_MASK) | pm; 133f803f0d0SThierry Reding 134f803f0d0SThierry Reding err = pcf8523_write(client, REG_CONTROL3, value); 135f803f0d0SThierry Reding if (err < 0) 136f803f0d0SThierry Reding return err; 137f803f0d0SThierry Reding 138f803f0d0SThierry Reding return 0; 139f803f0d0SThierry Reding } 140f803f0d0SThierry Reding 141f803f0d0SThierry Reding static int pcf8523_stop_rtc(struct i2c_client *client) 142f803f0d0SThierry Reding { 143f803f0d0SThierry Reding u8 value; 144f803f0d0SThierry Reding int err; 145f803f0d0SThierry Reding 146f803f0d0SThierry Reding err = pcf8523_read(client, REG_CONTROL1, &value); 147f803f0d0SThierry Reding if (err < 0) 148f803f0d0SThierry Reding return err; 149f803f0d0SThierry Reding 150f803f0d0SThierry Reding value |= REG_CONTROL1_STOP; 151f803f0d0SThierry Reding 152f803f0d0SThierry Reding err = pcf8523_write(client, REG_CONTROL1, value); 153f803f0d0SThierry Reding if (err < 0) 154f803f0d0SThierry Reding return err; 155f803f0d0SThierry Reding 156f803f0d0SThierry Reding return 0; 157f803f0d0SThierry Reding } 158f803f0d0SThierry Reding 159f803f0d0SThierry Reding static int pcf8523_start_rtc(struct i2c_client *client) 160f803f0d0SThierry Reding { 161f803f0d0SThierry Reding u8 value; 162f803f0d0SThierry Reding int err; 163f803f0d0SThierry Reding 164f803f0d0SThierry Reding err = pcf8523_read(client, REG_CONTROL1, &value); 165f803f0d0SThierry Reding if (err < 0) 166f803f0d0SThierry Reding return err; 167f803f0d0SThierry Reding 168f803f0d0SThierry Reding value &= ~REG_CONTROL1_STOP; 169f803f0d0SThierry Reding 170f803f0d0SThierry Reding err = pcf8523_write(client, REG_CONTROL1, value); 171f803f0d0SThierry Reding if (err < 0) 172f803f0d0SThierry Reding return err; 173f803f0d0SThierry Reding 174f803f0d0SThierry Reding return 0; 175f803f0d0SThierry Reding } 176f803f0d0SThierry Reding 177f803f0d0SThierry Reding static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) 178f803f0d0SThierry Reding { 179f803f0d0SThierry Reding struct i2c_client *client = to_i2c_client(dev); 180f803f0d0SThierry Reding u8 start = REG_SECONDS, regs[7]; 181f803f0d0SThierry Reding struct i2c_msg msgs[2]; 182f803f0d0SThierry Reding int err; 183f803f0d0SThierry Reding 184ecb4a353SBaruch Siach err = pcf8523_voltage_low(client); 185ecb4a353SBaruch Siach if (err < 0) { 186ecb4a353SBaruch Siach return err; 187ecb4a353SBaruch Siach } else if (err > 0) { 188ecb4a353SBaruch Siach dev_err(dev, "low voltage detected, time is unreliable\n"); 189ecb4a353SBaruch Siach return -EINVAL; 190ecb4a353SBaruch Siach } 191ecb4a353SBaruch Siach 192f803f0d0SThierry Reding msgs[0].addr = client->addr; 193f803f0d0SThierry Reding msgs[0].flags = 0; 194f803f0d0SThierry Reding msgs[0].len = 1; 195f803f0d0SThierry Reding msgs[0].buf = &start; 196f803f0d0SThierry Reding 197f803f0d0SThierry Reding msgs[1].addr = client->addr; 198f803f0d0SThierry Reding msgs[1].flags = I2C_M_RD; 199f803f0d0SThierry Reding msgs[1].len = sizeof(regs); 200f803f0d0SThierry Reding msgs[1].buf = regs; 201f803f0d0SThierry Reding 202f803f0d0SThierry Reding err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 203f803f0d0SThierry Reding if (err < 0) 204f803f0d0SThierry Reding return err; 205f803f0d0SThierry Reding 206f803f0d0SThierry Reding if (regs[0] & REG_SECONDS_OS) 207ede44c90SAlexandre Belloni return -EINVAL; 208f803f0d0SThierry Reding 209f803f0d0SThierry Reding tm->tm_sec = bcd2bin(regs[0] & 0x7f); 210f803f0d0SThierry Reding tm->tm_min = bcd2bin(regs[1] & 0x7f); 211f803f0d0SThierry Reding tm->tm_hour = bcd2bin(regs[2] & 0x3f); 212f803f0d0SThierry Reding tm->tm_mday = bcd2bin(regs[3] & 0x3f); 213f803f0d0SThierry Reding tm->tm_wday = regs[4] & 0x7; 21435738392SChris Cui tm->tm_mon = bcd2bin(regs[5] & 0x1f) - 1; 215f803f0d0SThierry Reding tm->tm_year = bcd2bin(regs[6]) + 100; 216f803f0d0SThierry Reding 21722652ba7SAlexandre Belloni return 0; 218f803f0d0SThierry Reding } 219f803f0d0SThierry Reding 220f803f0d0SThierry Reding static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) 221f803f0d0SThierry Reding { 222f803f0d0SThierry Reding struct i2c_client *client = to_i2c_client(dev); 223f803f0d0SThierry Reding struct i2c_msg msg; 224f803f0d0SThierry Reding u8 regs[8]; 225f803f0d0SThierry Reding int err; 226f803f0d0SThierry Reding 227f803f0d0SThierry Reding err = pcf8523_stop_rtc(client); 228f803f0d0SThierry Reding if (err < 0) 229f803f0d0SThierry Reding return err; 230f803f0d0SThierry Reding 231f803f0d0SThierry Reding regs[0] = REG_SECONDS; 232ede44c90SAlexandre Belloni /* This will purposely overwrite REG_SECONDS_OS */ 233f803f0d0SThierry Reding regs[1] = bin2bcd(tm->tm_sec); 234f803f0d0SThierry Reding regs[2] = bin2bcd(tm->tm_min); 235f803f0d0SThierry Reding regs[3] = bin2bcd(tm->tm_hour); 236f803f0d0SThierry Reding regs[4] = bin2bcd(tm->tm_mday); 237f803f0d0SThierry Reding regs[5] = tm->tm_wday; 23835738392SChris Cui regs[6] = bin2bcd(tm->tm_mon + 1); 239f803f0d0SThierry Reding regs[7] = bin2bcd(tm->tm_year - 100); 240f803f0d0SThierry Reding 241f803f0d0SThierry Reding msg.addr = client->addr; 242f803f0d0SThierry Reding msg.flags = 0; 243f803f0d0SThierry Reding msg.len = sizeof(regs); 244f803f0d0SThierry Reding msg.buf = regs; 245f803f0d0SThierry Reding 246f803f0d0SThierry Reding err = i2c_transfer(client->adapter, &msg, 1); 247f803f0d0SThierry Reding if (err < 0) { 248f803f0d0SThierry Reding /* 249f803f0d0SThierry Reding * If the time cannot be set, restart the RTC anyway. Note 250f803f0d0SThierry Reding * that errors are ignored if the RTC cannot be started so 251f803f0d0SThierry Reding * that we have a chance to propagate the original error. 252f803f0d0SThierry Reding */ 253f803f0d0SThierry Reding pcf8523_start_rtc(client); 254f803f0d0SThierry Reding return err; 255f803f0d0SThierry Reding } 256f803f0d0SThierry Reding 257f803f0d0SThierry Reding return pcf8523_start_rtc(client); 258f803f0d0SThierry Reding } 259f803f0d0SThierry Reding 260f32bc70dSJesper Nilsson #ifdef CONFIG_RTC_INTF_DEV 261f32bc70dSJesper Nilsson static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, 262f32bc70dSJesper Nilsson unsigned long arg) 263f32bc70dSJesper Nilsson { 264f32bc70dSJesper Nilsson struct i2c_client *client = to_i2c_client(dev); 265ecb4a353SBaruch Siach int ret; 266f32bc70dSJesper Nilsson 267f32bc70dSJesper Nilsson switch (cmd) { 268f32bc70dSJesper Nilsson case RTC_VL_READ: 269ecb4a353SBaruch Siach ret = pcf8523_voltage_low(client); 270ecb4a353SBaruch Siach if (ret < 0) 271ecb4a353SBaruch Siach return ret; 272244cf8f0SAlexandre Belloni if (ret) 273244cf8f0SAlexandre Belloni ret = RTC_VL_BACKUP_LOW; 274f32bc70dSJesper Nilsson 275244cf8f0SAlexandre Belloni return put_user(ret, (unsigned int __user *)arg); 276f32bc70dSJesper Nilsson 277f32bc70dSJesper Nilsson default: 278f32bc70dSJesper Nilsson return -ENOIOCTLCMD; 279f32bc70dSJesper Nilsson } 280f32bc70dSJesper Nilsson } 281f32bc70dSJesper Nilsson #else 282f32bc70dSJesper Nilsson #define pcf8523_rtc_ioctl NULL 283f32bc70dSJesper Nilsson #endif 284f32bc70dSJesper Nilsson 285bc3bee02SRussell King static int pcf8523_rtc_read_offset(struct device *dev, long *offset) 286bc3bee02SRussell King { 287bc3bee02SRussell King struct i2c_client *client = to_i2c_client(dev); 288bc3bee02SRussell King int err; 289bc3bee02SRussell King u8 value; 290bc3bee02SRussell King s8 val; 291bc3bee02SRussell King 292bc3bee02SRussell King err = pcf8523_read(client, REG_OFFSET, &value); 293bc3bee02SRussell King if (err < 0) 294bc3bee02SRussell King return err; 295bc3bee02SRussell King 296bc3bee02SRussell King /* sign extend the 7-bit offset value */ 297bc3bee02SRussell King val = value << 1; 298bc3bee02SRussell King *offset = (value & REG_OFFSET_MODE ? 4069 : 4340) * (val >> 1); 299bc3bee02SRussell King 300bc3bee02SRussell King return 0; 301bc3bee02SRussell King } 302bc3bee02SRussell King 303bc3bee02SRussell King static int pcf8523_rtc_set_offset(struct device *dev, long offset) 304bc3bee02SRussell King { 305bc3bee02SRussell King struct i2c_client *client = to_i2c_client(dev); 306bc3bee02SRussell King long reg_m0, reg_m1; 307bc3bee02SRussell King u8 value; 308bc3bee02SRussell King 309bc3bee02SRussell King reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L); 310bc3bee02SRussell King reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L); 311bc3bee02SRussell King 312bc3bee02SRussell King if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset)) 313bc3bee02SRussell King value = reg_m0 & 0x7f; 314bc3bee02SRussell King else 315bc3bee02SRussell King value = (reg_m1 & 0x7f) | REG_OFFSET_MODE; 316bc3bee02SRussell King 317bc3bee02SRussell King return pcf8523_write(client, REG_OFFSET, value); 318bc3bee02SRussell King } 319bc3bee02SRussell King 320f803f0d0SThierry Reding static const struct rtc_class_ops pcf8523_rtc_ops = { 321f803f0d0SThierry Reding .read_time = pcf8523_rtc_read_time, 322f803f0d0SThierry Reding .set_time = pcf8523_rtc_set_time, 323f32bc70dSJesper Nilsson .ioctl = pcf8523_rtc_ioctl, 324bc3bee02SRussell King .read_offset = pcf8523_rtc_read_offset, 325bc3bee02SRussell King .set_offset = pcf8523_rtc_set_offset, 326f803f0d0SThierry Reding }; 327f803f0d0SThierry Reding 328f803f0d0SThierry Reding static int pcf8523_probe(struct i2c_client *client, 329f803f0d0SThierry Reding const struct i2c_device_id *id) 330f803f0d0SThierry Reding { 33193966243SNobuhiro Iwamatsu struct rtc_device *rtc; 332f803f0d0SThierry Reding int err; 333f803f0d0SThierry Reding 334f803f0d0SThierry Reding if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 335f803f0d0SThierry Reding return -ENODEV; 336f803f0d0SThierry Reding 337189927e7SSam Ravnborg err = pcf8523_load_capacitance(client); 338f803f0d0SThierry Reding if (err < 0) 339189927e7SSam Ravnborg dev_warn(&client->dev, "failed to set xtal load capacitance: %d", 340189927e7SSam Ravnborg err); 341f803f0d0SThierry Reding 342f803f0d0SThierry Reding err = pcf8523_set_pm(client, 0); 343f803f0d0SThierry Reding if (err < 0) 344f803f0d0SThierry Reding return err; 345f803f0d0SThierry Reding 34688614405SAlexandre Belloni rtc = devm_rtc_allocate_device(&client->dev); 34793966243SNobuhiro Iwamatsu if (IS_ERR(rtc)) 34893966243SNobuhiro Iwamatsu return PTR_ERR(rtc); 349f803f0d0SThierry Reding 35088614405SAlexandre Belloni rtc->ops = &pcf8523_rtc_ops; 351219cc0f9SAlexandre Belloni rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 352219cc0f9SAlexandre Belloni rtc->range_max = RTC_TIMESTAMP_END_2099; 35388614405SAlexandre Belloni 35488614405SAlexandre Belloni return devm_rtc_register_device(rtc); 355f803f0d0SThierry Reding } 356f803f0d0SThierry Reding 357f803f0d0SThierry Reding static const struct i2c_device_id pcf8523_id[] = { 358f803f0d0SThierry Reding { "pcf8523", 0 }, 359f803f0d0SThierry Reding { } 360f803f0d0SThierry Reding }; 361f803f0d0SThierry Reding MODULE_DEVICE_TABLE(i2c, pcf8523_id); 362f803f0d0SThierry Reding 363f803f0d0SThierry Reding #ifdef CONFIG_OF 364f803f0d0SThierry Reding static const struct of_device_id pcf8523_of_match[] = { 365f803f0d0SThierry Reding { .compatible = "nxp,pcf8523" }, 3667c617e0cSAlexandre Belloni { .compatible = "microcrystal,rv8523" }, 367f803f0d0SThierry Reding { } 368f803f0d0SThierry Reding }; 369f803f0d0SThierry Reding MODULE_DEVICE_TABLE(of, pcf8523_of_match); 370f803f0d0SThierry Reding #endif 371f803f0d0SThierry Reding 372f803f0d0SThierry Reding static struct i2c_driver pcf8523_driver = { 373f803f0d0SThierry Reding .driver = { 374*94959a3aSAlexandre Belloni .name = "rtc-pcf8523", 375f803f0d0SThierry Reding .of_match_table = of_match_ptr(pcf8523_of_match), 376f803f0d0SThierry Reding }, 377f803f0d0SThierry Reding .probe = pcf8523_probe, 378f803f0d0SThierry Reding .id_table = pcf8523_id, 379f803f0d0SThierry Reding }; 380f803f0d0SThierry Reding module_i2c_driver(pcf8523_driver); 381f803f0d0SThierry Reding 382f803f0d0SThierry Reding MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); 383f803f0d0SThierry Reding MODULE_DESCRIPTION("NXP PCF8523 RTC driver"); 384f803f0d0SThierry Reding MODULE_LICENSE("GPL v2"); 385