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