446 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * TI TPS68470 PMIC operation region driver4 *5 * Copyright (C) 2017 Intel Corporation. All rights reserved.6 *7 * Author: Rajmohan Mani <rajmohan.mani@intel.com>8 *9 * Based on drivers/acpi/pmic/intel_pmic* drivers10 */11 12#include <linux/acpi.h>13#include <linux/init.h>14#include <linux/mfd/tps68470.h>15#include <linux/platform_device.h>16#include <linux/regmap.h>17 18struct tps68470_pmic_table {19 u32 address; /* operation region address */20 u32 reg; /* corresponding register */21 u32 bitmask; /* bit mask for power, clock */22};23 24#define TI_PMIC_POWER_OPREGION_ID 0xB025#define TI_PMIC_VR_VAL_OPREGION_ID 0xB126#define TI_PMIC_CLOCK_OPREGION_ID 0xB227#define TI_PMIC_CLKFREQ_OPREGION_ID 0xB328 29struct tps68470_pmic_opregion {30 struct mutex lock;31 struct regmap *regmap;32};33 34#define S_IO_I2C_EN (BIT(0) | BIT(1))35 36static const struct tps68470_pmic_table power_table[] = {37 {38 .address = 0x00,39 .reg = TPS68470_REG_S_I2C_CTL,40 .bitmask = S_IO_I2C_EN,41 /* S_I2C_CTL */42 },43 {44 .address = 0x04,45 .reg = TPS68470_REG_VCMCTL,46 .bitmask = BIT(0),47 /* VCMCTL */48 },49 {50 .address = 0x08,51 .reg = TPS68470_REG_VAUX1CTL,52 .bitmask = BIT(0),53 /* VAUX1_CTL */54 },55 {56 .address = 0x0C,57 .reg = TPS68470_REG_VAUX2CTL,58 .bitmask = BIT(0),59 /* VAUX2CTL */60 },61 {62 .address = 0x10,63 .reg = TPS68470_REG_VACTL,64 .bitmask = BIT(0),65 /* VACTL */66 },67 {68 .address = 0x14,69 .reg = TPS68470_REG_VDCTL,70 .bitmask = BIT(0),71 /* VDCTL */72 },73};74 75/* Table to set voltage regulator value */76static const struct tps68470_pmic_table vr_val_table[] = {77 {78 .address = 0x00,79 .reg = TPS68470_REG_VSIOVAL,80 .bitmask = TPS68470_VSIOVAL_IOVOLT_MASK,81 /* TPS68470_REG_VSIOVAL */82 },83 {84 .address = 0x04,85 .reg = TPS68470_REG_VIOVAL,86 .bitmask = TPS68470_VIOVAL_IOVOLT_MASK,87 /* TPS68470_REG_VIOVAL */88 },89 {90 .address = 0x08,91 .reg = TPS68470_REG_VCMVAL,92 .bitmask = TPS68470_VCMVAL_VCVOLT_MASK,93 /* TPS68470_REG_VCMVAL */94 },95 {96 .address = 0x0C,97 .reg = TPS68470_REG_VAUX1VAL,98 .bitmask = TPS68470_VAUX1VAL_AUX1VOLT_MASK,99 /* TPS68470_REG_VAUX1VAL */100 },101 {102 .address = 0x10,103 .reg = TPS68470_REG_VAUX2VAL,104 .bitmask = TPS68470_VAUX2VAL_AUX2VOLT_MASK,105 /* TPS68470_REG_VAUX2VAL */106 },107 {108 .address = 0x14,109 .reg = TPS68470_REG_VAVAL,110 .bitmask = TPS68470_VAVAL_AVOLT_MASK,111 /* TPS68470_REG_VAVAL */112 },113 {114 .address = 0x18,115 .reg = TPS68470_REG_VDVAL,116 .bitmask = TPS68470_VDVAL_DVOLT_MASK,117 /* TPS68470_REG_VDVAL */118 },119};120 121/* Table to configure clock frequency */122static const struct tps68470_pmic_table clk_freq_table[] = {123 {124 .address = 0x00,125 .reg = TPS68470_REG_POSTDIV2,126 .bitmask = BIT(0) | BIT(1),127 /* TPS68470_REG_POSTDIV2 */128 },129 {130 .address = 0x04,131 .reg = TPS68470_REG_BOOSTDIV,132 .bitmask = 0x1F,133 /* TPS68470_REG_BOOSTDIV */134 },135 {136 .address = 0x08,137 .reg = TPS68470_REG_BUCKDIV,138 .bitmask = 0x0F,139 /* TPS68470_REG_BUCKDIV */140 },141 {142 .address = 0x0C,143 .reg = TPS68470_REG_PLLSWR,144 .bitmask = 0x13,145 /* TPS68470_REG_PLLSWR */146 },147 {148 .address = 0x10,149 .reg = TPS68470_REG_XTALDIV,150 .bitmask = 0xFF,151 /* TPS68470_REG_XTALDIV */152 },153 {154 .address = 0x14,155 .reg = TPS68470_REG_PLLDIV,156 .bitmask = 0xFF,157 /* TPS68470_REG_PLLDIV */158 },159 {160 .address = 0x18,161 .reg = TPS68470_REG_POSTDIV,162 .bitmask = 0x83,163 /* TPS68470_REG_POSTDIV */164 },165};166 167/* Table to configure and enable clocks */168static const struct tps68470_pmic_table clk_table[] = {169 {170 .address = 0x00,171 .reg = TPS68470_REG_PLLCTL,172 .bitmask = 0xF5,173 /* TPS68470_REG_PLLCTL */174 },175 {176 .address = 0x04,177 .reg = TPS68470_REG_PLLCTL2,178 .bitmask = BIT(0),179 /* TPS68470_REG_PLLCTL2 */180 },181 {182 .address = 0x08,183 .reg = TPS68470_REG_CLKCFG1,184 .bitmask = TPS68470_CLKCFG1_MODE_A_MASK |185 TPS68470_CLKCFG1_MODE_B_MASK,186 /* TPS68470_REG_CLKCFG1 */187 },188 {189 .address = 0x0C,190 .reg = TPS68470_REG_CLKCFG2,191 .bitmask = TPS68470_CLKCFG1_MODE_A_MASK |192 TPS68470_CLKCFG1_MODE_B_MASK,193 /* TPS68470_REG_CLKCFG2 */194 },195};196 197static int pmic_get_reg_bit(u64 address,198 const struct tps68470_pmic_table *table,199 const unsigned int table_size, int *reg,200 int *bitmask)201{202 u64 i;203 204 i = address / 4;205 if (i >= table_size)206 return -ENOENT;207 208 if (!reg || !bitmask)209 return -EINVAL;210 211 *reg = table[i].reg;212 *bitmask = table[i].bitmask;213 214 return 0;215}216 217static int tps68470_pmic_get_power(struct regmap *regmap, int reg,218 int bitmask, u64 *value)219{220 unsigned int data;221 222 if (regmap_read(regmap, reg, &data))223 return -EIO;224 225 *value = (data & bitmask) ? 1 : 0;226 return 0;227}228 229static int tps68470_pmic_get_vr_val(struct regmap *regmap, int reg,230 int bitmask, u64 *value)231{232 unsigned int data;233 234 if (regmap_read(regmap, reg, &data))235 return -EIO;236 237 *value = data & bitmask;238 return 0;239}240 241static int tps68470_pmic_get_clk(struct regmap *regmap, int reg,242 int bitmask, u64 *value)243{244 unsigned int data;245 246 if (regmap_read(regmap, reg, &data))247 return -EIO;248 249 *value = (data & bitmask) ? 1 : 0;250 return 0;251}252 253static int tps68470_pmic_get_clk_freq(struct regmap *regmap, int reg,254 int bitmask, u64 *value)255{256 unsigned int data;257 258 if (regmap_read(regmap, reg, &data))259 return -EIO;260 261 *value = data & bitmask;262 return 0;263}264 265static int ti_tps68470_regmap_update_bits(struct regmap *regmap, int reg,266 int bitmask, u64 value)267{268 return regmap_update_bits(regmap, reg, bitmask, value);269}270 271static acpi_status tps68470_pmic_common_handler(u32 function,272 acpi_physical_address address,273 u32 bits, u64 *value,274 void *region_context,275 int (*get)(struct regmap *,276 int, int, u64 *),277 int (*update)(struct regmap *,278 int, int, u64),279 const struct tps68470_pmic_table *tbl,280 unsigned int tbl_size)281{282 struct tps68470_pmic_opregion *opregion = region_context;283 struct regmap *regmap = opregion->regmap;284 int reg, ret, bitmask;285 286 if (bits != 32)287 return AE_BAD_PARAMETER;288 289 ret = pmic_get_reg_bit(address, tbl, tbl_size, ®, &bitmask);290 if (ret < 0)291 return AE_BAD_PARAMETER;292 293 if (function == ACPI_WRITE && *value > bitmask)294 return AE_BAD_PARAMETER;295 296 mutex_lock(&opregion->lock);297 298 ret = (function == ACPI_READ) ?299 get(regmap, reg, bitmask, value) :300 update(regmap, reg, bitmask, *value);301 302 mutex_unlock(&opregion->lock);303 304 return ret ? AE_ERROR : AE_OK;305}306 307static acpi_status tps68470_pmic_cfreq_handler(u32 function,308 acpi_physical_address address,309 u32 bits, u64 *value,310 void *handler_context,311 void *region_context)312{313 return tps68470_pmic_common_handler(function, address, bits, value,314 region_context,315 tps68470_pmic_get_clk_freq,316 ti_tps68470_regmap_update_bits,317 clk_freq_table,318 ARRAY_SIZE(clk_freq_table));319}320 321static acpi_status tps68470_pmic_clk_handler(u32 function,322 acpi_physical_address address, u32 bits,323 u64 *value, void *handler_context,324 void *region_context)325{326 return tps68470_pmic_common_handler(function, address, bits, value,327 region_context,328 tps68470_pmic_get_clk,329 ti_tps68470_regmap_update_bits,330 clk_table,331 ARRAY_SIZE(clk_table));332}333 334static acpi_status tps68470_pmic_vrval_handler(u32 function,335 acpi_physical_address address,336 u32 bits, u64 *value,337 void *handler_context,338 void *region_context)339{340 return tps68470_pmic_common_handler(function, address, bits, value,341 region_context,342 tps68470_pmic_get_vr_val,343 ti_tps68470_regmap_update_bits,344 vr_val_table,345 ARRAY_SIZE(vr_val_table));346}347 348static acpi_status tps68470_pmic_pwr_handler(u32 function,349 acpi_physical_address address,350 u32 bits, u64 *value,351 void *handler_context,352 void *region_context)353{354 if (bits != 32)355 return AE_BAD_PARAMETER;356 357 /* set/clear for bit 0, bits 0 and 1 together */358 if (function == ACPI_WRITE &&359 !(*value == 0 || *value == 1 || *value == 3)) {360 return AE_BAD_PARAMETER;361 }362 363 return tps68470_pmic_common_handler(function, address, bits, value,364 region_context,365 tps68470_pmic_get_power,366 ti_tps68470_regmap_update_bits,367 power_table,368 ARRAY_SIZE(power_table));369}370 371static int tps68470_pmic_opregion_probe(struct platform_device *pdev)372{373 struct regmap *tps68470_regmap = dev_get_drvdata(pdev->dev.parent);374 acpi_handle handle = ACPI_HANDLE(pdev->dev.parent);375 struct device *dev = &pdev->dev;376 struct tps68470_pmic_opregion *opregion;377 acpi_status status;378 379 if (!tps68470_regmap)380 return dev_err_probe(dev, -EINVAL, "regmap is missing\n");381 382 if (!handle) {383 dev_warn(dev, "acpi handle is NULL\n");384 return -ENODEV;385 }386 387 opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);388 if (!opregion)389 return -ENOMEM;390 391 mutex_init(&opregion->lock);392 opregion->regmap = tps68470_regmap;393 394 status = acpi_install_address_space_handler(handle,395 TI_PMIC_POWER_OPREGION_ID,396 tps68470_pmic_pwr_handler,397 NULL, opregion);398 if (ACPI_FAILURE(status))399 goto out_mutex_destroy;400 401 status = acpi_install_address_space_handler(handle,402 TI_PMIC_VR_VAL_OPREGION_ID,403 tps68470_pmic_vrval_handler,404 NULL, opregion);405 if (ACPI_FAILURE(status))406 goto out_remove_power_handler;407 408 status = acpi_install_address_space_handler(handle,409 TI_PMIC_CLOCK_OPREGION_ID,410 tps68470_pmic_clk_handler,411 NULL, opregion);412 if (ACPI_FAILURE(status))413 goto out_remove_vr_val_handler;414 415 status = acpi_install_address_space_handler(handle,416 TI_PMIC_CLKFREQ_OPREGION_ID,417 tps68470_pmic_cfreq_handler,418 NULL, opregion);419 if (ACPI_FAILURE(status))420 goto out_remove_clk_handler;421 422 return 0;423 424out_remove_clk_handler:425 acpi_remove_address_space_handler(handle, TI_PMIC_CLOCK_OPREGION_ID,426 tps68470_pmic_clk_handler);427out_remove_vr_val_handler:428 acpi_remove_address_space_handler(handle, TI_PMIC_VR_VAL_OPREGION_ID,429 tps68470_pmic_vrval_handler);430out_remove_power_handler:431 acpi_remove_address_space_handler(handle, TI_PMIC_POWER_OPREGION_ID,432 tps68470_pmic_pwr_handler);433out_mutex_destroy:434 mutex_destroy(&opregion->lock);435 return -ENODEV;436}437 438static struct platform_driver tps68470_pmic_opregion_driver = {439 .probe = tps68470_pmic_opregion_probe,440 .driver = {441 .name = "tps68470_pmic_opregion",442 },443};444 445builtin_platform_driver(tps68470_pmic_opregion_driver)446