From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:50 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux driver --- kernel/drivers/hwmon/pmbus/tps53679.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 185 insertions(+), 43 deletions(-) diff --git a/kernel/drivers/hwmon/pmbus/tps53679.c b/kernel/drivers/hwmon/pmbus/tps53679.c index 2bc352c..db2bdf2 100644 --- a/kernel/drivers/hwmon/pmbus/tps53679.c +++ b/kernel/drivers/hwmon/pmbus/tps53679.c @@ -1,26 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware monitoring driver for Texas Instruments TPS53679 * * Copyright (c) 2017 Mellanox Technologies. All rights reserved. * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ +#include <linux/bits.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_device.h> #include "pmbus.h" + +enum chips { + tps53647, tps53667, tps53679, tps53681, tps53688 +}; + +#define TPS53647_PAGE_NUM 1 #define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */ #define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */ @@ -29,76 +28,219 @@ #define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ #define TPS53679_PAGE_NUM 2 -static int tps53679_identify(struct i2c_client *client, - struct pmbus_driver_info *info) +#define TPS53681_DEVICE_ID 0x81 + +#define TPS53681_PMBUS_REVISION 0x33 + +#define TPS53681_MFR_SPECIFIC_20 0xe4 /* Number of phases, per page */ + +static const struct i2c_device_id tps53679_id[]; + +static int tps53679_identify_mode(struct i2c_client *client, + struct pmbus_driver_info *info) { u8 vout_params; - int ret; + int i, ret; - /* Read the register with VOUT scaling value.*/ - ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); - if (ret < 0) - return ret; + for (i = 0; i < info->pages; i++) { + /* Read the register with VOUT scaling value.*/ + ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; - vout_params = ret & GENMASK(4, 0); + vout_params = ret & GENMASK(4, 0); - switch (vout_params) { - case TPS53679_PROT_VR13_10MV: - case TPS53679_PROT_VR12_5_10MV: - info->vrm_version = vr13; - break; - case TPS53679_PROT_VR13_5MV: - case TPS53679_PROT_VR12_5MV: - case TPS53679_PROT_IMVP8_5MV: - info->vrm_version = vr12; - break; - default: - return -EINVAL; + switch (vout_params) { + case TPS53679_PROT_VR13_10MV: + case TPS53679_PROT_VR12_5_10MV: + info->vrm_version[i] = vr13; + break; + case TPS53679_PROT_VR13_5MV: + case TPS53679_PROT_VR12_5MV: + case TPS53679_PROT_IMVP8_5MV: + info->vrm_version[i] = vr12; + break; + default: + return -EINVAL; + } } return 0; } +static int tps53679_identify_phases(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + int ret; + + /* On TPS53681, only channel A provides per-phase output current */ + ret = pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20); + if (ret < 0) + return ret; + info->phases[0] = (ret & 0x07) + 1; + + return 0; +} + +static int tps53679_identify_chip(struct i2c_client *client, + u8 revision, u16 id) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX]; + int ret; + + ret = pmbus_read_byte_data(client, 0, PMBUS_REVISION); + if (ret < 0) + return ret; + if (ret != revision) { + dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret); + return -ENODEV; + } + + ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); + if (ret < 0) + return ret; + if (ret != 1 || buf[0] != id) { + dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); + return -ENODEV; + } + return 0; +} + +/* + * Common identification function for chips with multi-phase support. + * Since those chips have special configuration registers, we want to have + * some level of reassurance that we are really talking with the chip + * being probed. Check PMBus revision and chip ID. + */ +static int tps53679_identify_multiphase(struct i2c_client *client, + struct pmbus_driver_info *info, + int pmbus_rev, int device_id) +{ + int ret; + + ret = tps53679_identify_chip(client, pmbus_rev, device_id); + if (ret < 0) + return ret; + + ret = tps53679_identify_mode(client, info); + if (ret < 0) + return ret; + + return tps53679_identify_phases(client, info); +} + +static int tps53679_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + return tps53679_identify_mode(client, info); +} + +static int tps53681_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + return tps53679_identify_multiphase(client, info, + TPS53681_PMBUS_REVISION, + TPS53681_DEVICE_ID); +} + +static int tps53681_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + /* + * For reading the total output current (READ_IOUT) for all phases, + * the chip datasheet is a bit vague. It says "PHASE must be set to + * FFh to access all phases simultaneously. PHASE may also be set to + * 80h readack (!) the total phase current". + * Experiments show that the command does _not_ report the total + * current for all phases if the phase is set to 0xff. Instead, it + * appears to report the current of one of the phases. Override phase + * parameter with 0x80 when reading the total output current on page 0. + */ + if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff) + return pmbus_read_word_data(client, page, 0x80, reg); + return -ENODATA; +} + static struct pmbus_driver_info tps53679_info = { - .pages = TPS53679_PAGE_NUM, .format[PSC_VOLTAGE_IN] = linear, .format[PSC_VOLTAGE_OUT] = vid, .format[PSC_TEMPERATURE] = linear, .format[PSC_CURRENT_OUT] = linear, .format[PSC_POWER] = linear, - .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | + PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT, - .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT, - .identify = tps53679_identify, + .pfunc[0] = PMBUS_HAVE_IOUT, + .pfunc[1] = PMBUS_HAVE_IOUT, + .pfunc[2] = PMBUS_HAVE_IOUT, + .pfunc[3] = PMBUS_HAVE_IOUT, + .pfunc[4] = PMBUS_HAVE_IOUT, + .pfunc[5] = PMBUS_HAVE_IOUT, }; -static int tps53679_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tps53679_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct pmbus_driver_info *info; + enum chips chip_id; - info = devm_kmemdup(&client->dev, &tps53679_info, sizeof(*info), - GFP_KERNEL); + if (dev->of_node) + chip_id = (enum chips)of_device_get_match_data(dev); + else + chip_id = i2c_match_id(tps53679_id, client)->driver_data; + + info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - return pmbus_do_probe(client, id, info); + switch (chip_id) { + case tps53647: + case tps53667: + info->pages = TPS53647_PAGE_NUM; + info->identify = tps53679_identify; + break; + case tps53679: + case tps53688: + info->pages = TPS53679_PAGE_NUM; + info->identify = tps53679_identify; + break; + case tps53681: + info->pages = TPS53679_PAGE_NUM; + info->phases[0] = 6; + info->identify = tps53681_identify; + info->read_word_data = tps53681_read_word_data; + break; + default: + return -ENODEV; + } + + return pmbus_do_probe(client, info); } static const struct i2c_device_id tps53679_id[] = { - {"tps53679", 0}, + {"tps53647", tps53647}, + {"tps53667", tps53667}, + {"tps53679", tps53679}, + {"tps53681", tps53681}, + {"tps53688", tps53688}, {} }; MODULE_DEVICE_TABLE(i2c, tps53679_id); -static const struct of_device_id tps53679_of_match[] = { - {.compatible = "ti,tps53679"}, +static const struct of_device_id __maybe_unused tps53679_of_match[] = { + {.compatible = "ti,tps53647", .data = (void *)tps53647}, + {.compatible = "ti,tps53667", .data = (void *)tps53667}, + {.compatible = "ti,tps53679", .data = (void *)tps53679}, + {.compatible = "ti,tps53681", .data = (void *)tps53681}, + {.compatible = "ti,tps53688", .data = (void *)tps53688}, {} }; MODULE_DEVICE_TABLE(of, tps53679_of_match); @@ -108,7 +250,7 @@ .name = "tps53679", .of_match_table = of_match_ptr(tps53679_of_match), }, - .probe = tps53679_probe, + .probe_new = tps53679_probe, .remove = pmbus_do_remove, .id_table = tps53679_id, }; -- Gitblit v1.6.2