| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Hardware monitoring driver for PMBus devices |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2010, 2011 Ericsson AB. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program; if not, write to the Free Software |
|---|
| 18 | | - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 19 | 6 | */ |
|---|
| 20 | 7 | |
|---|
| 21 | 8 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 27 | 14 | #include <linux/i2c.h> |
|---|
| 28 | 15 | #include <linux/pmbus.h> |
|---|
| 29 | 16 | #include "pmbus.h" |
|---|
| 17 | + |
|---|
| 18 | +struct pmbus_device_info { |
|---|
| 19 | + int pages; |
|---|
| 20 | + u32 flags; |
|---|
| 21 | +}; |
|---|
| 22 | + |
|---|
| 23 | +static const struct i2c_device_id pmbus_id[]; |
|---|
| 30 | 24 | |
|---|
| 31 | 25 | /* |
|---|
| 32 | 26 | * Find sensor groups and status registers on each page. |
|---|
| .. | .. |
|---|
| 110 | 104 | int page; |
|---|
| 111 | 105 | |
|---|
| 112 | 106 | for (page = 1; page < PMBUS_PAGES; page++) { |
|---|
| 113 | | - if (pmbus_set_page(client, page) < 0) |
|---|
| 107 | + if (pmbus_set_page(client, page, 0xff) < 0) |
|---|
| 114 | 108 | break; |
|---|
| 115 | 109 | } |
|---|
| 116 | | - pmbus_set_page(client, 0); |
|---|
| 110 | + pmbus_set_page(client, 0, 0xff); |
|---|
| 117 | 111 | info->pages = page; |
|---|
| 118 | 112 | } else { |
|---|
| 119 | 113 | info->pages = 1; |
|---|
| .. | .. |
|---|
| 123 | 117 | } |
|---|
| 124 | 118 | |
|---|
| 125 | 119 | if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) { |
|---|
| 126 | | - int vout_mode; |
|---|
| 120 | + int vout_mode, i; |
|---|
| 127 | 121 | |
|---|
| 128 | 122 | vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); |
|---|
| 129 | 123 | if (vout_mode >= 0 && vout_mode != 0xff) { |
|---|
| .. | .. |
|---|
| 132 | 126 | break; |
|---|
| 133 | 127 | case 1: |
|---|
| 134 | 128 | info->format[PSC_VOLTAGE_OUT] = vid; |
|---|
| 135 | | - info->vrm_version = vr11; |
|---|
| 129 | + for (i = 0; i < info->pages; i++) |
|---|
| 130 | + info->vrm_version[i] = vr11; |
|---|
| 136 | 131 | break; |
|---|
| 137 | 132 | case 2: |
|---|
| 138 | 133 | info->format[PSC_VOLTAGE_OUT] = direct; |
|---|
| .. | .. |
|---|
| 166 | 161 | return ret; |
|---|
| 167 | 162 | } |
|---|
| 168 | 163 | |
|---|
| 169 | | -static int pmbus_probe(struct i2c_client *client, |
|---|
| 170 | | - const struct i2c_device_id *id) |
|---|
| 164 | +static int pmbus_probe(struct i2c_client *client) |
|---|
| 171 | 165 | { |
|---|
| 172 | 166 | struct pmbus_driver_info *info; |
|---|
| 173 | 167 | struct pmbus_platform_data *pdata = NULL; |
|---|
| 174 | 168 | struct device *dev = &client->dev; |
|---|
| 169 | + struct pmbus_device_info *device_info; |
|---|
| 175 | 170 | |
|---|
| 176 | 171 | info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); |
|---|
| 177 | 172 | if (!info) |
|---|
| 178 | 173 | return -ENOMEM; |
|---|
| 179 | 174 | |
|---|
| 180 | | - if (!strcmp(id->name, "dps460") || !strcmp(id->name, "dps800") || |
|---|
| 181 | | - !strcmp(id->name, "sgd009")) { |
|---|
| 175 | + device_info = (struct pmbus_device_info *)i2c_match_id(pmbus_id, client)->driver_data; |
|---|
| 176 | + if (device_info->flags & PMBUS_SKIP_STATUS_CHECK) { |
|---|
| 182 | 177 | pdata = devm_kzalloc(dev, sizeof(struct pmbus_platform_data), |
|---|
| 183 | 178 | GFP_KERNEL); |
|---|
| 184 | 179 | if (!pdata) |
|---|
| .. | .. |
|---|
| 187 | 182 | pdata->flags = PMBUS_SKIP_STATUS_CHECK; |
|---|
| 188 | 183 | } |
|---|
| 189 | 184 | |
|---|
| 190 | | - info->pages = id->driver_data; |
|---|
| 185 | + info->pages = device_info->pages; |
|---|
| 191 | 186 | info->identify = pmbus_identify; |
|---|
| 192 | 187 | dev->platform_data = pdata; |
|---|
| 193 | 188 | |
|---|
| 194 | | - return pmbus_do_probe(client, id, info); |
|---|
| 189 | + return pmbus_do_probe(client, info); |
|---|
| 195 | 190 | } |
|---|
| 191 | + |
|---|
| 192 | +static const struct pmbus_device_info pmbus_info_one = { |
|---|
| 193 | + .pages = 1, |
|---|
| 194 | + .flags = 0 |
|---|
| 195 | +}; |
|---|
| 196 | +static const struct pmbus_device_info pmbus_info_zero = { |
|---|
| 197 | + .pages = 0, |
|---|
| 198 | + .flags = 0 |
|---|
| 199 | +}; |
|---|
| 200 | +static const struct pmbus_device_info pmbus_info_one_skip = { |
|---|
| 201 | + .pages = 1, |
|---|
| 202 | + .flags = PMBUS_SKIP_STATUS_CHECK |
|---|
| 203 | +}; |
|---|
| 196 | 204 | |
|---|
| 197 | 205 | /* |
|---|
| 198 | 206 | * Use driver_data to set the number of pages supported by the chip. |
|---|
| 199 | 207 | */ |
|---|
| 200 | 208 | static const struct i2c_device_id pmbus_id[] = { |
|---|
| 201 | | - {"adp4000", 1}, |
|---|
| 202 | | - {"bmr453", 1}, |
|---|
| 203 | | - {"bmr454", 1}, |
|---|
| 204 | | - {"dps460", 1}, |
|---|
| 205 | | - {"dps800", 1}, |
|---|
| 206 | | - {"mdt040", 1}, |
|---|
| 207 | | - {"ncp4200", 1}, |
|---|
| 208 | | - {"ncp4208", 1}, |
|---|
| 209 | | - {"pdt003", 1}, |
|---|
| 210 | | - {"pdt006", 1}, |
|---|
| 211 | | - {"pdt012", 1}, |
|---|
| 212 | | - {"pmbus", 0}, |
|---|
| 213 | | - {"sgd009", 1}, |
|---|
| 214 | | - {"tps40400", 1}, |
|---|
| 215 | | - {"tps544b20", 1}, |
|---|
| 216 | | - {"tps544b25", 1}, |
|---|
| 217 | | - {"tps544c20", 1}, |
|---|
| 218 | | - {"tps544c25", 1}, |
|---|
| 219 | | - {"udt020", 1}, |
|---|
| 209 | + {"adp4000", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 210 | + {"bmr453", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 211 | + {"bmr454", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 212 | + {"dps460", (kernel_ulong_t)&pmbus_info_one_skip}, |
|---|
| 213 | + {"dps650ab", (kernel_ulong_t)&pmbus_info_one_skip}, |
|---|
| 214 | + {"dps800", (kernel_ulong_t)&pmbus_info_one_skip}, |
|---|
| 215 | + {"max20796", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 216 | + {"mdt040", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 217 | + {"ncp4200", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 218 | + {"ncp4208", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 219 | + {"pdt003", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 220 | + {"pdt006", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 221 | + {"pdt012", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 222 | + {"pmbus", (kernel_ulong_t)&pmbus_info_zero}, |
|---|
| 223 | + {"sgd009", (kernel_ulong_t)&pmbus_info_one_skip}, |
|---|
| 224 | + {"tps40400", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 225 | + {"tps544b20", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 226 | + {"tps544b25", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 227 | + {"tps544c20", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 228 | + {"tps544c25", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 229 | + {"udt020", (kernel_ulong_t)&pmbus_info_one}, |
|---|
| 220 | 230 | {} |
|---|
| 221 | 231 | }; |
|---|
| 222 | 232 | |
|---|
| .. | .. |
|---|
| 227 | 237 | .driver = { |
|---|
| 228 | 238 | .name = "pmbus", |
|---|
| 229 | 239 | }, |
|---|
| 230 | | - .probe = pmbus_probe, |
|---|
| 240 | + .probe_new = pmbus_probe, |
|---|
| 231 | 241 | .remove = pmbus_do_remove, |
|---|
| 232 | 242 | .id_table = pmbus_id, |
|---|
| 233 | 243 | }; |
|---|