.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * intel_pmic.c - Intel PMIC operation region driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2014 Intel Corporation. All rights reserved. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public License version |
---|
8 | | - * 2 as published by the Free Software Foundation. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, |
---|
11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | | - * GNU General Public License for more details. |
---|
14 | 6 | */ |
---|
15 | 7 | |
---|
16 | 8 | #include <linux/export.h> |
---|
17 | 9 | #include <linux/acpi.h> |
---|
| 10 | +#include <linux/mfd/intel_soc_pmic.h> |
---|
18 | 11 | #include <linux/regmap.h> |
---|
19 | 12 | #include <acpi/acpi_lpat.h> |
---|
20 | 13 | #include "intel_pmic.h" |
---|
.. | .. |
---|
35 | 28 | struct intel_pmic_opregion_data *data; |
---|
36 | 29 | struct intel_pmic_regs_handler_ctx ctx; |
---|
37 | 30 | }; |
---|
| 31 | + |
---|
| 32 | +static struct intel_pmic_opregion *intel_pmic_opregion; |
---|
38 | 33 | |
---|
39 | 34 | static int pmic_get_reg_bit(int address, struct pmic_table *table, |
---|
40 | 35 | int count, int *reg, int *bit) |
---|
.. | .. |
---|
262 | 257 | struct regmap *regmap, |
---|
263 | 258 | struct intel_pmic_opregion_data *d) |
---|
264 | 259 | { |
---|
265 | | - acpi_status status; |
---|
| 260 | + acpi_status status = AE_OK; |
---|
266 | 261 | struct intel_pmic_opregion *opregion; |
---|
267 | 262 | int ret; |
---|
268 | 263 | |
---|
.. | .. |
---|
280 | 275 | opregion->regmap = regmap; |
---|
281 | 276 | opregion->lpat_table = acpi_lpat_get_conversion_table(handle); |
---|
282 | 277 | |
---|
283 | | - status = acpi_install_address_space_handler(handle, |
---|
| 278 | + if (d->power_table_count) |
---|
| 279 | + status = acpi_install_address_space_handler(handle, |
---|
284 | 280 | PMIC_POWER_OPREGION_ID, |
---|
285 | 281 | intel_pmic_power_handler, |
---|
286 | 282 | NULL, opregion); |
---|
.. | .. |
---|
289 | 285 | goto out_error; |
---|
290 | 286 | } |
---|
291 | 287 | |
---|
292 | | - status = acpi_install_address_space_handler(handle, |
---|
| 288 | + if (d->thermal_table_count) |
---|
| 289 | + status = acpi_install_address_space_handler(handle, |
---|
293 | 290 | PMIC_THERMAL_OPREGION_ID, |
---|
294 | 291 | intel_pmic_thermal_handler, |
---|
295 | 292 | NULL, opregion); |
---|
296 | 293 | if (ACPI_FAILURE(status)) { |
---|
297 | | - acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, |
---|
298 | | - intel_pmic_power_handler); |
---|
299 | 294 | ret = -ENODEV; |
---|
300 | 295 | goto out_remove_power_handler; |
---|
301 | 296 | } |
---|
.. | .. |
---|
309 | 304 | } |
---|
310 | 305 | |
---|
311 | 306 | opregion->data = d; |
---|
| 307 | + intel_pmic_opregion = opregion; |
---|
312 | 308 | return 0; |
---|
313 | 309 | |
---|
314 | 310 | out_remove_thermal_handler: |
---|
315 | | - acpi_remove_address_space_handler(handle, PMIC_THERMAL_OPREGION_ID, |
---|
316 | | - intel_pmic_thermal_handler); |
---|
| 311 | + if (d->thermal_table_count) |
---|
| 312 | + acpi_remove_address_space_handler(handle, |
---|
| 313 | + PMIC_THERMAL_OPREGION_ID, |
---|
| 314 | + intel_pmic_thermal_handler); |
---|
317 | 315 | |
---|
318 | 316 | out_remove_power_handler: |
---|
319 | | - acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, |
---|
320 | | - intel_pmic_power_handler); |
---|
| 317 | + if (d->power_table_count) |
---|
| 318 | + acpi_remove_address_space_handler(handle, |
---|
| 319 | + PMIC_POWER_OPREGION_ID, |
---|
| 320 | + intel_pmic_power_handler); |
---|
321 | 321 | |
---|
322 | 322 | out_error: |
---|
323 | 323 | acpi_lpat_free_conversion_table(opregion->lpat_table); |
---|
324 | 324 | return ret; |
---|
325 | 325 | } |
---|
326 | 326 | EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); |
---|
| 327 | + |
---|
| 328 | +/** |
---|
| 329 | + * intel_soc_pmic_exec_mipi_pmic_seq_element - Execute PMIC MIPI sequence |
---|
| 330 | + * @i2c_address: I2C client address for the PMIC |
---|
| 331 | + * @reg_address: PMIC register address |
---|
| 332 | + * @value: New value for the register bits to change |
---|
| 333 | + * @mask: Mask indicating which register bits to change |
---|
| 334 | + * |
---|
| 335 | + * DSI LCD panels describe an initialization sequence in the i915 VBT (Video |
---|
| 336 | + * BIOS Tables) using so called MIPI sequences. One possible element in these |
---|
| 337 | + * sequences is a PMIC specific element of 15 bytes. |
---|
| 338 | + * |
---|
| 339 | + * This function executes these PMIC specific elements sending the embedded |
---|
| 340 | + * commands to the PMIC. |
---|
| 341 | + * |
---|
| 342 | + * Return 0 on success, < 0 on failure. |
---|
| 343 | + */ |
---|
| 344 | +int intel_soc_pmic_exec_mipi_pmic_seq_element(u16 i2c_address, u32 reg_address, |
---|
| 345 | + u32 value, u32 mask) |
---|
| 346 | +{ |
---|
| 347 | + struct intel_pmic_opregion_data *d; |
---|
| 348 | + int ret; |
---|
| 349 | + |
---|
| 350 | + if (!intel_pmic_opregion) { |
---|
| 351 | + pr_warn("%s: No PMIC registered\n", __func__); |
---|
| 352 | + return -ENXIO; |
---|
| 353 | + } |
---|
| 354 | + |
---|
| 355 | + d = intel_pmic_opregion->data; |
---|
| 356 | + |
---|
| 357 | + mutex_lock(&intel_pmic_opregion->lock); |
---|
| 358 | + |
---|
| 359 | + if (d->exec_mipi_pmic_seq_element) { |
---|
| 360 | + ret = d->exec_mipi_pmic_seq_element(intel_pmic_opregion->regmap, |
---|
| 361 | + i2c_address, reg_address, |
---|
| 362 | + value, mask); |
---|
| 363 | + } else if (d->pmic_i2c_address) { |
---|
| 364 | + if (i2c_address == d->pmic_i2c_address) { |
---|
| 365 | + ret = regmap_update_bits(intel_pmic_opregion->regmap, |
---|
| 366 | + reg_address, mask, value); |
---|
| 367 | + } else { |
---|
| 368 | + pr_err("%s: Unexpected i2c-addr: 0x%02x (reg-addr 0x%x value 0x%x mask 0x%x)\n", |
---|
| 369 | + __func__, i2c_address, reg_address, value, mask); |
---|
| 370 | + ret = -ENXIO; |
---|
| 371 | + } |
---|
| 372 | + } else { |
---|
| 373 | + pr_warn("%s: Not implemented\n", __func__); |
---|
| 374 | + pr_warn("%s: i2c-addr: 0x%x reg-addr 0x%x value 0x%x mask 0x%x\n", |
---|
| 375 | + __func__, i2c_address, reg_address, value, mask); |
---|
| 376 | + ret = -EOPNOTSUPP; |
---|
| 377 | + } |
---|
| 378 | + |
---|
| 379 | + mutex_unlock(&intel_pmic_opregion->lock); |
---|
| 380 | + |
---|
| 381 | + return ret; |
---|
| 382 | +} |
---|
| 383 | +EXPORT_SYMBOL_GPL(intel_soc_pmic_exec_mipi_pmic_seq_element); |
---|