424 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Hardware monitoring driver for ZL6100 and compatibles4 *5 * Copyright (c) 2011 Ericsson AB.6 * Copyright (c) 2012 Guenter Roeck7 */8 9#include <linux/bitops.h>10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/init.h>13#include <linux/err.h>14#include <linux/slab.h>15#include <linux/i2c.h>16#include <linux/ktime.h>17#include <linux/delay.h>18#include "pmbus.h"19 20enum chips { zl2004, zl2005, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105,21 zl8802, zl9101, zl9117, zls1003, zls4009 };22 23struct zl6100_data {24 int id;25 struct pmbus_driver_info info;26};27 28#define to_zl6100_data(x) container_of(x, struct zl6100_data, info)29 30#define ZL6100_MFR_CONFIG 0xd031#define ZL6100_DEVICE_ID 0xe432 33#define ZL6100_MFR_XTEMP_ENABLE BIT(7)34 35#define ZL8802_MFR_USER_GLOBAL_CONFIG 0xe936#define ZL8802_MFR_TMON_ENABLE BIT(12)37#define ZL8802_MFR_USER_CONFIG 0xd138#define ZL8802_MFR_XTEMP_ENABLE_2 BIT(1)39#define ZL8802_MFR_DDC_CONFIG 0xd340#define ZL8802_MFR_PHASES_MASK 0x000741 42#define MFR_VMON_OV_FAULT_LIMIT 0xf543#define MFR_VMON_UV_FAULT_LIMIT 0xf644#define MFR_READ_VMON 0xf745 46#define VMON_UV_WARNING BIT(5)47#define VMON_OV_WARNING BIT(4)48#define VMON_UV_FAULT BIT(1)49#define VMON_OV_FAULT BIT(0)50 51#define ZL6100_WAIT_TIME 1000 /* uS */52 53static ushort delay = ZL6100_WAIT_TIME;54module_param(delay, ushort, 0644);55MODULE_PARM_DESC(delay, "Delay between chip accesses in uS");56 57/* Convert linear sensor value to milli-units */58static long zl6100_l2d(s16 l)59{60 s16 exponent;61 s32 mantissa;62 long val;63 64 exponent = l >> 11;65 mantissa = ((s16)((l & 0x7ff) << 5)) >> 5;66 67 val = mantissa;68 69 /* scale result to milli-units */70 val = val * 1000L;71 72 if (exponent >= 0)73 val <<= exponent;74 else75 val >>= -exponent;76 77 return val;78}79 80#define MAX_MANTISSA (1023 * 1000)81#define MIN_MANTISSA (511 * 1000)82 83static u16 zl6100_d2l(long val)84{85 s16 exponent = 0, mantissa;86 bool negative = false;87 88 /* simple case */89 if (val == 0)90 return 0;91 92 if (val < 0) {93 negative = true;94 val = -val;95 }96 97 /* Reduce large mantissa until it fits into 10 bit */98 while (val >= MAX_MANTISSA && exponent < 15) {99 exponent++;100 val >>= 1;101 }102 /* Increase small mantissa to improve precision */103 while (val < MIN_MANTISSA && exponent > -15) {104 exponent--;105 val <<= 1;106 }107 108 /* Convert mantissa from milli-units to units */109 mantissa = DIV_ROUND_CLOSEST(val, 1000);110 111 /* Ensure that resulting number is within range */112 if (mantissa > 0x3ff)113 mantissa = 0x3ff;114 115 /* restore sign */116 if (negative)117 mantissa = -mantissa;118 119 /* Convert to 5 bit exponent, 11 bit mantissa */120 return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);121}122 123static int zl6100_read_word_data(struct i2c_client *client, int page,124 int phase, int reg)125{126 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);127 struct zl6100_data *data = to_zl6100_data(info);128 int ret, vreg;129 130 if (page >= info->pages)131 return -ENXIO;132 133 if (data->id == zl2005) {134 /*135 * Limit register detection is not reliable on ZL2005.136 * Make sure registers are not erroneously detected.137 */138 switch (reg) {139 case PMBUS_VOUT_OV_WARN_LIMIT:140 case PMBUS_VOUT_UV_WARN_LIMIT:141 case PMBUS_IOUT_OC_WARN_LIMIT:142 return -ENXIO;143 }144 }145 146 switch (reg) {147 case PMBUS_VIRT_READ_VMON:148 vreg = MFR_READ_VMON;149 break;150 case PMBUS_VIRT_VMON_OV_WARN_LIMIT:151 case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:152 vreg = MFR_VMON_OV_FAULT_LIMIT;153 break;154 case PMBUS_VIRT_VMON_UV_WARN_LIMIT:155 case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:156 vreg = MFR_VMON_UV_FAULT_LIMIT;157 break;158 default:159 if (reg >= PMBUS_VIRT_BASE)160 return -ENXIO;161 vreg = reg;162 break;163 }164 165 ret = pmbus_read_word_data(client, page, phase, vreg);166 if (ret < 0)167 return ret;168 169 switch (reg) {170 case PMBUS_VIRT_VMON_OV_WARN_LIMIT:171 ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 9, 10));172 break;173 case PMBUS_VIRT_VMON_UV_WARN_LIMIT:174 ret = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(ret) * 11, 10));175 break;176 }177 178 return ret;179}180 181static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg)182{183 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);184 int ret, status;185 186 if (page >= info->pages)187 return -ENXIO;188 189 switch (reg) {190 case PMBUS_VIRT_STATUS_VMON:191 ret = pmbus_read_byte_data(client, 0,192 PMBUS_STATUS_MFR_SPECIFIC);193 if (ret < 0)194 break;195 196 status = 0;197 if (ret & VMON_UV_WARNING)198 status |= PB_VOLTAGE_UV_WARNING;199 if (ret & VMON_OV_WARNING)200 status |= PB_VOLTAGE_OV_WARNING;201 if (ret & VMON_UV_FAULT)202 status |= PB_VOLTAGE_UV_FAULT;203 if (ret & VMON_OV_FAULT)204 status |= PB_VOLTAGE_OV_FAULT;205 ret = status;206 break;207 default:208 ret = pmbus_read_byte_data(client, page, reg);209 break;210 }211 212 return ret;213}214 215static int zl6100_write_word_data(struct i2c_client *client, int page, int reg,216 u16 word)217{218 const struct pmbus_driver_info *info = pmbus_get_driver_info(client);219 int vreg;220 221 if (page >= info->pages)222 return -ENXIO;223 224 switch (reg) {225 case PMBUS_VIRT_VMON_OV_WARN_LIMIT:226 word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 9));227 vreg = MFR_VMON_OV_FAULT_LIMIT;228 pmbus_clear_cache(client);229 break;230 case PMBUS_VIRT_VMON_OV_FAULT_LIMIT:231 vreg = MFR_VMON_OV_FAULT_LIMIT;232 pmbus_clear_cache(client);233 break;234 case PMBUS_VIRT_VMON_UV_WARN_LIMIT:235 word = zl6100_d2l(DIV_ROUND_CLOSEST(zl6100_l2d(word) * 10, 11));236 vreg = MFR_VMON_UV_FAULT_LIMIT;237 pmbus_clear_cache(client);238 break;239 case PMBUS_VIRT_VMON_UV_FAULT_LIMIT:240 vreg = MFR_VMON_UV_FAULT_LIMIT;241 pmbus_clear_cache(client);242 break;243 default:244 if (reg >= PMBUS_VIRT_BASE)245 return -ENXIO;246 vreg = reg;247 }248 249 return pmbus_write_word_data(client, page, vreg, word);250}251 252static const struct i2c_device_id zl6100_id[] = {253 {"bmr450", zl2005},254 {"bmr451", zl2005},255 {"bmr462", zl2008},256 {"bmr463", zl2008},257 {"bmr464", zl2008},258 {"bmr465", zls4009},259 {"bmr466", zls1003},260 {"bmr467", zls4009},261 {"bmr469", zl8802},262 {"zl2004", zl2004},263 {"zl2005", zl2005},264 {"zl2006", zl2006},265 {"zl2008", zl2008},266 {"zl2105", zl2105},267 {"zl2106", zl2106},268 {"zl6100", zl6100},269 {"zl6105", zl6105},270 {"zl8802", zl8802},271 {"zl9101", zl9101},272 {"zl9117", zl9117},273 {"zls1003", zls1003},274 {"zls4009", zls4009},275 { }276};277MODULE_DEVICE_TABLE(i2c, zl6100_id);278 279static int zl6100_probe(struct i2c_client *client)280{281 int ret, i;282 struct zl6100_data *data;283 struct pmbus_driver_info *info;284 u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];285 const struct i2c_device_id *mid;286 287 if (!i2c_check_functionality(client->adapter,288 I2C_FUNC_SMBUS_READ_WORD_DATA289 | I2C_FUNC_SMBUS_READ_BLOCK_DATA))290 return -ENODEV;291 292 ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID,293 device_id);294 if (ret < 0) {295 dev_err(&client->dev, "Failed to read device ID\n");296 return ret;297 }298 device_id[ret] = '\0';299 dev_info(&client->dev, "Device ID %s\n", device_id);300 301 mid = NULL;302 for (mid = zl6100_id; mid->name[0]; mid++) {303 if (!strncasecmp(mid->name, device_id, strlen(mid->name)))304 break;305 }306 if (!mid->name[0]) {307 dev_err(&client->dev, "Unsupported device\n");308 return -ENODEV;309 }310 if (strcmp(client->name, mid->name) != 0)311 dev_notice(&client->dev,312 "Device mismatch: Configured %s, detected %s\n",313 client->name, mid->name);314 315 data = devm_kzalloc(&client->dev, sizeof(struct zl6100_data),316 GFP_KERNEL);317 if (!data)318 return -ENOMEM;319 320 data->id = mid->driver_data;321 322 /*323 * According to information from the chip vendor, all currently324 * supported chips are known to require a wait time between I2C325 * accesses.326 */327 udelay(delay);328 329 info = &data->info;330 331 info->pages = 1;332 info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT333 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT334 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT335 | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;336 337 /*338 * ZL2004, ZL8802, ZL9101M, ZL9117M and ZLS4009 support monitoring339 * an extra voltage (VMON for ZL2004, ZL8802 and ZLS4009,340 * VDRV for ZL9101M and ZL9117M). Report it as vmon.341 */342 if (data->id == zl2004 || data->id == zl8802 || data->id == zl9101 ||343 data->id == zl9117 || data->id == zls4009)344 info->func[0] |= PMBUS_HAVE_VMON | PMBUS_HAVE_STATUS_VMON;345 346 /*347 * ZL8802 has two outputs that can be used either independently or in348 * a current sharing configuration. The driver uses the DDC_CONFIG349 * register to check if the module is running with independent or350 * shared outputs. If the module is in shared output mode, only one351 * output voltage will be reported.352 */353 if (data->id == zl8802) {354 info->pages = 2;355 info->func[0] |= PMBUS_HAVE_IIN;356 357 ret = i2c_smbus_read_word_data(client, ZL8802_MFR_DDC_CONFIG);358 if (ret < 0)359 return ret;360 361 udelay(delay);362 363 if (ret & ZL8802_MFR_PHASES_MASK)364 info->func[1] |= PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;365 else366 info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT367 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;368 369 for (i = 0; i < 2; i++) {370 ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);371 if (ret < 0)372 return ret;373 374 udelay(delay);375 376 ret = i2c_smbus_read_word_data(client, ZL8802_MFR_USER_CONFIG);377 if (ret < 0)378 return ret;379 380 if (ret & ZL8802_MFR_XTEMP_ENABLE_2)381 info->func[i] |= PMBUS_HAVE_TEMP2;382 383 udelay(delay);384 }385 ret = i2c_smbus_read_word_data(client, ZL8802_MFR_USER_GLOBAL_CONFIG);386 if (ret < 0)387 return ret;388 389 if (ret & ZL8802_MFR_TMON_ENABLE)390 info->func[0] |= PMBUS_HAVE_TEMP3;391 } else {392 ret = i2c_smbus_read_word_data(client, ZL6100_MFR_CONFIG);393 if (ret < 0)394 return ret;395 396 if (ret & ZL6100_MFR_XTEMP_ENABLE)397 info->func[0] |= PMBUS_HAVE_TEMP2;398 }399 400 udelay(delay);401 402 info->access_delay = delay;403 info->read_word_data = zl6100_read_word_data;404 info->read_byte_data = zl6100_read_byte_data;405 info->write_word_data = zl6100_write_word_data;406 407 return pmbus_do_probe(client, info);408}409 410static struct i2c_driver zl6100_driver = {411 .driver = {412 .name = "zl6100",413 },414 .probe = zl6100_probe,415 .id_table = zl6100_id,416};417 418module_i2c_driver(zl6100_driver);419 420MODULE_AUTHOR("Guenter Roeck");421MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");422MODULE_LICENSE("GPL");423MODULE_IMPORT_NS(PMBUS);424