diff options
| author | Dmitry Torokhov <[email protected]> | 2023-05-01 15:20:08 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-05-01 15:20:08 -0700 | 
| commit | 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e (patch) | |
| tree | d57f3a63479a07b4e0cece029886e76e04feb984 /drivers/rtc/rtc-abx80x.c | |
| parent | 5dc63e56a9cf8df0b59c234a505a1653f1bdf885 (diff) | |
| parent | 53bea86b5712c7491bb3dae12e271666df0a308c (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.4 merge window.
Diffstat (limited to 'drivers/rtc/rtc-abx80x.c')
| -rw-r--r-- | drivers/rtc/rtc-abx80x.c | 77 | 
1 files changed, 77 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 2e0e6432901b..f34a2e59cac7 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -11,6 +11,7 @@   */  #include <linux/bcd.h> +#include <linux/bitfield.h>  #include <linux/i2c.h>  #include <linux/kstrtox.h>  #include <linux/module.h> @@ -88,6 +89,16 @@  #define ABX8XX_TRICKLE_STANDARD_DIODE	0x8  #define ABX8XX_TRICKLE_SCHOTTKY_DIODE	0x4 +#define ABX8XX_REG_EXTRAM	0x3f +#define ABX8XX_EXTRAM_XADS	GENMASK(1, 0) + +#define ABX8XX_SRAM_BASE	0x40 +#define ABX8XX_SRAM_WIN_SIZE	0x40 +#define ABX8XX_RAM_SIZE		256 + +#define NVMEM_ADDR_LOWER	GENMASK(5, 0) +#define NVMEM_ADDR_UPPER	GENMASK(7, 6) +  static u8 trickle_resistors[] = {0, 3, 6, 11};  enum abx80x_chip {AB0801, AB0803, AB0804, AB0805, @@ -674,6 +685,68 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv)  }  #endif +static int abx80x_nvmem_xfer(struct abx80x_priv *priv, unsigned int offset, +			     void *val, size_t bytes, bool write) +{ +	int ret; + +	while (bytes) { +		u8 extram, reg, len, lower, upper; + +		lower = FIELD_GET(NVMEM_ADDR_LOWER, offset); +		upper = FIELD_GET(NVMEM_ADDR_UPPER, offset); +		extram = FIELD_PREP(ABX8XX_EXTRAM_XADS, upper); +		reg = ABX8XX_SRAM_BASE + lower; +		len = min(lower + bytes, (size_t)ABX8XX_SRAM_WIN_SIZE) - lower; +		len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); + +		ret = i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_EXTRAM, +						extram); +		if (ret) +			return ret; + +		if (write) +			ret = i2c_smbus_write_i2c_block_data(priv->client, reg, +							     len, val); +		else +			ret = i2c_smbus_read_i2c_block_data(priv->client, reg, +							    len, val); +		if (ret) +			return ret; + +		offset += len; +		val += len; +		bytes -= len; +	} + +	return 0; +} + +static int abx80x_nvmem_read(void *priv, unsigned int offset, void *val, +			     size_t bytes) +{ +	return abx80x_nvmem_xfer(priv, offset, val, bytes, false); +} + +static int abx80x_nvmem_write(void *priv, unsigned int offset, void *val, +			      size_t bytes) +{ +	return abx80x_nvmem_xfer(priv, offset, val, bytes, true); +} + +static int abx80x_setup_nvmem(struct abx80x_priv *priv) +{ +	struct nvmem_config config = { +		.type = NVMEM_TYPE_BATTERY_BACKED, +		.reg_read = abx80x_nvmem_read, +		.reg_write = abx80x_nvmem_write, +		.size = ABX8XX_RAM_SIZE, +		.priv = priv, +	}; + +	return devm_rtc_nvmem_register(priv->rtc, &config); +} +  static const struct i2c_device_id abx80x_id[] = {  	{ "abx80x", ABX80X },  	{ "ab0801", AB0801 }, @@ -840,6 +913,10 @@ static int abx80x_probe(struct i2c_client *client)  			return err;  	} +	err = abx80x_setup_nvmem(priv); +	if (err) +		return err; +  	if (client->irq > 0) {  		dev_info(&client->dev, "IRQ %d supplied\n", client->irq);  		err = devm_request_threaded_irq(&client->dev, client->irq, NULL,  |