1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * mpq7932.c - hwmon with optional regulator driver for mps mpq7932 |
4 | * Copyright 2022 Monolithic Power Systems, Inc |
5 | * |
6 | * Author: Saravanan Sekar <saravanan@linumiz.com> |
7 | */ |
8 | |
9 | #include <linux/bits.h> |
10 | #include <linux/err.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> |
15 | #include <linux/of.h> |
16 | #include <linux/pmbus.h> |
17 | #include "pmbus.h" |
18 | |
19 | #define MPQ7932_BUCK_UV_MIN 206250 |
20 | #define MPQ7932_UV_STEP 6250 |
21 | #define MPQ7932_N_VOLTAGES 256 |
22 | #define MPQ7932_VOUT_MAX 0xFF |
23 | #define MPQ7932_NUM_PAGES 6 |
24 | #define MPQ2286_NUM_PAGES 1 |
25 | |
26 | #define MPQ7932_TON_DELAY 0x60 |
27 | #define MPQ7932_VOUT_STARTUP_SLEW 0xA3 |
28 | #define MPQ7932_VOUT_SHUTDOWN_SLEW 0xA5 |
29 | #define MPQ7932_VOUT_SLEW_MASK GENMASK(1, 0) |
30 | #define MPQ7932_TON_DELAY_MASK GENMASK(4, 0) |
31 | |
32 | struct mpq7932_data { |
33 | struct pmbus_driver_info info; |
34 | struct pmbus_platform_data pdata; |
35 | }; |
36 | |
37 | #if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR) |
38 | static struct regulator_desc mpq7932_regulators_desc[] = { |
39 | PMBUS_REGULATOR_STEP("buck" , 0, MPQ7932_N_VOLTAGES, |
40 | MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), |
41 | PMBUS_REGULATOR_STEP("buck" , 1, MPQ7932_N_VOLTAGES, |
42 | MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), |
43 | PMBUS_REGULATOR_STEP("buck" , 2, MPQ7932_N_VOLTAGES, |
44 | MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), |
45 | PMBUS_REGULATOR_STEP("buck" , 3, MPQ7932_N_VOLTAGES, |
46 | MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), |
47 | PMBUS_REGULATOR_STEP("buck" , 4, MPQ7932_N_VOLTAGES, |
48 | MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), |
49 | PMBUS_REGULATOR_STEP("buck" , 5, MPQ7932_N_VOLTAGES, |
50 | MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), |
51 | }; |
52 | |
53 | static const struct regulator_desc mpq7932_regulators_desc_one[] = { |
54 | PMBUS_REGULATOR_STEP_ONE("buck" , MPQ7932_N_VOLTAGES, |
55 | MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), |
56 | }; |
57 | #endif |
58 | |
59 | static int mpq7932_write_word_data(struct i2c_client *client, int page, int reg, |
60 | u16 word) |
61 | { |
62 | switch (reg) { |
63 | /* |
64 | * chip supports only byte access for VOUT_COMMAND otherwise |
65 | * access results -EREMOTEIO |
66 | */ |
67 | case PMBUS_VOUT_COMMAND: |
68 | return pmbus_write_byte_data(client, page, reg, value: word & 0xFF); |
69 | |
70 | default: |
71 | return -ENODATA; |
72 | } |
73 | } |
74 | |
75 | static int mpq7932_read_word_data(struct i2c_client *client, int page, |
76 | int phase, int reg) |
77 | { |
78 | switch (reg) { |
79 | /* |
80 | * chip supports neither (PMBUS_VOUT_MARGIN_HIGH, PMBUS_VOUT_MARGIN_LOW) |
81 | * nor (PMBUS_MFR_VOUT_MIN, PMBUS_MFR_VOUT_MAX). As a result set voltage |
82 | * fails due to error in pmbus_regulator_get_low_margin, so faked. |
83 | */ |
84 | case PMBUS_MFR_VOUT_MIN: |
85 | return 0; |
86 | |
87 | case PMBUS_MFR_VOUT_MAX: |
88 | return MPQ7932_VOUT_MAX; |
89 | |
90 | /* |
91 | * chip supports only byte access for VOUT_COMMAND otherwise |
92 | * access results in -EREMOTEIO |
93 | */ |
94 | case PMBUS_READ_VOUT: |
95 | return pmbus_read_byte_data(client, page, reg: PMBUS_VOUT_COMMAND); |
96 | |
97 | default: |
98 | return -ENODATA; |
99 | } |
100 | } |
101 | |
102 | static int mpq7932_probe(struct i2c_client *client) |
103 | { |
104 | struct mpq7932_data *data; |
105 | struct pmbus_driver_info *info; |
106 | struct device *dev = &client->dev; |
107 | int i; |
108 | |
109 | data = devm_kzalloc(dev, size: sizeof(struct mpq7932_data), GFP_KERNEL); |
110 | if (!data) |
111 | return -ENOMEM; |
112 | |
113 | info = &data->info; |
114 | info->pages = (int)(unsigned long)device_get_match_data(dev: &client->dev); |
115 | info->format[PSC_VOLTAGE_OUT] = direct; |
116 | info->m[PSC_VOLTAGE_OUT] = 160; |
117 | info->b[PSC_VOLTAGE_OUT] = -33; |
118 | for (i = 0; i < info->pages; i++) { |
119 | info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
120 | | PMBUS_HAVE_STATUS_TEMP; |
121 | } |
122 | |
123 | #if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR) |
124 | info->num_regulators = info->pages; |
125 | if (info->num_regulators == 1) |
126 | info->reg_desc = mpq7932_regulators_desc_one; |
127 | else |
128 | info->reg_desc = mpq7932_regulators_desc; |
129 | #endif |
130 | |
131 | info->read_word_data = mpq7932_read_word_data; |
132 | info->write_word_data = mpq7932_write_word_data; |
133 | |
134 | data->pdata.flags = PMBUS_NO_CAPABILITY; |
135 | dev->platform_data = &data->pdata; |
136 | |
137 | return pmbus_do_probe(client, info); |
138 | } |
139 | |
140 | static const struct of_device_id mpq7932_of_match[] = { |
141 | { .compatible = "mps,mpq2286" , .data = (void *)MPQ2286_NUM_PAGES }, |
142 | { .compatible = "mps,mpq7932" , .data = (void *)MPQ7932_NUM_PAGES }, |
143 | {}, |
144 | }; |
145 | MODULE_DEVICE_TABLE(of, mpq7932_of_match); |
146 | |
147 | static const struct i2c_device_id mpq7932_id[] = { |
148 | { "mpq2286" , }, |
149 | { "mpq7932" , }, |
150 | { }, |
151 | }; |
152 | MODULE_DEVICE_TABLE(i2c, mpq7932_id); |
153 | |
154 | static struct i2c_driver mpq7932_regulator_driver = { |
155 | .driver = { |
156 | .name = "mpq7932" , |
157 | .of_match_table = mpq7932_of_match, |
158 | }, |
159 | .probe = mpq7932_probe, |
160 | .id_table = mpq7932_id, |
161 | }; |
162 | module_i2c_driver(mpq7932_regulator_driver); |
163 | |
164 | MODULE_AUTHOR("Saravanan Sekar <saravanan@linumiz.com>" ); |
165 | MODULE_DESCRIPTION("MPQ7932 PMIC regulator driver" ); |
166 | MODULE_LICENSE("GPL" ); |
167 | MODULE_IMPORT_NS(PMBUS); |
168 | |