brintos

brintos / linux-shallow public Read only

0
0
Text · 10.9 KiB · 2aabb91 Raw
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