brintos

brintos / linux-shallow public Read only

0
0
Text · 11.4 KiB · a235c1c Raw
425 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for Delta modules, Q54SJ108A2 series 1/4 Brick DC/DC4 * Regulated Power Module5 *6 * Copyright 2020 Delta LLC.7 */8 9#include <linux/debugfs.h>10#include <linux/i2c.h>11#include <linux/kstrtox.h>12#include <linux/module.h>13#include <linux/of.h>14#include "pmbus.h"15 16#define STORE_DEFAULT_ALL		0x1117#define ERASE_BLACKBOX_DATA		0xD118#define READ_HISTORY_EVENT_NUMBER	0xD219#define READ_HISTORY_EVENTS		0xE020#define SET_HISTORY_EVENT_OFFSET	0xE121#define PMBUS_FLASH_KEY_WRITE		0xEC22 23enum chips {24	q54sj108a225};26 27enum {28	Q54SJ108A2_DEBUGFS_OPERATION = 0,29	Q54SJ108A2_DEBUGFS_CLEARFAULT,30	Q54SJ108A2_DEBUGFS_WRITEPROTECT,31	Q54SJ108A2_DEBUGFS_STOREDEFAULT,32	Q54SJ108A2_DEBUGFS_VOOV_RESPONSE,33	Q54SJ108A2_DEBUGFS_IOOC_RESPONSE,34	Q54SJ108A2_DEBUGFS_PMBUS_VERSION,35	Q54SJ108A2_DEBUGFS_MFR_ID,36	Q54SJ108A2_DEBUGFS_MFR_MODEL,37	Q54SJ108A2_DEBUGFS_MFR_REVISION,38	Q54SJ108A2_DEBUGFS_MFR_LOCATION,39	Q54SJ108A2_DEBUGFS_BLACKBOX_ERASE,40	Q54SJ108A2_DEBUGFS_BLACKBOX_READ_OFFSET,41	Q54SJ108A2_DEBUGFS_BLACKBOX_SET_OFFSET,42	Q54SJ108A2_DEBUGFS_BLACKBOX_READ,43	Q54SJ108A2_DEBUGFS_FLASH_KEY,44	Q54SJ108A2_DEBUGFS_NUM_ENTRIES45};46 47struct q54sj108a2_data {48	enum chips chip;49	struct i2c_client *client;50 51	int debugfs_entries[Q54SJ108A2_DEBUGFS_NUM_ENTRIES];52};53 54#define to_psu(x, y) container_of((x), struct q54sj108a2_data, debugfs_entries[(y)])55 56static struct pmbus_driver_info q54sj108a2_info[] = {57	[q54sj108a2] = {58		.pages = 1,59 60		/* Source : Delta Q54SJ108A2 */61		.format[PSC_TEMPERATURE] = linear,62		.format[PSC_VOLTAGE_IN] = linear,63		.format[PSC_CURRENT_OUT] = linear,64 65		.func[0] = PMBUS_HAVE_VIN |66		PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |67		PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |68		PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |69		PMBUS_HAVE_STATUS_INPUT,70	},71};72 73static ssize_t q54sj108a2_debugfs_read(struct file *file, char __user *buf,74				       size_t count, loff_t *ppos)75{76	int rc;77	int *idxp = file->private_data;78	int idx = *idxp;79	struct q54sj108a2_data *psu = to_psu(idxp, idx);80	char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };81	char data_char[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };82	char *res;83 84	switch (idx) {85	case Q54SJ108A2_DEBUGFS_OPERATION:86		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_OPERATION);87		if (rc < 0)88			return rc;89 90		rc = snprintf(data, 3, "%02x", rc);91		break;92	case Q54SJ108A2_DEBUGFS_WRITEPROTECT:93		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_WRITE_PROTECT);94		if (rc < 0)95			return rc;96 97		rc = snprintf(data, 3, "%02x", rc);98		break;99	case Q54SJ108A2_DEBUGFS_VOOV_RESPONSE:100		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_VOUT_OV_FAULT_RESPONSE);101		if (rc < 0)102			return rc;103 104		rc = snprintf(data, 3, "%02x", rc);105		break;106	case Q54SJ108A2_DEBUGFS_IOOC_RESPONSE:107		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_IOUT_OC_FAULT_RESPONSE);108		if (rc < 0)109			return rc;110 111		rc = snprintf(data, 3, "%02x", rc);112		break;113	case Q54SJ108A2_DEBUGFS_PMBUS_VERSION:114		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_REVISION);115		if (rc < 0)116			return rc;117 118		rc = snprintf(data, 3, "%02x", rc);119		break;120	case Q54SJ108A2_DEBUGFS_MFR_ID:121		rc = i2c_smbus_read_block_data(psu->client, PMBUS_MFR_ID, data);122		if (rc < 0)123			return rc;124		break;125	case Q54SJ108A2_DEBUGFS_MFR_MODEL:126		rc = i2c_smbus_read_block_data(psu->client, PMBUS_MFR_MODEL, data);127		if (rc < 0)128			return rc;129		break;130	case Q54SJ108A2_DEBUGFS_MFR_REVISION:131		rc = i2c_smbus_read_block_data(psu->client, PMBUS_MFR_REVISION, data);132		if (rc < 0)133			return rc;134		break;135	case Q54SJ108A2_DEBUGFS_MFR_LOCATION:136		rc = i2c_smbus_read_block_data(psu->client, PMBUS_MFR_LOCATION, data);137		if (rc < 0)138			return rc;139		break;140	case Q54SJ108A2_DEBUGFS_BLACKBOX_READ_OFFSET:141		rc = i2c_smbus_read_byte_data(psu->client, READ_HISTORY_EVENT_NUMBER);142		if (rc < 0)143			return rc;144 145		rc = snprintf(data, 3, "%02x", rc);146		break;147	case Q54SJ108A2_DEBUGFS_BLACKBOX_READ:148		rc = i2c_smbus_read_block_data(psu->client, READ_HISTORY_EVENTS, data);149		if (rc < 0)150			return rc;151 152		res = bin2hex(data, data_char, 32);153		rc = res - data;154 155		break;156	case Q54SJ108A2_DEBUGFS_FLASH_KEY:157		rc = i2c_smbus_read_block_data(psu->client, PMBUS_FLASH_KEY_WRITE, data);158		if (rc < 0)159			return rc;160 161		res = bin2hex(data, data_char, 4);162		rc = res - data;163 164		break;165	default:166		return -EINVAL;167	}168 169	data[rc] = '\n';170	rc += 2;171 172	return simple_read_from_buffer(buf, count, ppos, data, rc);173}174 175static ssize_t q54sj108a2_debugfs_write(struct file *file, const char __user *buf,176					size_t count, loff_t *ppos)177{178	u8 flash_key[4];179	u8 dst_data;180	ssize_t rc;181	int *idxp = file->private_data;182	int idx = *idxp;183	struct q54sj108a2_data *psu = to_psu(idxp, idx);184 185	rc = i2c_smbus_write_byte_data(psu->client, PMBUS_WRITE_PROTECT, 0);186	if (rc)187		return rc;188 189	switch (idx) {190	case Q54SJ108A2_DEBUGFS_OPERATION:191		rc = kstrtou8_from_user(buf, count, 0, &dst_data);192		if (rc < 0)193			return rc;194 195		rc = i2c_smbus_write_byte_data(psu->client, PMBUS_OPERATION, dst_data);196		if (rc < 0)197			return rc;198 199		break;200	case Q54SJ108A2_DEBUGFS_CLEARFAULT:201		rc = i2c_smbus_write_byte(psu->client, PMBUS_CLEAR_FAULTS);202		if (rc < 0)203			return rc;204 205		break;206	case Q54SJ108A2_DEBUGFS_STOREDEFAULT:207		flash_key[0] = 0x7E;208		flash_key[1] = 0x15;209		flash_key[2] = 0xDC;210		flash_key[3] = 0x42;211		rc = i2c_smbus_write_block_data(psu->client, PMBUS_FLASH_KEY_WRITE, 4, flash_key);212		if (rc < 0)213			return rc;214 215		rc = i2c_smbus_write_byte(psu->client, STORE_DEFAULT_ALL);216		if (rc < 0)217			return rc;218 219		break;220	case Q54SJ108A2_DEBUGFS_VOOV_RESPONSE:221		rc = kstrtou8_from_user(buf, count, 0, &dst_data);222		if (rc < 0)223			return rc;224 225		rc = i2c_smbus_write_byte_data(psu->client, PMBUS_VOUT_OV_FAULT_RESPONSE, dst_data);226		if (rc < 0)227			return rc;228 229		break;230	case Q54SJ108A2_DEBUGFS_IOOC_RESPONSE:231		rc = kstrtou8_from_user(buf, count, 0, &dst_data);232		if (rc < 0)233			return rc;234 235		rc = i2c_smbus_write_byte_data(psu->client, PMBUS_IOUT_OC_FAULT_RESPONSE, dst_data);236		if (rc < 0)237			return rc;238 239		break;240	case Q54SJ108A2_DEBUGFS_BLACKBOX_ERASE:241		rc = i2c_smbus_write_byte(psu->client, ERASE_BLACKBOX_DATA);242		if (rc < 0)243			return rc;244 245		break;246	case Q54SJ108A2_DEBUGFS_BLACKBOX_SET_OFFSET:247		rc = kstrtou8_from_user(buf, count, 0, &dst_data);248		if (rc < 0)249			return rc;250 251		rc = i2c_smbus_write_byte_data(psu->client, SET_HISTORY_EVENT_OFFSET, dst_data);252		if (rc < 0)253			return rc;254 255		break;256	default:257		return -EINVAL;258	}259 260	return count;261}262 263static const struct file_operations q54sj108a2_fops = {264	.llseek = noop_llseek,265	.read = q54sj108a2_debugfs_read,266	.write = q54sj108a2_debugfs_write,267	.open = simple_open,268};269 270static const struct i2c_device_id q54sj108a2_id[] = {271	{ "q54sj108a2", q54sj108a2 },272	{ },273};274 275MODULE_DEVICE_TABLE(i2c, q54sj108a2_id);276 277static int q54sj108a2_probe(struct i2c_client *client)278{279	struct device *dev = &client->dev;280	u8 buf[I2C_SMBUS_BLOCK_MAX + 1];281	enum chips chip_id;282	int ret, i;283	struct dentry *debugfs;284	struct dentry *q54sj108a2_dir;285	struct q54sj108a2_data *psu;286 287	if (!i2c_check_functionality(client->adapter,288				     I2C_FUNC_SMBUS_BYTE_DATA |289				     I2C_FUNC_SMBUS_WORD_DATA |290				     I2C_FUNC_SMBUS_BLOCK_DATA))291		return -ENODEV;292 293	if (client->dev.of_node)294		chip_id = (enum chips)(unsigned long)of_device_get_match_data(dev);295	else296		chip_id = i2c_match_id(q54sj108a2_id, client)->driver_data;297 298	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);299	if (ret < 0) {300		dev_err(&client->dev, "Failed to read Manufacturer ID\n");301		return ret;302	}303	if (ret != 6 || strncmp(buf, "DELTA", 5)) {304		buf[ret] = '\0';305		dev_err(dev, "Unsupported Manufacturer ID '%s'\n", buf);306		return -ENODEV;307	}308 309	/*310	 * The chips support reading PMBUS_MFR_MODEL.311	 */312	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);313	if (ret < 0) {314		dev_err(dev, "Failed to read Manufacturer Model\n");315		return ret;316	}317	if (ret != 14 || strncmp(buf, "Q54SJ108A2", 10)) {318		buf[ret] = '\0';319		dev_err(dev, "Unsupported Manufacturer Model '%s'\n", buf);320		return -ENODEV;321	}322 323	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_REVISION, buf);324	if (ret < 0) {325		dev_err(dev, "Failed to read Manufacturer Revision\n");326		return ret;327	}328	if (ret != 4 || buf[0] != 'S') {329		buf[ret] = '\0';330		dev_err(dev, "Unsupported Manufacturer Revision '%s'\n", buf);331		return -ENODEV;332	}333 334	ret = pmbus_do_probe(client, &q54sj108a2_info[chip_id]);335	if (ret)336		return ret;337 338	psu = devm_kzalloc(&client->dev, sizeof(*psu), GFP_KERNEL);339	if (!psu)340		return 0;341 342	psu->client = client;343 344	debugfs = pmbus_get_debugfs_dir(client);345 346	q54sj108a2_dir = debugfs_create_dir(client->name, debugfs);347 348	for (i = 0; i < Q54SJ108A2_DEBUGFS_NUM_ENTRIES; ++i)349		psu->debugfs_entries[i] = i;350 351	debugfs_create_file("operation", 0644, q54sj108a2_dir,352			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_OPERATION],353			    &q54sj108a2_fops);354	debugfs_create_file("clear_fault", 0200, q54sj108a2_dir,355			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_CLEARFAULT],356			    &q54sj108a2_fops);357	debugfs_create_file("write_protect", 0444, q54sj108a2_dir,358			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_WRITEPROTECT],359			    &q54sj108a2_fops);360	debugfs_create_file("store_default", 0200, q54sj108a2_dir,361			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_STOREDEFAULT],362			    &q54sj108a2_fops);363	debugfs_create_file("vo_ov_response", 0644, q54sj108a2_dir,364			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_VOOV_RESPONSE],365			    &q54sj108a2_fops);366	debugfs_create_file("io_oc_response", 0644, q54sj108a2_dir,367			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_IOOC_RESPONSE],368			    &q54sj108a2_fops);369	debugfs_create_file("pmbus_revision", 0444, q54sj108a2_dir,370			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_PMBUS_VERSION],371			    &q54sj108a2_fops);372	debugfs_create_file("mfr_id", 0444, q54sj108a2_dir,373			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_MFR_ID],374			    &q54sj108a2_fops);375	debugfs_create_file("mfr_model", 0444, q54sj108a2_dir,376			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_MFR_MODEL],377			    &q54sj108a2_fops);378	debugfs_create_file("mfr_revision", 0444, q54sj108a2_dir,379			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_MFR_REVISION],380			    &q54sj108a2_fops);381	debugfs_create_file("mfr_location", 0444, q54sj108a2_dir,382			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_MFR_LOCATION],383			    &q54sj108a2_fops);384	debugfs_create_file("blackbox_erase", 0200, q54sj108a2_dir,385			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_BLACKBOX_ERASE],386			    &q54sj108a2_fops);387	debugfs_create_file("blackbox_read_offset", 0444, q54sj108a2_dir,388			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_BLACKBOX_READ_OFFSET],389			    &q54sj108a2_fops);390	debugfs_create_file("blackbox_set_offset", 0200, q54sj108a2_dir,391			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_BLACKBOX_SET_OFFSET],392			    &q54sj108a2_fops);393	debugfs_create_file("blackbox_read", 0444, q54sj108a2_dir,394			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_BLACKBOX_READ],395			    &q54sj108a2_fops);396	debugfs_create_file("flash_key", 0444, q54sj108a2_dir,397			    &psu->debugfs_entries[Q54SJ108A2_DEBUGFS_FLASH_KEY],398			    &q54sj108a2_fops);399 400	return 0;401}402 403static const struct of_device_id q54sj108a2_of_match[] = {404	{ .compatible = "delta,q54sj108a2", .data = (void *)q54sj108a2 },405	{ },406};407 408MODULE_DEVICE_TABLE(of, q54sj108a2_of_match);409 410static struct i2c_driver q54sj108a2_driver = {411	.driver = {412		.name = "q54sj108a2",413		.of_match_table = q54sj108a2_of_match,414	},415	.probe = q54sj108a2_probe,416	.id_table = q54sj108a2_id,417};418 419module_i2c_driver(q54sj108a2_driver);420 421MODULE_AUTHOR("Xiao.Ma <xiao.mx.ma@deltaww.com>");422MODULE_DESCRIPTION("PMBus driver for Delta Q54SJ108A2 series modules");423MODULE_LICENSE("GPL");424MODULE_IMPORT_NS(PMBUS);425