root/drivers/hwmon/pmbus/adm1266.c
// SPDX-License-Identifier: GPL-2.0
/*
 * ADM1266 - Cascadable Super Sequencer with Margin
 * Control and Fault Recording
 *
 * Copyright 2020 Analog Devices Inc.
 */

#include <linux/bitfield.h>
#include <linux/crc8.h>
#include <linux/debugfs.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/nvmem-provider.h>
#include "pmbus.h"
#include <linux/slab.h>
#include <linux/timekeeping.h>

#define ADM1266_BLACKBOX_CONFIG 0xD3
#define ADM1266_PDIO_CONFIG     0xD4
#define ADM1266_READ_STATE      0xD9
#define ADM1266_READ_BLACKBOX   0xDE
#define ADM1266_SET_RTC         0xDF
#define ADM1266_GPIO_CONFIG     0xE1
#define ADM1266_BLACKBOX_INFO   0xE6
#define ADM1266_PDIO_STATUS     0xE9
#define ADM1266_GPIO_STATUS     0xEA

/* ADM1266 GPIO defines */
#define ADM1266_GPIO_NR                 9
#define ADM1266_GPIO_FUNCTIONS(x)       FIELD_GET(BIT(0), x)
#define ADM1266_GPIO_INPUT_EN(x)        FIELD_GET(BIT(2), x)
#define ADM1266_GPIO_OUTPUT_EN(x)       FIELD_GET(BIT(3), x)
#define ADM1266_GPIO_OPEN_DRAIN(x)      FIELD_GET(BIT(4), x)

/* ADM1266 PDIO defines */
#define ADM1266_PDIO_NR                 16
#define ADM1266_PDIO_PIN_CFG(x)         FIELD_GET(GENMASK(15, 13), x)
#define ADM1266_PDIO_GLITCH_FILT(x)     FIELD_GET(GENMASK(12, 9), x)
#define ADM1266_PDIO_OUT_CFG(x)         FIELD_GET(GENMASK(2, 0), x)

#define ADM1266_BLACKBOX_OFFSET         0
#define ADM1266_BLACKBOX_SIZE           64

#define ADM1266_PMBUS_BLOCK_MAX         255

struct adm1266_data {
        struct pmbus_driver_info info;
        struct gpio_chip gc;
        const char *gpio_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR];
        struct i2c_client *client;
        struct dentry *debugfs_dir;
        struct nvmem_config nvmem_config;
        struct nvmem_device *nvmem;
        u8 *dev_mem;
        struct mutex buf_mutex;
        u8 write_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned;
        u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1] ____cacheline_aligned;
};

static const struct nvmem_cell_info adm1266_nvmem_cells[] = {
        {
                .name           = "blackbox",
                .offset         = ADM1266_BLACKBOX_OFFSET,
                .bytes          = 2048,
        },
};

DECLARE_CRC8_TABLE(pmbus_crc_table);

/*
 * Different from Block Read as it sends data and waits for the slave to
 * return a value dependent on that data. The protocol is simply a Write Block
 * followed by a Read Block without the Read-Block command field and the
 * Write-Block STOP bit.
 */
static int adm1266_pmbus_block_xfer(struct adm1266_data *data, u8 cmd, u8 w_len, u8 *data_w,
                                    u8 *data_r)
{
        struct i2c_client *client = data->client;
        struct i2c_msg msgs[2] = {
                {
                        .addr = client->addr,
                        .flags = I2C_M_DMA_SAFE,
                        .buf = data->write_buf,
                        .len = w_len + 2,
                },
                {
                        .addr = client->addr,
                        .flags = I2C_M_RD | I2C_M_DMA_SAFE,
                        .buf = data->read_buf,
                        .len = ADM1266_PMBUS_BLOCK_MAX + 2,
                }
        };
        u8 addr;
        u8 crc;
        int ret;

        mutex_lock(&data->buf_mutex);

        msgs[0].buf[0] = cmd;
        msgs[0].buf[1] = w_len;
        memcpy(&msgs[0].buf[2], data_w, w_len);

        ret = i2c_transfer(client->adapter, msgs, 2);
        if (ret != 2) {
                if (ret >= 0)
                        ret = -EPROTO;

                mutex_unlock(&data->buf_mutex);

                return ret;
        }

        if (client->flags & I2C_CLIENT_PEC) {
                addr = i2c_8bit_addr_from_msg(&msgs[0]);
                crc = crc8(pmbus_crc_table, &addr, 1, 0);
                crc = crc8(pmbus_crc_table, msgs[0].buf,  msgs[0].len, crc);

                addr = i2c_8bit_addr_from_msg(&msgs[1]);
                crc = crc8(pmbus_crc_table, &addr, 1, crc);
                crc = crc8(pmbus_crc_table, msgs[1].buf,  msgs[1].buf[0] + 1, crc);

                if (crc != msgs[1].buf[msgs[1].buf[0] + 1]) {
                        mutex_unlock(&data->buf_mutex);
                        return -EBADMSG;
                }
        }

        memcpy(data_r, &msgs[1].buf[1], msgs[1].buf[0]);

        ret = msgs[1].buf[0];
        mutex_unlock(&data->buf_mutex);

        return ret;
}

static const unsigned int adm1266_gpio_mapping[ADM1266_GPIO_NR][2] = {
        {1, 0},
        {2, 1},
        {3, 2},
        {4, 8},
        {5, 9},
        {6, 10},
        {7, 11},
        {8, 6},
        {9, 7},
};

static const char *adm1266_names[ADM1266_GPIO_NR + ADM1266_PDIO_NR] = {
        "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5", "GPIO6", "GPIO7", "GPIO8",
        "GPIO9", "PDIO1", "PDIO2", "PDIO3", "PDIO4", "PDIO5", "PDIO6",
        "PDIO7", "PDIO8", "PDIO9", "PDIO10", "PDIO11", "PDIO12", "PDIO13",
        "PDIO14", "PDIO15", "PDIO16",
};

static int adm1266_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
        struct adm1266_data *data = gpiochip_get_data(chip);
        u8 read_buf[I2C_SMBUS_BLOCK_MAX + 1];
        unsigned long pins_status;
        unsigned int pmbus_cmd;
        int ret;

        if (offset < ADM1266_GPIO_NR)
                pmbus_cmd = ADM1266_GPIO_STATUS;
        else
                pmbus_cmd = ADM1266_PDIO_STATUS;

        ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf);
        if (ret < 0)
                return ret;

        pins_status = read_buf[0] + (read_buf[1] << 8);
        if (offset < ADM1266_GPIO_NR)
                return test_bit(adm1266_gpio_mapping[offset][1], &pins_status);

        return test_bit(offset - ADM1266_GPIO_NR, &pins_status);
}

static int adm1266_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
                                     unsigned long *bits)
{
        struct adm1266_data *data = gpiochip_get_data(chip);
        u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1];
        unsigned long status;
        unsigned int gpio_nr;
        int ret;

        ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf);
        if (ret < 0)
                return ret;

        status = read_buf[0] + (read_buf[1] << 8);

        *bits = 0;
        for_each_set_bit(gpio_nr, mask, ADM1266_GPIO_NR) {
                if (test_bit(adm1266_gpio_mapping[gpio_nr][1], &status))
                        set_bit(gpio_nr, bits);
        }

        ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf);
        if (ret < 0)
                return ret;

        status = read_buf[0] + (read_buf[1] << 8);

        *bits = 0;
        for_each_set_bit_from(gpio_nr, mask, ADM1266_GPIO_NR + ADM1266_PDIO_STATUS) {
                if (test_bit(gpio_nr - ADM1266_GPIO_NR, &status))
                        set_bit(gpio_nr, bits);
        }

        return 0;
}

static void adm1266_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
        struct adm1266_data *data = gpiochip_get_data(chip);
        u8 read_buf[ADM1266_PMBUS_BLOCK_MAX + 1];
        unsigned long gpio_config;
        unsigned long pdio_config;
        unsigned long pin_cfg;
        u8 write_cmd;
        int ret;
        int i;

        for (i = 0; i < ADM1266_GPIO_NR; i++) {
                write_cmd = adm1266_gpio_mapping[i][1];
                ret = adm1266_pmbus_block_xfer(data, ADM1266_GPIO_CONFIG, 1, &write_cmd, read_buf);
                if (ret != 2)
                        return;

                gpio_config = read_buf[0];
                seq_puts(s, adm1266_names[i]);

                seq_puts(s, " ( ");
                if (!ADM1266_GPIO_FUNCTIONS(gpio_config)) {
                        seq_puts(s, "high-Z )\n");
                        continue;
                }
                if (ADM1266_GPIO_INPUT_EN(gpio_config))
                        seq_puts(s, "input ");
                if (ADM1266_GPIO_OUTPUT_EN(gpio_config))
                        seq_puts(s, "output ");
                if (ADM1266_GPIO_OPEN_DRAIN(gpio_config))
                        seq_puts(s, "open-drain )\n");
                else
                        seq_puts(s, "push-pull )\n");
        }

        write_cmd = 0xFF;
        ret = adm1266_pmbus_block_xfer(data, ADM1266_PDIO_CONFIG, 1, &write_cmd, read_buf);
        if (ret != 32)
                return;

        for (i = 0; i < ADM1266_PDIO_NR; i++) {
                seq_puts(s, adm1266_names[ADM1266_GPIO_NR + i]);

                pdio_config = read_buf[2 * i];
                pdio_config += (read_buf[2 * i + 1] << 8);
                pin_cfg = ADM1266_PDIO_PIN_CFG(pdio_config);

                seq_puts(s, " ( ");
                if (!pin_cfg || pin_cfg > 5) {
                        seq_puts(s, "high-Z )\n");
                        continue;
                }

                if (pin_cfg & BIT(0))
                        seq_puts(s, "output ");

                if (pin_cfg & BIT(1))
                        seq_puts(s, "input ");

                seq_puts(s, ")\n");
        }
}

static int adm1266_config_gpio(struct adm1266_data *data)
{
        const char *name = dev_name(&data->client->dev);
        char *gpio_name;
        int ret;
        int i;

        for (i = 0; i < ARRAY_SIZE(data->gpio_names); i++) {
                gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%x-%s",
                                           data->client->addr, adm1266_names[i]);
                if (!gpio_name)
                        return -ENOMEM;

                data->gpio_names[i] = gpio_name;
        }

        data->gc.label = name;
        data->gc.parent = &data->client->dev;
        data->gc.owner = THIS_MODULE;
        data->gc.can_sleep = true;
        data->gc.base = -1;
        data->gc.names = data->gpio_names;
        data->gc.ngpio = ARRAY_SIZE(data->gpio_names);
        data->gc.get = adm1266_gpio_get;
        data->gc.get_multiple = adm1266_gpio_get_multiple;
        data->gc.dbg_show = adm1266_gpio_dbg_show;

        ret = devm_gpiochip_add_data(&data->client->dev, &data->gc, data);
        if (ret)
                dev_err(&data->client->dev, "GPIO registering failed (%d)\n", ret);

        return ret;
}

static int adm1266_state_read(struct seq_file *s, void *pdata)
{
        struct device *dev = s->private;
        struct i2c_client *client = to_i2c_client(dev);
        int ret;

        ret = i2c_smbus_read_word_data(client, ADM1266_READ_STATE);
        if (ret < 0)
                return ret;

        seq_printf(s, "%d\n", ret);

        return 0;
}

static void adm1266_init_debugfs(struct adm1266_data *data)
{
        struct dentry *root;

        root = pmbus_get_debugfs_dir(data->client);
        if (!root)
                return;

        data->debugfs_dir = debugfs_create_dir(data->client->name, root);

        debugfs_create_devm_seqfile(&data->client->dev, "sequencer_state", data->debugfs_dir,
                                    adm1266_state_read);
}

static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff)
{
        int record_count;
        char index;
        u8 buf[5];
        int ret;

        ret = i2c_smbus_read_block_data(data->client, ADM1266_BLACKBOX_INFO, buf);
        if (ret < 0)
                return ret;

        if (ret != 4)
                return -EIO;

        record_count = buf[3];

        for (index = 0; index < record_count; index++) {
                ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, 1, &index, read_buff);
                if (ret < 0)
                        return ret;

                if (ret != ADM1266_BLACKBOX_SIZE)
                        return -EIO;

                read_buff += ADM1266_BLACKBOX_SIZE;
        }

        return 0;
}

static int adm1266_nvmem_read(void *priv, unsigned int offset, void *val, size_t bytes)
{
        struct adm1266_data *data = priv;
        int ret;

        if (offset + bytes > data->nvmem_config.size)
                return -EINVAL;

        if (offset == 0) {
                memset(data->dev_mem, 0, data->nvmem_config.size);

                ret = adm1266_nvmem_read_blackbox(data, data->dev_mem);
                if (ret) {
                        dev_err(&data->client->dev, "Could not read blackbox!");
                        return ret;
                }
        }

        memcpy(val, data->dev_mem + offset, bytes);

        return 0;
}

static int adm1266_config_nvmem(struct adm1266_data *data)
{
        data->nvmem_config.name = dev_name(&data->client->dev);
        data->nvmem_config.dev = &data->client->dev;
        data->nvmem_config.root_only = true;
        data->nvmem_config.read_only = true;
        data->nvmem_config.owner = THIS_MODULE;
        data->nvmem_config.reg_read = adm1266_nvmem_read;
        data->nvmem_config.cells = adm1266_nvmem_cells;
        data->nvmem_config.ncells = ARRAY_SIZE(adm1266_nvmem_cells);
        data->nvmem_config.priv = data;
        data->nvmem_config.stride = 1;
        data->nvmem_config.word_size = 1;
        data->nvmem_config.size = adm1266_nvmem_cells[0].bytes;

        data->dev_mem = devm_kzalloc(&data->client->dev, data->nvmem_config.size, GFP_KERNEL);
        if (!data->dev_mem)
                return -ENOMEM;

        data->nvmem = devm_nvmem_register(&data->client->dev, &data->nvmem_config);
        if (IS_ERR(data->nvmem)) {
                dev_err(&data->client->dev, "Could not register nvmem!");
                return PTR_ERR(data->nvmem);
        }

        return 0;
}

static int adm1266_set_rtc(struct adm1266_data *data)
{
        time64_t kt;
        char write_buf[6];
        int i;

        kt = ktime_get_seconds();

        memset(write_buf, 0, sizeof(write_buf));

        for (i = 0; i < 4; i++)
                write_buf[2 + i] = (kt >> (i * 8)) & 0xFF;

        return i2c_smbus_write_block_data(data->client, ADM1266_SET_RTC, sizeof(write_buf),
                                          write_buf);
}

static int adm1266_probe(struct i2c_client *client)
{
        struct adm1266_data *data;
        int ret;
        int i;

        data = devm_kzalloc(&client->dev, sizeof(struct adm1266_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;

        data->client = client;
        data->info.pages = 17;
        data->info.format[PSC_VOLTAGE_OUT] = linear;
        for (i = 0; i < data->info.pages; i++)
                data->info.func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;

        crc8_populate_msb(pmbus_crc_table, 0x7);
        mutex_init(&data->buf_mutex);

        ret = adm1266_config_gpio(data);
        if (ret < 0)
                return ret;

        ret = adm1266_set_rtc(data);
        if (ret < 0)
                return ret;

        ret = adm1266_config_nvmem(data);
        if (ret < 0)
                return ret;

        ret = pmbus_do_probe(client, &data->info);
        if (ret)
                return ret;

        adm1266_init_debugfs(data);

        return 0;
}

static const struct of_device_id adm1266_of_match[] = {
        { .compatible = "adi,adm1266" },
        { }
};
MODULE_DEVICE_TABLE(of, adm1266_of_match);

static const struct i2c_device_id adm1266_id[] = {
        { "adm1266" },
        { }
};
MODULE_DEVICE_TABLE(i2c, adm1266_id);

static struct i2c_driver adm1266_driver = {
        .driver = {
                   .name = "adm1266",
                   .of_match_table = adm1266_of_match,
                  },
        .probe = adm1266_probe,
        .id_table = adm1266_id,
};

module_i2c_driver(adm1266_driver);

MODULE_AUTHOR("Alexandru Tachici <alexandru.tachici@analog.com>");
MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1266");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS("PMBUS");