500 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * An I2C driver for the Intersil ISL 120264 *5 * Copyright (c) 2018 Cavium, Inc.6 */7#include <linux/bcd.h>8#include <linux/delay.h>9#include <linux/i2c.h>10#include <linux/module.h>11#include <linux/mutex.h>12#include <linux/nvmem-provider.h>13#include <linux/of.h>14#include <linux/rtc.h>15#include <linux/slab.h>16 17/* register offsets */18#define ISL12026_REG_PWR 0x1419# define ISL12026_REG_PWR_BSW BIT(6)20# define ISL12026_REG_PWR_SBIB BIT(7)21#define ISL12026_REG_SC 0x3022#define ISL12026_REG_HR 0x3223# define ISL12026_REG_HR_MIL BIT(7) /* military or 24 hour time */24#define ISL12026_REG_SR 0x3f25# define ISL12026_REG_SR_RTCF BIT(0)26# define ISL12026_REG_SR_WEL BIT(1)27# define ISL12026_REG_SR_RWEL BIT(2)28# define ISL12026_REG_SR_MBZ BIT(3)29# define ISL12026_REG_SR_OSCF BIT(4)30 31/* The EEPROM array responds at i2c address 0x57 */32#define ISL12026_EEPROM_ADDR 0x5733 34#define ISL12026_PAGESIZE 1635#define ISL12026_NVMEM_WRITE_TIME 2036 37struct isl12026 {38 struct rtc_device *rtc;39 struct i2c_client *nvm_client;40};41 42static int isl12026_read_reg(struct i2c_client *client, int reg)43{44 u8 addr[] = {0, reg};45 u8 val;46 int ret;47 48 struct i2c_msg msgs[] = {49 {50 .addr = client->addr,51 .flags = 0,52 .len = sizeof(addr),53 .buf = addr54 }, {55 .addr = client->addr,56 .flags = I2C_M_RD,57 .len = 1,58 .buf = &val59 }60 };61 62 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));63 if (ret != ARRAY_SIZE(msgs)) {64 dev_err(&client->dev, "read reg error, ret=%d\n", ret);65 ret = ret < 0 ? ret : -EIO;66 } else {67 ret = val;68 }69 70 return ret;71}72 73static int isl12026_arm_write(struct i2c_client *client)74{75 int ret;76 u8 op[3];77 struct i2c_msg msg = {78 .addr = client->addr,79 .flags = 0,80 .len = 1,81 .buf = op82 };83 84 /* Set SR.WEL */85 op[0] = 0;86 op[1] = ISL12026_REG_SR;87 op[2] = ISL12026_REG_SR_WEL;88 msg.len = 3;89 ret = i2c_transfer(client->adapter, &msg, 1);90 if (ret != 1) {91 dev_err(&client->dev, "write error SR.WEL, ret=%d\n", ret);92 ret = ret < 0 ? ret : -EIO;93 goto out;94 }95 96 /* Set SR.WEL and SR.RWEL */97 op[2] = ISL12026_REG_SR_WEL | ISL12026_REG_SR_RWEL;98 msg.len = 3;99 ret = i2c_transfer(client->adapter, &msg, 1);100 if (ret != 1) {101 dev_err(&client->dev,102 "write error SR.WEL|SR.RWEL, ret=%d\n", ret);103 ret = ret < 0 ? ret : -EIO;104 goto out;105 } else {106 ret = 0;107 }108out:109 return ret;110}111 112static int isl12026_disarm_write(struct i2c_client *client)113{114 int ret;115 u8 op[3] = {0, ISL12026_REG_SR, 0};116 struct i2c_msg msg = {117 .addr = client->addr,118 .flags = 0,119 .len = sizeof(op),120 .buf = op121 };122 123 ret = i2c_transfer(client->adapter, &msg, 1);124 if (ret != 1) {125 dev_err(&client->dev,126 "write error SR, ret=%d\n", ret);127 ret = ret < 0 ? ret : -EIO;128 } else {129 ret = 0;130 }131 132 return ret;133}134 135static int isl12026_write_reg(struct i2c_client *client, int reg, u8 val)136{137 int ret;138 u8 op[3] = {0, reg, val};139 struct i2c_msg msg = {140 .addr = client->addr,141 .flags = 0,142 .len = sizeof(op),143 .buf = op144 };145 146 ret = isl12026_arm_write(client);147 if (ret)148 return ret;149 150 ret = i2c_transfer(client->adapter, &msg, 1);151 if (ret != 1) {152 dev_err(&client->dev, "write error CCR, ret=%d\n", ret);153 ret = ret < 0 ? ret : -EIO;154 goto out;155 }156 157 msleep(ISL12026_NVMEM_WRITE_TIME);158 159 ret = isl12026_disarm_write(client);160out:161 return ret;162}163 164static int isl12026_rtc_set_time(struct device *dev, struct rtc_time *tm)165{166 struct i2c_client *client = to_i2c_client(dev);167 int ret;168 u8 op[10];169 struct i2c_msg msg = {170 .addr = client->addr,171 .flags = 0,172 .len = sizeof(op),173 .buf = op174 };175 176 ret = isl12026_arm_write(client);177 if (ret)178 return ret;179 180 /* Set the CCR registers */181 op[0] = 0;182 op[1] = ISL12026_REG_SC;183 op[2] = bin2bcd(tm->tm_sec); /* SC */184 op[3] = bin2bcd(tm->tm_min); /* MN */185 op[4] = bin2bcd(tm->tm_hour) | ISL12026_REG_HR_MIL; /* HR */186 op[5] = bin2bcd(tm->tm_mday); /* DT */187 op[6] = bin2bcd(tm->tm_mon + 1); /* MO */188 op[7] = bin2bcd(tm->tm_year % 100); /* YR */189 op[8] = bin2bcd(tm->tm_wday & 7); /* DW */190 op[9] = bin2bcd(tm->tm_year >= 100 ? 20 : 19); /* Y2K */191 ret = i2c_transfer(client->adapter, &msg, 1);192 if (ret != 1) {193 dev_err(&client->dev, "write error CCR, ret=%d\n", ret);194 ret = ret < 0 ? ret : -EIO;195 goto out;196 }197 198 ret = isl12026_disarm_write(client);199out:200 return ret;201}202 203static int isl12026_rtc_read_time(struct device *dev, struct rtc_time *tm)204{205 struct i2c_client *client = to_i2c_client(dev);206 u8 ccr[8];207 u8 addr[2];208 u8 sr;209 int ret;210 struct i2c_msg msgs[] = {211 {212 .addr = client->addr,213 .flags = 0,214 .len = sizeof(addr),215 .buf = addr216 }, {217 .addr = client->addr,218 .flags = I2C_M_RD,219 }220 };221 222 /* First, read SR */223 addr[0] = 0;224 addr[1] = ISL12026_REG_SR;225 msgs[1].len = 1;226 msgs[1].buf = &sr;227 228 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));229 if (ret != ARRAY_SIZE(msgs)) {230 dev_err(&client->dev, "read error, ret=%d\n", ret);231 ret = ret < 0 ? ret : -EIO;232 goto out;233 }234 235 if (sr & ISL12026_REG_SR_RTCF)236 dev_warn(&client->dev, "Real-Time Clock Failure on read\n");237 if (sr & ISL12026_REG_SR_OSCF)238 dev_warn(&client->dev, "Oscillator Failure on read\n");239 240 /* Second, CCR regs */241 addr[0] = 0;242 addr[1] = ISL12026_REG_SC;243 msgs[1].len = sizeof(ccr);244 msgs[1].buf = ccr;245 246 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));247 if (ret != ARRAY_SIZE(msgs)) {248 dev_err(&client->dev, "read error, ret=%d\n", ret);249 ret = ret < 0 ? ret : -EIO;250 goto out;251 }252 253 tm->tm_sec = bcd2bin(ccr[0] & 0x7F);254 tm->tm_min = bcd2bin(ccr[1] & 0x7F);255 if (ccr[2] & ISL12026_REG_HR_MIL)256 tm->tm_hour = bcd2bin(ccr[2] & 0x3F);257 else258 tm->tm_hour = bcd2bin(ccr[2] & 0x1F) +259 ((ccr[2] & 0x20) ? 12 : 0);260 tm->tm_mday = bcd2bin(ccr[3] & 0x3F);261 tm->tm_mon = bcd2bin(ccr[4] & 0x1F) - 1;262 tm->tm_year = bcd2bin(ccr[5]);263 if (bcd2bin(ccr[7]) == 20)264 tm->tm_year += 100;265 tm->tm_wday = ccr[6] & 0x07;266 267 ret = 0;268out:269 return ret;270}271 272static const struct rtc_class_ops isl12026_rtc_ops = {273 .read_time = isl12026_rtc_read_time,274 .set_time = isl12026_rtc_set_time,275};276 277static int isl12026_nvm_read(void *p, unsigned int offset,278 void *val, size_t bytes)279{280 struct isl12026 *priv = p;281 int ret;282 u8 addr[2];283 struct i2c_msg msgs[] = {284 {285 .addr = priv->nvm_client->addr,286 .flags = 0,287 .len = sizeof(addr),288 .buf = addr289 }, {290 .addr = priv->nvm_client->addr,291 .flags = I2C_M_RD,292 .buf = val293 }294 };295 296 /*297 * offset and bytes checked and limited by nvmem core, so298 * proceed without further checks.299 */300 ret = mutex_lock_interruptible(&priv->rtc->ops_lock);301 if (ret)302 return ret;303 304 /* 2 bytes of address, most significant first */305 addr[0] = offset >> 8;306 addr[1] = offset;307 msgs[1].len = bytes;308 ret = i2c_transfer(priv->nvm_client->adapter, msgs, ARRAY_SIZE(msgs));309 310 mutex_unlock(&priv->rtc->ops_lock);311 312 if (ret != ARRAY_SIZE(msgs)) {313 dev_err(&priv->nvm_client->dev,314 "nvmem read error, ret=%d\n", ret);315 return ret < 0 ? ret : -EIO;316 }317 318 return 0;319}320 321static int isl12026_nvm_write(void *p, unsigned int offset,322 void *val, size_t bytes)323{324 struct isl12026 *priv = p;325 int ret;326 u8 *v = val;327 size_t chunk_size, num_written;328 u8 payload[ISL12026_PAGESIZE + 2]; /* page + 2 address bytes */329 struct i2c_msg msgs[] = {330 {331 .addr = priv->nvm_client->addr,332 .flags = 0,333 .buf = payload334 }335 };336 337 /*338 * offset and bytes checked and limited by nvmem core, so339 * proceed without further checks.340 */341 ret = mutex_lock_interruptible(&priv->rtc->ops_lock);342 if (ret)343 return ret;344 345 num_written = 0;346 while (bytes) {347 chunk_size = round_down(offset, ISL12026_PAGESIZE) +348 ISL12026_PAGESIZE - offset;349 chunk_size = min(bytes, chunk_size);350 /*351 * 2 bytes of address, most significant first, followed352 * by page data bytes353 */354 memcpy(payload + 2, v + num_written, chunk_size);355 payload[0] = offset >> 8;356 payload[1] = offset;357 msgs[0].len = chunk_size + 2;358 ret = i2c_transfer(priv->nvm_client->adapter,359 msgs, ARRAY_SIZE(msgs));360 if (ret != ARRAY_SIZE(msgs)) {361 dev_err(&priv->nvm_client->dev,362 "nvmem write error, ret=%d\n", ret);363 ret = ret < 0 ? ret : -EIO;364 break;365 }366 ret = 0;367 bytes -= chunk_size;368 offset += chunk_size;369 num_written += chunk_size;370 msleep(ISL12026_NVMEM_WRITE_TIME);371 }372 373 mutex_unlock(&priv->rtc->ops_lock);374 375 return ret;376}377 378static void isl12026_force_power_modes(struct i2c_client *client)379{380 int ret;381 int pwr, requested_pwr;382 u32 bsw_val, sbib_val;383 bool set_bsw, set_sbib;384 385 /*386 * If we can read the of_property, set the specified value.387 * If there is an error reading the of_property (likely388 * because it does not exist), keep the current value.389 */390 ret = of_property_read_u32(client->dev.of_node,391 "isil,pwr-bsw", &bsw_val);392 set_bsw = (ret == 0);393 394 ret = of_property_read_u32(client->dev.of_node,395 "isil,pwr-sbib", &sbib_val);396 set_sbib = (ret == 0);397 398 /* Check if PWR.BSW and/or PWR.SBIB need specified values */399 if (!set_bsw && !set_sbib)400 return;401 402 pwr = isl12026_read_reg(client, ISL12026_REG_PWR);403 if (pwr < 0) {404 dev_warn(&client->dev, "Error: Failed to read PWR %d\n", pwr);405 return;406 }407 408 requested_pwr = pwr;409 410 if (set_bsw) {411 if (bsw_val)412 requested_pwr |= ISL12026_REG_PWR_BSW;413 else414 requested_pwr &= ~ISL12026_REG_PWR_BSW;415 } /* else keep current BSW */416 417 if (set_sbib) {418 if (sbib_val)419 requested_pwr |= ISL12026_REG_PWR_SBIB;420 else421 requested_pwr &= ~ISL12026_REG_PWR_SBIB;422 } /* else keep current SBIB */423 424 if (pwr >= 0 && pwr != requested_pwr) {425 dev_dbg(&client->dev, "PWR: %02x\n", pwr);426 dev_dbg(&client->dev, "Updating PWR to: %02x\n", requested_pwr);427 isl12026_write_reg(client, ISL12026_REG_PWR, requested_pwr);428 }429}430 431static int isl12026_probe(struct i2c_client *client)432{433 struct isl12026 *priv;434 int ret;435 struct nvmem_config nvm_cfg = {436 .name = "isl12026-",437 .base_dev = &client->dev,438 .stride = 1,439 .word_size = 1,440 .size = 512,441 .reg_read = isl12026_nvm_read,442 .reg_write = isl12026_nvm_write,443 };444 445 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))446 return -ENODEV;447 448 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);449 if (!priv)450 return -ENOMEM;451 452 i2c_set_clientdata(client, priv);453 454 isl12026_force_power_modes(client);455 456 priv->nvm_client = i2c_new_dummy_device(client->adapter, ISL12026_EEPROM_ADDR);457 if (IS_ERR(priv->nvm_client))458 return PTR_ERR(priv->nvm_client);459 460 priv->rtc = devm_rtc_allocate_device(&client->dev);461 ret = PTR_ERR_OR_ZERO(priv->rtc);462 if (ret)463 return ret;464 465 priv->rtc->ops = &isl12026_rtc_ops;466 nvm_cfg.priv = priv;467 ret = devm_rtc_nvmem_register(priv->rtc, &nvm_cfg);468 if (ret)469 return ret;470 471 return devm_rtc_register_device(priv->rtc);472}473 474static void isl12026_remove(struct i2c_client *client)475{476 struct isl12026 *priv = i2c_get_clientdata(client);477 478 i2c_unregister_device(priv->nvm_client);479}480 481static const struct of_device_id isl12026_dt_match[] = {482 { .compatible = "isil,isl12026" },483 { }484};485MODULE_DEVICE_TABLE(of, isl12026_dt_match);486 487static struct i2c_driver isl12026_driver = {488 .driver = {489 .name = "rtc-isl12026",490 .of_match_table = isl12026_dt_match,491 },492 .probe = isl12026_probe,493 .remove = isl12026_remove,494};495 496module_i2c_driver(isl12026_driver);497 498MODULE_DESCRIPTION("ISL 12026 RTC driver");499MODULE_LICENSE("GPL");500