Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Hardware monitoring driver for BEL PFE family power supplies.
0004  *
0005  * Copyright (c) 2019 Facebook Inc.
0006  */
0007 
0008 #include <linux/err.h>
0009 #include <linux/i2c.h>
0010 #include <linux/init.h>
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/pmbus.h>
0014 
0015 #include "pmbus.h"
0016 
0017 enum chips {pfe1100, pfe3000};
0018 
0019 /*
0020  * Disable status check for pfe3000 devices, because some devices report
0021  * communication error (invalid command) for VOUT_MODE command (0x20)
0022  * although correct VOUT_MODE (0x16) is returned: it leads to incorrect
0023  * exponent in linear mode.
0024  */
0025 static struct pmbus_platform_data pfe3000_plat_data = {
0026     .flags = PMBUS_SKIP_STATUS_CHECK,
0027 };
0028 
0029 static struct pmbus_driver_info pfe_driver_info[] = {
0030     [pfe1100] = {
0031         .pages = 1,
0032         .format[PSC_VOLTAGE_IN] = linear,
0033         .format[PSC_VOLTAGE_OUT] = linear,
0034         .format[PSC_CURRENT_IN] = linear,
0035         .format[PSC_CURRENT_OUT] = linear,
0036         .format[PSC_POWER] = linear,
0037         .format[PSC_TEMPERATURE] = linear,
0038         .format[PSC_FAN] = linear,
0039 
0040         .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
0041                PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
0042                PMBUS_HAVE_POUT |
0043                PMBUS_HAVE_VIN | PMBUS_HAVE_IIN |
0044                PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
0045                PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
0046                PMBUS_HAVE_STATUS_TEMP |
0047                PMBUS_HAVE_FAN12,
0048     },
0049 
0050     [pfe3000] = {
0051         .pages = 7,
0052         .format[PSC_VOLTAGE_IN] = linear,
0053         .format[PSC_VOLTAGE_OUT] = linear,
0054         .format[PSC_CURRENT_IN] = linear,
0055         .format[PSC_CURRENT_OUT] = linear,
0056         .format[PSC_POWER] = linear,
0057         .format[PSC_TEMPERATURE] = linear,
0058         .format[PSC_FAN] = linear,
0059 
0060         /* Page 0: V1. */
0061         .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
0062                PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
0063                PMBUS_HAVE_POUT | PMBUS_HAVE_FAN12 |
0064                PMBUS_HAVE_VIN | PMBUS_HAVE_IIN |
0065                PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
0066                PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
0067                PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP |
0068                PMBUS_HAVE_VCAP,
0069 
0070         /* Page 1: Vsb. */
0071         .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
0072                PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
0073                PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
0074                PMBUS_HAVE_POUT,
0075 
0076         /*
0077          * Page 2: V1 Ishare.
0078          * Page 3: Reserved.
0079          * Page 4: V1 Cathode.
0080          * Page 5: Vsb Cathode.
0081          * Page 6: V1 Sense.
0082          */
0083         .func[2] = PMBUS_HAVE_VOUT,
0084         .func[4] = PMBUS_HAVE_VOUT,
0085         .func[5] = PMBUS_HAVE_VOUT,
0086         .func[6] = PMBUS_HAVE_VOUT,
0087     },
0088 };
0089 
0090 static const struct i2c_device_id pfe_device_id[];
0091 
0092 static int pfe_pmbus_probe(struct i2c_client *client)
0093 {
0094     int model;
0095 
0096     model = (int)i2c_match_id(pfe_device_id, client)->driver_data;
0097 
0098     /*
0099      * PFE3000-12-069RA devices may not stay in page 0 during device
0100      * probe which leads to probe failure (read status word failed).
0101      * So let's set the device to page 0 at the beginning.
0102      */
0103     if (model == pfe3000) {
0104         client->dev.platform_data = &pfe3000_plat_data;
0105         i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
0106     }
0107 
0108     return pmbus_do_probe(client, &pfe_driver_info[model]);
0109 }
0110 
0111 static const struct i2c_device_id pfe_device_id[] = {
0112     {"pfe1100", pfe1100},
0113     {"pfe3000", pfe3000},
0114     {}
0115 };
0116 
0117 MODULE_DEVICE_TABLE(i2c, pfe_device_id);
0118 
0119 static struct i2c_driver pfe_pmbus_driver = {
0120     .driver = {
0121            .name = "bel-pfe",
0122     },
0123     .probe_new = pfe_pmbus_probe,
0124     .id_table = pfe_device_id,
0125 };
0126 
0127 module_i2c_driver(pfe_pmbus_driver);
0128 
0129 MODULE_AUTHOR("Tao Ren <rentao.bupt@gmail.com>");
0130 MODULE_DESCRIPTION("PMBus driver for BEL PFE Family Power Supplies");
0131 MODULE_LICENSE("GPL");
0132 MODULE_IMPORT_NS(PMBUS);