162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * mpq7932.c - hwmon with optional regulator driver for mps mpq7932
462306a36Sopenharmony_ci * Copyright 2022 Monolithic Power Systems, Inc
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author: Saravanan Sekar <saravanan@linumiz.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bits.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/i2c.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/pmbus.h>
1762306a36Sopenharmony_ci#include "pmbus.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define MPQ7932_BUCK_UV_MIN		206250
2062306a36Sopenharmony_ci#define MPQ7932_UV_STEP			6250
2162306a36Sopenharmony_ci#define MPQ7932_N_VOLTAGES		256
2262306a36Sopenharmony_ci#define MPQ7932_VOUT_MAX		0xFF
2362306a36Sopenharmony_ci#define MPQ7932_NUM_PAGES		6
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define MPQ7932_TON_DELAY		0x60
2662306a36Sopenharmony_ci#define MPQ7932_VOUT_STARTUP_SLEW	0xA3
2762306a36Sopenharmony_ci#define MPQ7932_VOUT_SHUTDOWN_SLEW	0xA5
2862306a36Sopenharmony_ci#define MPQ7932_VOUT_SLEW_MASK		GENMASK(1, 0)
2962306a36Sopenharmony_ci#define MPQ7932_TON_DELAY_MASK		GENMASK(4, 0)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct mpq7932_data {
3262306a36Sopenharmony_ci	struct pmbus_driver_info info;
3362306a36Sopenharmony_ci	struct pmbus_platform_data pdata;
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
3762306a36Sopenharmony_cistatic struct regulator_desc mpq7932_regulators_desc[] = {
3862306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("buck", 0, MPQ7932_N_VOLTAGES,
3962306a36Sopenharmony_ci			     MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
4062306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("buck", 1, MPQ7932_N_VOLTAGES,
4162306a36Sopenharmony_ci			     MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
4262306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("buck", 2, MPQ7932_N_VOLTAGES,
4362306a36Sopenharmony_ci			     MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
4462306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("buck", 3, MPQ7932_N_VOLTAGES,
4562306a36Sopenharmony_ci			     MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
4662306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("buck", 4, MPQ7932_N_VOLTAGES,
4762306a36Sopenharmony_ci			     MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
4862306a36Sopenharmony_ci	PMBUS_REGULATOR_STEP("buck", 5, MPQ7932_N_VOLTAGES,
4962306a36Sopenharmony_ci			     MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci#endif
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int mpq7932_write_word_data(struct i2c_client *client, int page, int reg,
5462306a36Sopenharmony_ci				   u16 word)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	switch (reg) {
5762306a36Sopenharmony_ci	/*
5862306a36Sopenharmony_ci	 * chip supports only byte access for VOUT_COMMAND otherwise
5962306a36Sopenharmony_ci	 * access results -EREMOTEIO
6062306a36Sopenharmony_ci	 */
6162306a36Sopenharmony_ci	case PMBUS_VOUT_COMMAND:
6262306a36Sopenharmony_ci		return pmbus_write_byte_data(client, page, reg, word & 0xFF);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	default:
6562306a36Sopenharmony_ci		return -ENODATA;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic int mpq7932_read_word_data(struct i2c_client *client, int page,
7062306a36Sopenharmony_ci				  int phase, int reg)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	switch (reg) {
7362306a36Sopenharmony_ci	/*
7462306a36Sopenharmony_ci	 * chip supports neither (PMBUS_VOUT_MARGIN_HIGH, PMBUS_VOUT_MARGIN_LOW)
7562306a36Sopenharmony_ci	 * nor (PMBUS_MFR_VOUT_MIN, PMBUS_MFR_VOUT_MAX). As a result set voltage
7662306a36Sopenharmony_ci	 * fails due to error in pmbus_regulator_get_low_margin, so faked.
7762306a36Sopenharmony_ci	 */
7862306a36Sopenharmony_ci	case PMBUS_MFR_VOUT_MIN:
7962306a36Sopenharmony_ci		return 0;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	case PMBUS_MFR_VOUT_MAX:
8262306a36Sopenharmony_ci		return MPQ7932_VOUT_MAX;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/*
8562306a36Sopenharmony_ci	 * chip supports only byte access for VOUT_COMMAND otherwise
8662306a36Sopenharmony_ci	 * access results in -EREMOTEIO
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	case PMBUS_READ_VOUT:
8962306a36Sopenharmony_ci		return pmbus_read_byte_data(client, page, PMBUS_VOUT_COMMAND);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	default:
9262306a36Sopenharmony_ci		return -ENODATA;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int mpq7932_probe(struct i2c_client *client)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct mpq7932_data *data;
9962306a36Sopenharmony_ci	struct pmbus_driver_info *info;
10062306a36Sopenharmony_ci	struct device *dev = &client->dev;
10162306a36Sopenharmony_ci	int i;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct mpq7932_data), GFP_KERNEL);
10462306a36Sopenharmony_ci	if (!data)
10562306a36Sopenharmony_ci		return -ENOMEM;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	info = &data->info;
10862306a36Sopenharmony_ci	info->pages = MPQ7932_NUM_PAGES;
10962306a36Sopenharmony_ci	info->format[PSC_VOLTAGE_OUT] = direct;
11062306a36Sopenharmony_ci	info->m[PSC_VOLTAGE_OUT] = 160;
11162306a36Sopenharmony_ci	info->b[PSC_VOLTAGE_OUT] = -33;
11262306a36Sopenharmony_ci	for (i = 0; i < info->pages; i++) {
11362306a36Sopenharmony_ci		info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
11462306a36Sopenharmony_ci				| PMBUS_HAVE_STATUS_TEMP;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
11862306a36Sopenharmony_ci	info->num_regulators = ARRAY_SIZE(mpq7932_regulators_desc);
11962306a36Sopenharmony_ci	info->reg_desc = mpq7932_regulators_desc;
12062306a36Sopenharmony_ci#endif
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	info->read_word_data = mpq7932_read_word_data;
12362306a36Sopenharmony_ci	info->write_word_data = mpq7932_write_word_data;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	data->pdata.flags = PMBUS_NO_CAPABILITY;
12662306a36Sopenharmony_ci	dev->platform_data = &data->pdata;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return pmbus_do_probe(client, info);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic const struct of_device_id mpq7932_of_match[] = {
13262306a36Sopenharmony_ci	{ .compatible = "mps,mpq7932"},
13362306a36Sopenharmony_ci	{},
13462306a36Sopenharmony_ci};
13562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mpq7932_of_match);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic const struct i2c_device_id mpq7932_id[] = {
13862306a36Sopenharmony_ci	{ "mpq7932", },
13962306a36Sopenharmony_ci	{ },
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mpq7932_id);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic struct i2c_driver mpq7932_regulator_driver = {
14462306a36Sopenharmony_ci	.driver = {
14562306a36Sopenharmony_ci		.name = "mpq7932",
14662306a36Sopenharmony_ci		.of_match_table = mpq7932_of_match,
14762306a36Sopenharmony_ci	},
14862306a36Sopenharmony_ci	.probe = mpq7932_probe,
14962306a36Sopenharmony_ci	.id_table = mpq7932_id,
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_cimodule_i2c_driver(mpq7932_regulator_driver);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciMODULE_AUTHOR("Saravanan Sekar <saravanan@linumiz.com>");
15462306a36Sopenharmony_ciMODULE_DESCRIPTION("MPQ7932 PMIC regulator driver");
15562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
15662306a36Sopenharmony_ciMODULE_IMPORT_NS(PMBUS);
157