1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright 2023 IBM Corp. 4 */ 5 6 #include <linux/debugfs.h> 7 #include <linux/device.h> 8 #include <linux/fs.h> 9 #include <linux/i2c.h> 10 #include <linux/minmax.h> 11 #include <linux/module.h> 12 #include <linux/pmbus.h> 13 #include <linux/hwmon-sysfs.h> 14 #include "pmbus.h" 15 16 #define ACBEL_MFR_FW_REVISION 0xd9 17 18 static ssize_t acbel_fsg032_debugfs_read(struct file *file, char __user *buf, size_t count, 19 loff_t *ppos) 20 { 21 struct i2c_client *client = file->private_data; 22 u8 data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 }; 23 char out[8]; 24 int rc; 25 26 rc = i2c_smbus_read_block_data(client, ACBEL_MFR_FW_REVISION, data); 27 if (rc < 0) 28 return rc; 29 30 rc = snprintf(out, sizeof(out), "%*phN\n", min(rc, 3), data); 31 return simple_read_from_buffer(buf, count, ppos, out, rc); 32 } 33 34 static const struct file_operations acbel_debugfs_ops = { 35 .llseek = noop_llseek, 36 .read = acbel_fsg032_debugfs_read, 37 .write = NULL, 38 .open = simple_open, 39 }; 40 41 static void acbel_fsg032_init_debugfs(struct i2c_client *client) 42 { 43 struct dentry *debugfs = pmbus_get_debugfs_dir(client); 44 45 if (!debugfs) 46 return; 47 48 debugfs_create_file("fw_version", 0444, debugfs, client, &acbel_debugfs_ops); 49 } 50 51 static const struct i2c_device_id acbel_fsg032_id[] = { 52 { "acbel_fsg032" }, 53 {} 54 }; 55 56 static struct pmbus_driver_info acbel_fsg032_info = { 57 .pages = 1, 58 .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | 59 PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | 60 PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | 61 PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_VOUT | 62 PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_TEMP | 63 PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_FAN12, 64 }; 65 66 static int acbel_fsg032_probe(struct i2c_client *client) 67 { 68 u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; 69 struct device *dev = &client->dev; 70 int rc; 71 72 rc = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); 73 if (rc < 0) { 74 dev_err(dev, "Failed to read PMBUS_MFR_ID\n"); 75 return rc; 76 } 77 if (strncmp(buf, "ACBEL", 5)) { 78 buf[rc] = '\0'; 79 dev_err(dev, "Manufacturer '%s' not supported\n", buf); 80 return -ENODEV; 81 } 82 83 rc = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); 84 if (rc < 0) { 85 dev_err(dev, "Failed to read PMBUS_MFR_MODEL\n"); 86 return rc; 87 } 88 89 if (strncmp(buf, "FSG032", 6)) { 90 buf[rc] = '\0'; 91 dev_err(dev, "Model '%s' not supported\n", buf); 92 return -ENODEV; 93 } 94 95 rc = pmbus_do_probe(client, &acbel_fsg032_info); 96 if (rc) 97 return rc; 98 99 acbel_fsg032_init_debugfs(client); 100 return 0; 101 } 102 103 static const struct of_device_id acbel_fsg032_of_match[] = { 104 { .compatible = "acbel,fsg032" }, 105 {} 106 }; 107 MODULE_DEVICE_TABLE(of, acbel_fsg032_of_match); 108 109 static struct i2c_driver acbel_fsg032_driver = { 110 .driver = { 111 .name = "acbel-fsg032", 112 .of_match_table = acbel_fsg032_of_match, 113 }, 114 .probe = acbel_fsg032_probe, 115 .id_table = acbel_fsg032_id, 116 }; 117 118 module_i2c_driver(acbel_fsg032_driver); 119 120 MODULE_AUTHOR("Lakshmi Yadlapati"); 121 MODULE_DESCRIPTION("PMBus driver for AcBel Power System power supplies"); 122 MODULE_LICENSE("GPL"); 123 MODULE_IMPORT_NS(PMBUS); 124