brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · 04e0d59 Raw
207 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for Delta DPS920AB PSU4 *5 * Copyright (C) 2021 Delta Networks, Inc.6 * Copyright (C) 2021 Sartura Ltd.7 */8 9#include <linux/debugfs.h>10#include <linux/i2c.h>11#include <linux/module.h>12#include <linux/of.h>13#include "pmbus.h"14 15struct dps920ab_data {16	char *mfr_model;17	char *mfr_id;18};19 20static int dps920ab_read_word_data(struct i2c_client *client, int page, int phase, int reg)21{22	/*23	 * This masks commands which are not supported.24	 * PSU advertises that all features are supported,25	 * in reality that unfortunately is not true.26	 * So enable only those that the datasheet confirms.27	 */28	switch (reg) {29	case PMBUS_FAN_COMMAND_1:30	case PMBUS_IOUT_OC_WARN_LIMIT:31	case PMBUS_STATUS_WORD:32	case PMBUS_READ_VIN:33	case PMBUS_READ_IIN:34	case PMBUS_READ_VOUT:35	case PMBUS_READ_IOUT:36	case PMBUS_READ_TEMPERATURE_1:37	case PMBUS_READ_TEMPERATURE_2:38	case PMBUS_READ_TEMPERATURE_3:39	case PMBUS_READ_FAN_SPEED_1:40	case PMBUS_READ_POUT:41	case PMBUS_READ_PIN:42	case PMBUS_MFR_VOUT_MIN:43	case PMBUS_MFR_VOUT_MAX:44	case PMBUS_MFR_IOUT_MAX:45	case PMBUS_MFR_POUT_MAX:46		return pmbus_read_word_data(client, page, phase, reg);47	default:48		return -ENXIO;49	}50}51 52static int dps920ab_write_word_data(struct i2c_client *client, int page, int reg,53				    u16 word)54{55	/*56	 * This masks commands which are not supported.57	 * PSU only has one R/W register and that is58	 * for the fan.59	 */60	switch (reg) {61	case PMBUS_FAN_COMMAND_1:62		return pmbus_write_word_data(client, page, reg, word);63	default:64		return -EACCES;65	}66}67 68static struct pmbus_driver_info dps920ab_info = {69	.pages = 1,70 71	.format[PSC_VOLTAGE_IN] = linear,72	.format[PSC_VOLTAGE_OUT] = linear,73	.format[PSC_CURRENT_IN] = linear,74	.format[PSC_CURRENT_OUT] = linear,75	.format[PSC_POWER] = linear,76	.format[PSC_FAN] = linear,77	.format[PSC_TEMPERATURE] = linear,78 79	.func[0] =80		PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |81		PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |82		PMBUS_HAVE_TEMP  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |83		PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 |84		PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |85		PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,86	.read_word_data = dps920ab_read_word_data,87	.write_word_data = dps920ab_write_word_data,88};89 90static int dps920ab_mfr_id_show(struct seq_file *s, void *data)91{92	struct dps920ab_data *priv = s->private;93 94	seq_printf(s, "%s\n", priv->mfr_id);95 96	return 0;97}98 99DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_id);100 101static int dps920ab_mfr_model_show(struct seq_file *s, void *data)102{103	struct dps920ab_data *priv = s->private;104 105	seq_printf(s, "%s\n", priv->mfr_model);106 107	return 0;108}109 110DEFINE_SHOW_ATTRIBUTE(dps920ab_mfr_model);111 112static void dps920ab_init_debugfs(struct dps920ab_data *data, struct i2c_client *client)113{114	struct dentry *debugfs_dir;115	struct dentry *root;116 117	root = pmbus_get_debugfs_dir(client);118	if (!root)119		return;120 121	debugfs_dir = debugfs_create_dir(client->name, root);122 123	debugfs_create_file("mfr_id",124			    0400,125			    debugfs_dir,126			    data,127			    &dps920ab_mfr_id_fops);128 129	debugfs_create_file("mfr_model",130			    0400,131			    debugfs_dir,132			    data,133			    &dps920ab_mfr_model_fops);134}135 136static int dps920ab_probe(struct i2c_client *client)137{138	u8 buf[I2C_SMBUS_BLOCK_MAX + 1];139	struct dps920ab_data *data;140	int ret;141 142	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);143	if (!data)144		return -ENOMEM;145 146	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);147	if (ret < 0) {148		dev_err(&client->dev, "Failed to read Manufacturer ID\n");149		return ret;150	}151 152	buf[ret] = '\0';153	if (ret != 5 || strncmp(buf, "DELTA", 5)) {154		buf[ret] = '\0';155		dev_err(&client->dev, "Unsupported Manufacturer ID '%s'\n", buf);156		return -ENODEV;157	}158	data->mfr_id = devm_kstrdup(&client->dev, buf, GFP_KERNEL);159	if (!data->mfr_id)160		return -ENOMEM;161 162	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);163	if (ret < 0) {164		dev_err(&client->dev, "Failed to read Manufacturer Model\n");165		return ret;166	}167 168	buf[ret] = '\0';169	if (ret != 11 || strncmp(buf, "DPS-920AB", 9)) {170		dev_err(&client->dev, "Unsupported Manufacturer Model '%s'\n", buf);171		return -ENODEV;172	}173	data->mfr_model = devm_kstrdup(&client->dev, buf, GFP_KERNEL);174	if (!data->mfr_model)175		return -ENOMEM;176 177	ret = pmbus_do_probe(client, &dps920ab_info);178	if (ret)179		return ret;180 181	dps920ab_init_debugfs(data, client);182 183	return 0;184}185 186static const struct of_device_id __maybe_unused dps920ab_of_match[] = {187	{ .compatible = "delta,dps920ab", },188	{}189};190 191MODULE_DEVICE_TABLE(of, dps920ab_of_match);192 193static struct i2c_driver dps920ab_driver = {194	.driver = {195		   .name = "dps920ab",196		   .of_match_table = of_match_ptr(dps920ab_of_match),197	},198	.probe = dps920ab_probe,199};200 201module_i2c_driver(dps920ab_driver);202 203MODULE_AUTHOR("Robert Marko <robert.marko@sartura.hr>");204MODULE_DESCRIPTION("PMBus driver for Delta DPS920AB PSU");205MODULE_LICENSE("GPL");206MODULE_IMPORT_NS(PMBUS);207