18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ADM1266 - Cascadable Super Sequencer with Margin
48c2ecf20Sopenharmony_ci * Control and Fault Recording
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2020 Analog Devices Inc.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
108c2ecf20Sopenharmony_ci#include <linux/crc8.h>
118c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
128c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/i2c-smbus.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/nvmem-consumer.h>
198c2ecf20Sopenharmony_ci#include <linux/nvmem-provider.h>
208c2ecf20Sopenharmony_ci#include "pmbus.h"
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include <linux/timekeeping.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define ADM1266_BLACKBOX_CONFIG	0xD3
258c2ecf20Sopenharmony_ci#define ADM1266_PDIO_CONFIG	0xD4
268c2ecf20Sopenharmony_ci#define ADM1266_READ_STATE	0xD9
278c2ecf20Sopenharmony_ci#define ADM1266_READ_BLACKBOX	0xDE
288c2ecf20Sopenharmony_ci#define ADM1266_SET_RTC		0xDF
298c2ecf20Sopenharmony_ci#define ADM1266_GPIO_CONFIG	0xE1
308c2ecf20Sopenharmony_ci#define ADM1266_BLACKBOX_INFO	0xE6
318c2ecf20Sopenharmony_ci#define ADM1266_PDIO_STATUS	0xE9
328c2ecf20Sopenharmony_ci#define ADM1266_GPIO_STATUS	0xEA
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* ADM1266 GPIO defines */
358c2ecf20Sopenharmony_ci#define ADM1266_GPIO_NR			9
368c2ecf20Sopenharmony_ci#define ADM1266_GPIO_FUNCTIONS(x)	FIELD_GET(BIT(0), x)
378c2ecf20Sopenharmony_ci#define ADM1266_GPIO_INPUT_EN(x)	FIELD_GET(BIT(2), x)
388c2ecf20Sopenharmony_ci#define ADM1266_GPIO_OUTPUT_EN(x)	FIELD_GET(BIT(3), x)
398c2ecf20Sopenharmony_ci#define ADM1266_GPIO_OPEN_DRAIN(x)	FIELD_GET(BIT(4), x)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* ADM1266 PDIO defines */
428c2ecf20Sopenharmony_ci#define ADM1266_PDIO_NR			16
438c2ecf20Sopenharmony_ci#define ADM1266_PDIO_PIN_CFG(x)		FIELD_GET(GENMASK(15, 13), x)
448c2ecf20Sopenharmony_ci#define ADM1266_PDIO_GLITCH_FILT(x)	FIELD_GET(GENMASK(12, 9), x)
458c2ecf20Sopenharmony_ci#define ADM1266_PDIO_OUT_CFG(x)		FIELD_GET(GENMASK(2, 0), x)
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define ADM1266_BLACKBOX_OFFSET		0
488c2ecf20Sopenharmony_ci#define ADM1266_BLACKBOX_SIZE		64
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define ADM1266_PMBUS_BLOCK_MAX		255
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistruct adm1266_data {
538c2ecf20Sopenharmony_ci	struct pmbus_driver_info info;
548c2ecf20Sopenharmony_ci	struct gpio_chip gc;
558c2ecf20Sopenharmony_ci	const char *gpio_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR];
568c2ecf20Sopenharmony_ci	struct i2c_client *client;
578c2ecf20Sopenharmony_ci	struct dentry *debugfs_dir;
588c2ecf20Sopenharmony_ci	struct nvmem_config nvmem_config;
598c2ecf20Sopenharmony_ci	struct nvmem_device *nvmem;
608c2ecf20Sopenharmony_ci	u8 *dev_mem;
618c2ecf20Sopenharmony_ci	struct mutex buf_mutex;
628c2ecf20Sopenharmony_ci	u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned;
638c2ecf20Sopenharmony_ci	u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned;
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic const struct nvmem_cell_info adm1266_nvmem_cells[] = {
678c2ecf20Sopenharmony_ci	{
688c2ecf20Sopenharmony_ci		.name           = "blackbox",
698c2ecf20Sopenharmony_ci		.offset         = ADM1266_BLACKBOX_OFFSET,
708c2ecf20Sopenharmony_ci		.bytes          = 2048,
718c2ecf20Sopenharmony_ci	},
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciDECLARE_CRC8_TABLE(pmbus_crc_table);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/*
778c2ecf20Sopenharmony_ci * Different from Block Read as it sends data and waits for the slave to
788c2ecf20Sopenharmony_ci * return a value dependent on that data. The protocol is simply a Write Block
798c2ecf20Sopenharmony_ci * followed by a Read Block without the Read-Block command field and the
808c2ecf20Sopenharmony_ci * Write-Block STOP bit.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_cistatic int adm1266_pmbus_block_xfer(struct adm1266_data *data, u8 cmd, u8 w_len, u8 *data_w,
838c2ecf20Sopenharmony_ci				    u8 *data_r)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
868c2ecf20Sopenharmony_ci	struct i2c_msg msgs[2] = {
878c2ecf20Sopenharmony_ci		{
888c2ecf20Sopenharmony_ci			.addr = client->addr,
898c2ecf20Sopenharmony_ci			.flags = I2C_M_DMA_SAFE,
908c2ecf20Sopenharmony_ci			.buf = data->write_buf,
918c2ecf20Sopenharmony_ci			.len = w_len + 2,
928c2ecf20Sopenharmony_ci		},
938c2ecf20Sopenharmony_ci		{
948c2ecf20Sopenharmony_ci			.addr = client->addr,
958c2ecf20Sopenharmony_ci			.flags = I2C_M_RD | I2C_M_DMA_SAFE,
968c2ecf20Sopenharmony_ci			.buf = data->read_buf,
978c2ecf20Sopenharmony_ci			.len = ADM1266_PMBUS_BLOCK_MAX + 2,
988c2ecf20Sopenharmony_ci		}
998c2ecf20Sopenharmony_ci	};
1008c2ecf20Sopenharmony_ci	u8 addr;
1018c2ecf20Sopenharmony_ci	u8 crc;
1028c2ecf20Sopenharmony_ci	int ret;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	mutex_lock(&data->buf_mutex);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	msgs[0].buf[0] = cmd;
1078c2ecf20Sopenharmony_ci	msgs[0].buf[1] = w_len;
1088c2ecf20Sopenharmony_ci	memcpy(&msgs[0].buf[2], data_w, w_len);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	ret = i2c_transfer(client->adapter, msgs, 2);
1118c2ecf20Sopenharmony_ci	if (ret != 2) {
1128c2ecf20Sopenharmony_ci		if (ret >= 0)
1138c2ecf20Sopenharmony_ci			ret = -EPROTO;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci		mutex_unlock(&data->buf_mutex);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci		return ret;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (client->flags & I2C_CLIENT_PEC) {
1218c2ecf20Sopenharmony_ci		addr = i2c_8bit_addr_from_msg(&msgs[0]);
1228c2ecf20Sopenharmony_ci		crc = crc8(pmbus_crc_table, &addr, 1, 0);
1238c2ecf20Sopenharmony_ci		crc = crc8(pmbus_crc_table, msgs[0].buf,  msgs[0].len, crc);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci		addr = i2c_8bit_addr_from_msg(&msgs[1]);
1268c2ecf20Sopenharmony_ci		crc = crc8(pmbus_crc_table, &addr, 1, crc);
1278c2ecf20Sopenharmony_ci		crc = crc8(pmbus_crc_table, msgs[1].buf,  msgs[1].buf[0] + 1, crc);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci		if (crc != msgs[1].buf[msgs[1].buf[0] + 1]) {
1308c2ecf20Sopenharmony_ci			mutex_unlock(&data->buf_mutex);
1318c2ecf20Sopenharmony_ci			return -EBADMSG;
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	memcpy(data_r, &msgs[1].buf[1], msgs[1].buf[0]);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	ret = msgs[1].buf[0];
1388c2ecf20Sopenharmony_ci	mutex_unlock(&data->buf_mutex);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return ret;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic const unsigned int adm1266_gpio_mapping[ADM1266_GPIO_NR][2] = {
1448c2ecf20Sopenharmony_ci	{1, 0},
1458c2ecf20Sopenharmony_ci	{2, 1},
1468c2ecf20Sopenharmony_ci	{3, 2},
1478c2ecf20Sopenharmony_ci	{4, 8},
1488c2ecf20Sopenharmony_ci	{5, 9},
1498c2ecf20Sopenharmony_ci	{6, 10},
1508c2ecf20Sopenharmony_ci	{7, 11},
1518c2ecf20Sopenharmony_ci	{8, 6},
1528c2ecf20Sopenharmony_ci	{9, 7},
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic const char *adm1266_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR] = {
1568c2ecf20Sopenharmony_ci	"GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", "GPIO6", "GPIO7", "GPIO8",
1578c2ecf20Sopenharmony_ci	"GPIO9", "PDIO1", "PDIO2", "PDIO3", "PDIO4", "PDIO5", "PDIO6",
1588c2ecf20Sopenharmony_ci	"PDIO7", "PDIO8", "PDIO9", "PDIO10", "PDIO11", "PDIO12", "PDIO13",
1598c2ecf20Sopenharmony_ci	"PDIO14", "PDIO15", "PDIO16",
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int adm1266_gpio_get(struct gpio_chip *chip, unsigned int offset)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct adm1266_data *data = gpiochip_get_data(chip);
1658c2ecf20Sopenharmony_ci	u8 read_buf[I2C_SMBUS_BLOCK_MAX + 1];
1668c2ecf20Sopenharmony_ci	unsigned long pins_status;
1678c2ecf20Sopenharmony_ci	unsigned int pmbus_cmd;
1688c2ecf20Sopenharmony_ci	int ret;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (offset < ADM1266_GPIO_NR)
1718c2ecf20Sopenharmony_ci		pmbus_cmd = ADM1266_GPIO_STATUS;
1728c2ecf20Sopenharmony_ci	else
1738c2ecf20Sopenharmony_ci		pmbus_cmd = ADM1266_PDIO_STATUS;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf);
1768c2ecf20Sopenharmony_ci	if (ret < 0)
1778c2ecf20Sopenharmony_ci		return ret;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	pins_status = read_buf[0] + (read_buf[1] << 8);
1808c2ecf20Sopenharmony_ci	if (offset < ADM1266_GPIO_NR)
1818c2ecf20Sopenharmony_ci		return test_bit(adm1266_gpio_mapping[offset][1], &pins_status);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	return test_bit(offset - ADM1266_GPIO_NR, &pins_status);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
1878c2ecf20Sopenharmony_ci				     unsigned long *bits)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct adm1266_data *data = gpiochip_get_data(chip);
1908c2ecf20Sopenharmony_ci	u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1];
1918c2ecf20Sopenharmony_ci	unsigned long status;
1928c2ecf20Sopenharmony_ci	unsigned int gpio_nr;
1938c2ecf20Sopenharmony_ci	int ret;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf);
1968c2ecf20Sopenharmony_ci	if (ret < 0)
1978c2ecf20Sopenharmony_ci		return ret;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	status = read_buf[0] + (read_buf[1] << 8);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	*bits = 0;
2028c2ecf20Sopenharmony_ci	for_each_set_bit(gpio_nr, mask, ADM1266_GPIO_NR) {
2038c2ecf20Sopenharmony_ci		if (test_bit(adm1266_gpio_mapping[gpio_nr][1], &status))
2048c2ecf20Sopenharmony_ci			set_bit(gpio_nr, bits);
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf);
2088c2ecf20Sopenharmony_ci	if (ret < 0)
2098c2ecf20Sopenharmony_ci		return ret;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	status = read_buf[0] + (read_buf[1] << 8);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	*bits = 0;
2148c2ecf20Sopenharmony_ci	for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_STATUS) {
2158c2ecf20Sopenharmony_ci		if (test_bit(gpio_nr - ADM1266_GPIO_NR, &status))
2168c2ecf20Sopenharmony_ci			set_bit(gpio_nr, bits);
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	return 0;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic void adm1266_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct adm1266_data *data = gpiochip_get_data(chip);
2258c2ecf20Sopenharmony_ci	u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1];
2268c2ecf20Sopenharmony_ci	unsigned long gpio_config;
2278c2ecf20Sopenharmony_ci	unsigned long pdio_config;
2288c2ecf20Sopenharmony_ci	unsigned long pin_cfg;
2298c2ecf20Sopenharmony_ci	u8 write_cmd;
2308c2ecf20Sopenharmony_ci	int ret;
2318c2ecf20Sopenharmony_ci	int i;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	for (i = 0; i < ADM1266_GPIO_NR; i++) {
2348c2ecf20Sopenharmony_ci		write_cmd = adm1266_gpio_mapping[i][1];
2358c2ecf20Sopenharmony_ci		ret = adm1266_pmbus_block_xfer(data, ADM1266_GPIO_CONFIG, 1, &write_cmd, read_buf);
2368c2ecf20Sopenharmony_ci		if (ret != 2)
2378c2ecf20Sopenharmony_ci			return;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci		gpio_config = read_buf[0];
2408c2ecf20Sopenharmony_ci		seq_puts(s, adm1266_names[i]);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		seq_puts(s, " ( ");
2438c2ecf20Sopenharmony_ci		if (!ADM1266_GPIO_FUNCTIONS(gpio_config)) {
2448c2ecf20Sopenharmony_ci			seq_puts(s, "high-Z )\n");
2458c2ecf20Sopenharmony_ci			continue;
2468c2ecf20Sopenharmony_ci		}
2478c2ecf20Sopenharmony_ci		if (ADM1266_GPIO_INPUT_EN(gpio_config))
2488c2ecf20Sopenharmony_ci			seq_puts(s, "input ");
2498c2ecf20Sopenharmony_ci		if (ADM1266_GPIO_OUTPUT_EN(gpio_config))
2508c2ecf20Sopenharmony_ci			seq_puts(s, "output ");
2518c2ecf20Sopenharmony_ci		if (ADM1266_GPIO_OPEN_DRAIN(gpio_config))
2528c2ecf20Sopenharmony_ci			seq_puts(s, "open-drain )\n");
2538c2ecf20Sopenharmony_ci		else
2548c2ecf20Sopenharmony_ci			seq_puts(s, "push-pull )\n");
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	write_cmd = 0xFF;
2588c2ecf20Sopenharmony_ci	ret = adm1266_pmbus_block_xfer(data, ADM1266_PDIO_CONFIG, 1, &write_cmd, read_buf);
2598c2ecf20Sopenharmony_ci	if (ret != 32)
2608c2ecf20Sopenharmony_ci		return;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	for (i = 0; i < ADM1266_PDIO_NR; i++) {
2638c2ecf20Sopenharmony_ci		seq_puts(s, adm1266_names[ADM1266_GPIO_NR + i]);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci		pdio_config = read_buf[2 * i];
2668c2ecf20Sopenharmony_ci		pdio_config += (read_buf[2 * i + 1] << 8);
2678c2ecf20Sopenharmony_ci		pin_cfg = ADM1266_PDIO_PIN_CFG(pdio_config);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		seq_puts(s, " ( ");
2708c2ecf20Sopenharmony_ci		if (!pin_cfg || pin_cfg > 5) {
2718c2ecf20Sopenharmony_ci			seq_puts(s, "high-Z )\n");
2728c2ecf20Sopenharmony_ci			continue;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		if (pin_cfg & BIT(0))
2768c2ecf20Sopenharmony_ci			seq_puts(s, "output ");
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		if (pin_cfg & BIT(1))
2798c2ecf20Sopenharmony_ci			seq_puts(s, "input ");
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		seq_puts(s, ")\n");
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int adm1266_config_gpio(struct adm1266_data *data)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	const char *name = dev_name(&data->client->dev);
2888c2ecf20Sopenharmony_ci	char *gpio_name;
2898c2ecf20Sopenharmony_ci	int ret;
2908c2ecf20Sopenharmony_ci	int i;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->gpio_names); i++) {
2938c2ecf20Sopenharmony_ci		gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%x-%s",
2948c2ecf20Sopenharmony_ci					   data->client->addr, adm1266_names[i]);
2958c2ecf20Sopenharmony_ci		if (!gpio_name)
2968c2ecf20Sopenharmony_ci			return -ENOMEM;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci		data->gpio_names[i] = gpio_name;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	data->gc.label = name;
3028c2ecf20Sopenharmony_ci	data->gc.parent = &data->client->dev;
3038c2ecf20Sopenharmony_ci	data->gc.owner = THIS_MODULE;
3048c2ecf20Sopenharmony_ci	data->gc.can_sleep = true;
3058c2ecf20Sopenharmony_ci	data->gc.base = -1;
3068c2ecf20Sopenharmony_ci	data->gc.names = data->gpio_names;
3078c2ecf20Sopenharmony_ci	data->gc.ngpio = ARRAY_SIZE(data->gpio_names);
3088c2ecf20Sopenharmony_ci	data->gc.get = adm1266_gpio_get;
3098c2ecf20Sopenharmony_ci	data->gc.get_multiple = adm1266_gpio_get_multiple;
3108c2ecf20Sopenharmony_ci	data->gc.dbg_show = adm1266_gpio_dbg_show;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	ret = devm_gpiochip_add_data(&data->client->dev, &data->gc, data);
3138c2ecf20Sopenharmony_ci	if (ret)
3148c2ecf20Sopenharmony_ci		dev_err(&data->client->dev, "GPIO registering failed (%d)\n", ret);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return ret;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cistatic int adm1266_state_read(struct seq_file *s, void *pdata)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	struct device *dev = s->private;
3228c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
3238c2ecf20Sopenharmony_ci	int ret;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_word_data(client, ADM1266_READ_STATE);
3268c2ecf20Sopenharmony_ci	if (ret < 0)
3278c2ecf20Sopenharmony_ci		return ret;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	seq_printf(s, "%d\n", ret);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return 0;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic void adm1266_init_debugfs(struct adm1266_data *data)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct dentry *root;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	root = pmbus_get_debugfs_dir(data->client);
3398c2ecf20Sopenharmony_ci	if (!root)
3408c2ecf20Sopenharmony_ci		return;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	data->debugfs_dir = debugfs_create_dir(data->client->name, root);
3438c2ecf20Sopenharmony_ci	if (!data->debugfs_dir)
3448c2ecf20Sopenharmony_ci		return;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	debugfs_create_devm_seqfile(&data->client->dev, "sequencer_state", data->debugfs_dir,
3478c2ecf20Sopenharmony_ci				    adm1266_state_read);
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	int record_count;
3538c2ecf20Sopenharmony_ci	char index;
3548c2ecf20Sopenharmony_ci	u8 buf[5];
3558c2ecf20Sopenharmony_ci	int ret;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf);
3588c2ecf20Sopenharmony_ci	if (ret < 0)
3598c2ecf20Sopenharmony_ci		return ret;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (ret != 4)
3628c2ecf20Sopenharmony_ci		return -EIO;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	record_count = buf[3];
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	for (index = 0; index < record_count; index++) {
3678c2ecf20Sopenharmony_ci		ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, read_buff);
3688c2ecf20Sopenharmony_ci		if (ret < 0)
3698c2ecf20Sopenharmony_ci			return ret;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci		if (ret != ADM1266_BLACKBOX_SIZE)
3728c2ecf20Sopenharmony_ci			return -EIO;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		read_buff += ADM1266_BLACKBOX_SIZE;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return 0;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic int adm1266_nvmem_read(void *priv, unsigned int offset, void *val, size_t bytes)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	struct adm1266_data *data = priv;
3838c2ecf20Sopenharmony_ci	int ret;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (offset + bytes > data->nvmem_config.size)
3868c2ecf20Sopenharmony_ci		return -EINVAL;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (offset == 0) {
3898c2ecf20Sopenharmony_ci		memset(data->dev_mem, 0, data->nvmem_config.size);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		ret = adm1266_nvmem_read_blackbox(data, data->dev_mem);
3928c2ecf20Sopenharmony_ci		if (ret) {
3938c2ecf20Sopenharmony_ci			dev_err(&data->client->dev, "Could not read blackbox!");
3948c2ecf20Sopenharmony_ci			return ret;
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	memcpy(val, data->dev_mem + offset, bytes);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	return 0;
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic int adm1266_config_nvmem(struct adm1266_data *data)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	data->nvmem_config.name = dev_name(&data->client->dev);
4068c2ecf20Sopenharmony_ci	data->nvmem_config.dev = &data->client->dev;
4078c2ecf20Sopenharmony_ci	data->nvmem_config.root_only = true;
4088c2ecf20Sopenharmony_ci	data->nvmem_config.read_only = true;
4098c2ecf20Sopenharmony_ci	data->nvmem_config.owner = THIS_MODULE;
4108c2ecf20Sopenharmony_ci	data->nvmem_config.reg_read = adm1266_nvmem_read;
4118c2ecf20Sopenharmony_ci	data->nvmem_config.cells = adm1266_nvmem_cells;
4128c2ecf20Sopenharmony_ci	data->nvmem_config.ncells = ARRAY_SIZE(adm1266_nvmem_cells);
4138c2ecf20Sopenharmony_ci	data->nvmem_config.priv = data;
4148c2ecf20Sopenharmony_ci	data->nvmem_config.stride = 1;
4158c2ecf20Sopenharmony_ci	data->nvmem_config.word_size = 1;
4168c2ecf20Sopenharmony_ci	data->nvmem_config.size = adm1266_nvmem_cells[0].bytes;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	data->dev_mem = devm_kzalloc(&data->client->dev, data->nvmem_config.size, GFP_KERNEL);
4198c2ecf20Sopenharmony_ci	if (!data->dev_mem)
4208c2ecf20Sopenharmony_ci		return -ENOMEM;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	data->nvmem = devm_nvmem_register(&data->client->dev, &data->nvmem_config);
4238c2ecf20Sopenharmony_ci	if (IS_ERR(data->nvmem)) {
4248c2ecf20Sopenharmony_ci		dev_err(&data->client->dev, "Could not register nvmem!");
4258c2ecf20Sopenharmony_ci		return PTR_ERR(data->nvmem);
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	return 0;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic int adm1266_set_rtc(struct adm1266_data *data)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	time64_t kt;
4348c2ecf20Sopenharmony_ci	char write_buf[6];
4358c2ecf20Sopenharmony_ci	int i;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	kt = ktime_get_seconds();
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	memset(write_buf, 0, sizeof(write_buf));
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
4428c2ecf20Sopenharmony_ci		write_buf[2 + i] = (kt >> (i * 8)) & 0xFF;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	return i2c_smbus_write_block_data(data->client, ADM1266_SET_RTC, sizeof(write_buf),
4458c2ecf20Sopenharmony_ci					  write_buf);
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic int adm1266_probe(struct i2c_client *client)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	struct adm1266_data *data;
4518c2ecf20Sopenharmony_ci	int ret;
4528c2ecf20Sopenharmony_ci	int i;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	data = devm_kzalloc(&client->dev, sizeof(struct adm1266_data), GFP_KERNEL);
4558c2ecf20Sopenharmony_ci	if (!data)
4568c2ecf20Sopenharmony_ci		return -ENOMEM;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	data->client = client;
4598c2ecf20Sopenharmony_ci	data->info.pages = 17;
4608c2ecf20Sopenharmony_ci	data->info.format[PSC_VOLTAGE_OUT] = linear;
4618c2ecf20Sopenharmony_ci	for (i = 0; i < data->info.pages; i++)
4628c2ecf20Sopenharmony_ci		data->info.func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	crc8_populate_msb(pmbus_crc_table, 0x7);
4658c2ecf20Sopenharmony_ci	mutex_init(&data->buf_mutex);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	ret = adm1266_config_gpio(data);
4688c2ecf20Sopenharmony_ci	if (ret < 0)
4698c2ecf20Sopenharmony_ci		return ret;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	ret = adm1266_set_rtc(data);
4728c2ecf20Sopenharmony_ci	if (ret < 0)
4738c2ecf20Sopenharmony_ci		return ret;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	ret = adm1266_config_nvmem(data);
4768c2ecf20Sopenharmony_ci	if (ret < 0)
4778c2ecf20Sopenharmony_ci		return ret;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	ret = pmbus_do_probe(client, &data->info);
4808c2ecf20Sopenharmony_ci	if (ret)
4818c2ecf20Sopenharmony_ci		return ret;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	adm1266_init_debugfs(data);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic const struct of_device_id adm1266_of_match[] = {
4898c2ecf20Sopenharmony_ci	{ .compatible = "adi,adm1266" },
4908c2ecf20Sopenharmony_ci	{ }
4918c2ecf20Sopenharmony_ci};
4928c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, adm1266_of_match);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic const struct i2c_device_id adm1266_id[] = {
4958c2ecf20Sopenharmony_ci	{ "adm1266", 0 },
4968c2ecf20Sopenharmony_ci	{ }
4978c2ecf20Sopenharmony_ci};
4988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adm1266_id);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic struct i2c_driver adm1266_driver = {
5018c2ecf20Sopenharmony_ci	.driver = {
5028c2ecf20Sopenharmony_ci		   .name = "adm1266",
5038c2ecf20Sopenharmony_ci		   .of_match_table = adm1266_of_match,
5048c2ecf20Sopenharmony_ci		  },
5058c2ecf20Sopenharmony_ci	.probe_new = adm1266_probe,
5068c2ecf20Sopenharmony_ci	.remove = pmbus_do_remove,
5078c2ecf20Sopenharmony_ci	.id_table = adm1266_id,
5088c2ecf20Sopenharmony_ci};
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cimodule_i2c_driver(adm1266_driver);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexandru Tachici <alexandru.tachici@analog.com>");
5138c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1266");
5148c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
515