162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * act8865-regulator.c - Voltage regulation for active-semi ACT88xx PMUs 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * http://www.active-semi.com/products/power-management-units/act88xx/ 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2013 Atmel Corporation 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/i2c.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1662306a36Sopenharmony_ci#include <linux/regulator/act8865.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/of_device.h> 1962306a36Sopenharmony_ci#include <linux/power_supply.h> 2062306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 2162306a36Sopenharmony_ci#include <linux/regmap.h> 2262306a36Sopenharmony_ci#include <dt-bindings/regulator/active-semi,8865-regulator.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * ACT8600 Global Register Map. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci#define ACT8600_SYS_MODE 0x00 2862306a36Sopenharmony_ci#define ACT8600_SYS_CTRL 0x01 2962306a36Sopenharmony_ci#define ACT8600_DCDC1_VSET 0x10 3062306a36Sopenharmony_ci#define ACT8600_DCDC1_CTRL 0x12 3162306a36Sopenharmony_ci#define ACT8600_DCDC2_VSET 0x20 3262306a36Sopenharmony_ci#define ACT8600_DCDC2_CTRL 0x22 3362306a36Sopenharmony_ci#define ACT8600_DCDC3_VSET 0x30 3462306a36Sopenharmony_ci#define ACT8600_DCDC3_CTRL 0x32 3562306a36Sopenharmony_ci#define ACT8600_SUDCDC4_VSET 0x40 3662306a36Sopenharmony_ci#define ACT8600_SUDCDC4_CTRL 0x41 3762306a36Sopenharmony_ci#define ACT8600_LDO5_VSET 0x50 3862306a36Sopenharmony_ci#define ACT8600_LDO5_CTRL 0x51 3962306a36Sopenharmony_ci#define ACT8600_LDO6_VSET 0x60 4062306a36Sopenharmony_ci#define ACT8600_LDO6_CTRL 0x61 4162306a36Sopenharmony_ci#define ACT8600_LDO7_VSET 0x70 4262306a36Sopenharmony_ci#define ACT8600_LDO7_CTRL 0x71 4362306a36Sopenharmony_ci#define ACT8600_LDO8_VSET 0x80 4462306a36Sopenharmony_ci#define ACT8600_LDO8_CTRL 0x81 4562306a36Sopenharmony_ci#define ACT8600_LDO910_CTRL 0x91 4662306a36Sopenharmony_ci#define ACT8600_APCH0 0xA1 4762306a36Sopenharmony_ci#define ACT8600_APCH1 0xA8 4862306a36Sopenharmony_ci#define ACT8600_APCH2 0xA9 4962306a36Sopenharmony_ci#define ACT8600_APCH_STAT 0xAA 5062306a36Sopenharmony_ci#define ACT8600_OTG0 0xB0 5162306a36Sopenharmony_ci#define ACT8600_OTG1 0xB2 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * ACT8846 Global Register Map. 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ci#define ACT8846_SYS0 0x00 5762306a36Sopenharmony_ci#define ACT8846_SYS1 0x01 5862306a36Sopenharmony_ci#define ACT8846_REG1_VSET 0x10 5962306a36Sopenharmony_ci#define ACT8846_REG1_CTRL 0x12 6062306a36Sopenharmony_ci#define ACT8846_REG2_VSET0 0x20 6162306a36Sopenharmony_ci#define ACT8846_REG2_VSET1 0x21 6262306a36Sopenharmony_ci#define ACT8846_REG2_CTRL 0x22 6362306a36Sopenharmony_ci#define ACT8846_REG3_VSET0 0x30 6462306a36Sopenharmony_ci#define ACT8846_REG3_VSET1 0x31 6562306a36Sopenharmony_ci#define ACT8846_REG3_CTRL 0x32 6662306a36Sopenharmony_ci#define ACT8846_REG4_VSET0 0x40 6762306a36Sopenharmony_ci#define ACT8846_REG4_VSET1 0x41 6862306a36Sopenharmony_ci#define ACT8846_REG4_CTRL 0x42 6962306a36Sopenharmony_ci#define ACT8846_REG5_VSET 0x50 7062306a36Sopenharmony_ci#define ACT8846_REG5_CTRL 0x51 7162306a36Sopenharmony_ci#define ACT8846_REG6_VSET 0x58 7262306a36Sopenharmony_ci#define ACT8846_REG6_CTRL 0x59 7362306a36Sopenharmony_ci#define ACT8846_REG7_VSET 0x60 7462306a36Sopenharmony_ci#define ACT8846_REG7_CTRL 0x61 7562306a36Sopenharmony_ci#define ACT8846_REG8_VSET 0x68 7662306a36Sopenharmony_ci#define ACT8846_REG8_CTRL 0x69 7762306a36Sopenharmony_ci#define ACT8846_REG9_VSET 0x70 7862306a36Sopenharmony_ci#define ACT8846_REG9_CTRL 0x71 7962306a36Sopenharmony_ci#define ACT8846_REG10_VSET 0x80 8062306a36Sopenharmony_ci#define ACT8846_REG10_CTRL 0x81 8162306a36Sopenharmony_ci#define ACT8846_REG11_VSET 0x90 8262306a36Sopenharmony_ci#define ACT8846_REG11_CTRL 0x91 8362306a36Sopenharmony_ci#define ACT8846_REG12_VSET 0xa0 8462306a36Sopenharmony_ci#define ACT8846_REG12_CTRL 0xa1 8562306a36Sopenharmony_ci#define ACT8846_REG13_CTRL 0xb1 8662306a36Sopenharmony_ci#define ACT8846_GLB_OFF_CTRL 0xc3 8762306a36Sopenharmony_ci#define ACT8846_OFF_SYSMASK 0x18 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * ACT8865 Global Register Map. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci#define ACT8865_SYS_MODE 0x00 9362306a36Sopenharmony_ci#define ACT8865_SYS_CTRL 0x01 9462306a36Sopenharmony_ci#define ACT8865_SYS_UNLK_REGS 0x0b 9562306a36Sopenharmony_ci#define ACT8865_DCDC1_VSET1 0x20 9662306a36Sopenharmony_ci#define ACT8865_DCDC1_VSET2 0x21 9762306a36Sopenharmony_ci#define ACT8865_DCDC1_CTRL 0x22 9862306a36Sopenharmony_ci#define ACT8865_DCDC1_SUS 0x24 9962306a36Sopenharmony_ci#define ACT8865_DCDC2_VSET1 0x30 10062306a36Sopenharmony_ci#define ACT8865_DCDC2_VSET2 0x31 10162306a36Sopenharmony_ci#define ACT8865_DCDC2_CTRL 0x32 10262306a36Sopenharmony_ci#define ACT8865_DCDC2_SUS 0x34 10362306a36Sopenharmony_ci#define ACT8865_DCDC3_VSET1 0x40 10462306a36Sopenharmony_ci#define ACT8865_DCDC3_VSET2 0x41 10562306a36Sopenharmony_ci#define ACT8865_DCDC3_CTRL 0x42 10662306a36Sopenharmony_ci#define ACT8865_DCDC3_SUS 0x44 10762306a36Sopenharmony_ci#define ACT8865_LDO1_VSET 0x50 10862306a36Sopenharmony_ci#define ACT8865_LDO1_CTRL 0x51 10962306a36Sopenharmony_ci#define ACT8865_LDO1_SUS 0x52 11062306a36Sopenharmony_ci#define ACT8865_LDO2_VSET 0x54 11162306a36Sopenharmony_ci#define ACT8865_LDO2_CTRL 0x55 11262306a36Sopenharmony_ci#define ACT8865_LDO2_SUS 0x56 11362306a36Sopenharmony_ci#define ACT8865_LDO3_VSET 0x60 11462306a36Sopenharmony_ci#define ACT8865_LDO3_CTRL 0x61 11562306a36Sopenharmony_ci#define ACT8865_LDO3_SUS 0x62 11662306a36Sopenharmony_ci#define ACT8865_LDO4_VSET 0x64 11762306a36Sopenharmony_ci#define ACT8865_LDO4_CTRL 0x65 11862306a36Sopenharmony_ci#define ACT8865_LDO4_SUS 0x66 11962306a36Sopenharmony_ci#define ACT8865_MSTROFF 0x20 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * Field Definitions. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci#define ACT8865_ENA 0x80 /* ON - [7] */ 12562306a36Sopenharmony_ci#define ACT8865_DIS 0x40 /* DIS - [6] */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define ACT8865_VSEL_MASK 0x3F /* VSET - [5:0] */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define ACT8600_LDO10_ENA 0x40 /* ON - [6] */ 13162306a36Sopenharmony_ci#define ACT8600_SUDCDC_VSEL_MASK 0xFF /* SUDCDC VSET - [7:0] */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define ACT8600_APCH_CHG_ACIN BIT(7) 13462306a36Sopenharmony_ci#define ACT8600_APCH_CHG_USB BIT(6) 13562306a36Sopenharmony_ci#define ACT8600_APCH_CSTATE0 BIT(5) 13662306a36Sopenharmony_ci#define ACT8600_APCH_CSTATE1 BIT(4) 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * ACT8865 voltage number 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci#define ACT8865_VOLTAGE_NUM 64 14262306a36Sopenharmony_ci#define ACT8600_SUDCDC_VOLTAGE_NUM 256 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistruct act8865 { 14562306a36Sopenharmony_ci struct regmap *regmap; 14662306a36Sopenharmony_ci int off_reg; 14762306a36Sopenharmony_ci int off_mask; 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic const struct regmap_range act8600_reg_ranges[] = { 15162306a36Sopenharmony_ci regmap_reg_range(0x00, 0x01), 15262306a36Sopenharmony_ci regmap_reg_range(0x10, 0x10), 15362306a36Sopenharmony_ci regmap_reg_range(0x12, 0x12), 15462306a36Sopenharmony_ci regmap_reg_range(0x20, 0x20), 15562306a36Sopenharmony_ci regmap_reg_range(0x22, 0x22), 15662306a36Sopenharmony_ci regmap_reg_range(0x30, 0x30), 15762306a36Sopenharmony_ci regmap_reg_range(0x32, 0x32), 15862306a36Sopenharmony_ci regmap_reg_range(0x40, 0x41), 15962306a36Sopenharmony_ci regmap_reg_range(0x50, 0x51), 16062306a36Sopenharmony_ci regmap_reg_range(0x60, 0x61), 16162306a36Sopenharmony_ci regmap_reg_range(0x70, 0x71), 16262306a36Sopenharmony_ci regmap_reg_range(0x80, 0x81), 16362306a36Sopenharmony_ci regmap_reg_range(0x91, 0x91), 16462306a36Sopenharmony_ci regmap_reg_range(0xA1, 0xA1), 16562306a36Sopenharmony_ci regmap_reg_range(0xA8, 0xAA), 16662306a36Sopenharmony_ci regmap_reg_range(0xB0, 0xB0), 16762306a36Sopenharmony_ci regmap_reg_range(0xB2, 0xB2), 16862306a36Sopenharmony_ci regmap_reg_range(0xC1, 0xC1), 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic const struct regmap_range act8600_reg_ro_ranges[] = { 17262306a36Sopenharmony_ci regmap_reg_range(0xAA, 0xAA), 17362306a36Sopenharmony_ci regmap_reg_range(0xC1, 0xC1), 17462306a36Sopenharmony_ci}; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic const struct regmap_range act8600_reg_volatile_ranges[] = { 17762306a36Sopenharmony_ci regmap_reg_range(0x00, 0x01), 17862306a36Sopenharmony_ci regmap_reg_range(0x12, 0x12), 17962306a36Sopenharmony_ci regmap_reg_range(0x22, 0x22), 18062306a36Sopenharmony_ci regmap_reg_range(0x32, 0x32), 18162306a36Sopenharmony_ci regmap_reg_range(0x41, 0x41), 18262306a36Sopenharmony_ci regmap_reg_range(0x51, 0x51), 18362306a36Sopenharmony_ci regmap_reg_range(0x61, 0x61), 18462306a36Sopenharmony_ci regmap_reg_range(0x71, 0x71), 18562306a36Sopenharmony_ci regmap_reg_range(0x81, 0x81), 18662306a36Sopenharmony_ci regmap_reg_range(0xA8, 0xA8), 18762306a36Sopenharmony_ci regmap_reg_range(0xAA, 0xAA), 18862306a36Sopenharmony_ci regmap_reg_range(0xB0, 0xB0), 18962306a36Sopenharmony_ci regmap_reg_range(0xC1, 0xC1), 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic const struct regmap_access_table act8600_write_ranges_table = { 19362306a36Sopenharmony_ci .yes_ranges = act8600_reg_ranges, 19462306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(act8600_reg_ranges), 19562306a36Sopenharmony_ci .no_ranges = act8600_reg_ro_ranges, 19662306a36Sopenharmony_ci .n_no_ranges = ARRAY_SIZE(act8600_reg_ro_ranges), 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic const struct regmap_access_table act8600_read_ranges_table = { 20062306a36Sopenharmony_ci .yes_ranges = act8600_reg_ranges, 20162306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(act8600_reg_ranges), 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic const struct regmap_access_table act8600_volatile_ranges_table = { 20562306a36Sopenharmony_ci .yes_ranges = act8600_reg_volatile_ranges, 20662306a36Sopenharmony_ci .n_yes_ranges = ARRAY_SIZE(act8600_reg_volatile_ranges), 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic const struct regmap_config act8600_regmap_config = { 21062306a36Sopenharmony_ci .reg_bits = 8, 21162306a36Sopenharmony_ci .val_bits = 8, 21262306a36Sopenharmony_ci .max_register = 0xFF, 21362306a36Sopenharmony_ci .wr_table = &act8600_write_ranges_table, 21462306a36Sopenharmony_ci .rd_table = &act8600_read_ranges_table, 21562306a36Sopenharmony_ci .volatile_table = &act8600_volatile_ranges_table, 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic const struct regmap_config act8865_regmap_config = { 21962306a36Sopenharmony_ci .reg_bits = 8, 22062306a36Sopenharmony_ci .val_bits = 8, 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic const struct linear_range act8865_voltage_ranges[] = { 22462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000), 22562306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000), 22662306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic const struct linear_range act8600_sudcdc_voltage_ranges[] = { 23062306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(3000000, 0, 63, 0), 23162306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(3000000, 64, 159, 100000), 23262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(12600000, 160, 191, 200000), 23362306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(19000000, 192, 247, 400000), 23462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0), 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int act8865_set_suspend_state(struct regulator_dev *rdev, bool enable) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct regmap *regmap = rdev->regmap; 24062306a36Sopenharmony_ci int id = rdev->desc->id, reg, val; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci switch (id) { 24362306a36Sopenharmony_ci case ACT8865_ID_DCDC1: 24462306a36Sopenharmony_ci reg = ACT8865_DCDC1_SUS; 24562306a36Sopenharmony_ci val = 0xa8; 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci case ACT8865_ID_DCDC2: 24862306a36Sopenharmony_ci reg = ACT8865_DCDC2_SUS; 24962306a36Sopenharmony_ci val = 0xa8; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci case ACT8865_ID_DCDC3: 25262306a36Sopenharmony_ci reg = ACT8865_DCDC3_SUS; 25362306a36Sopenharmony_ci val = 0xa8; 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci case ACT8865_ID_LDO1: 25662306a36Sopenharmony_ci reg = ACT8865_LDO1_SUS; 25762306a36Sopenharmony_ci val = 0xe8; 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci case ACT8865_ID_LDO2: 26062306a36Sopenharmony_ci reg = ACT8865_LDO2_SUS; 26162306a36Sopenharmony_ci val = 0xe8; 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci case ACT8865_ID_LDO3: 26462306a36Sopenharmony_ci reg = ACT8865_LDO3_SUS; 26562306a36Sopenharmony_ci val = 0xe8; 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci case ACT8865_ID_LDO4: 26862306a36Sopenharmony_ci reg = ACT8865_LDO4_SUS; 26962306a36Sopenharmony_ci val = 0xe8; 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci default: 27262306a36Sopenharmony_ci return -EINVAL; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (enable) 27662306a36Sopenharmony_ci val |= BIT(4); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * Ask the PMIC to enable/disable this output when entering hibernate 28062306a36Sopenharmony_ci * mode. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci return regmap_write(regmap, reg, val); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int act8865_set_suspend_enable(struct regulator_dev *rdev) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci return act8865_set_suspend_state(rdev, true); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int act8865_set_suspend_disable(struct regulator_dev *rdev) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci return act8865_set_suspend_state(rdev, false); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic unsigned int act8865_of_map_mode(unsigned int mode) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci switch (mode) { 29862306a36Sopenharmony_ci case ACT8865_REGULATOR_MODE_FIXED: 29962306a36Sopenharmony_ci return REGULATOR_MODE_FAST; 30062306a36Sopenharmony_ci case ACT8865_REGULATOR_MODE_NORMAL: 30162306a36Sopenharmony_ci return REGULATOR_MODE_NORMAL; 30262306a36Sopenharmony_ci case ACT8865_REGULATOR_MODE_LOWPOWER: 30362306a36Sopenharmony_ci return REGULATOR_MODE_STANDBY; 30462306a36Sopenharmony_ci default: 30562306a36Sopenharmony_ci return REGULATOR_MODE_INVALID; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int act8865_set_mode(struct regulator_dev *rdev, unsigned int mode) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct regmap *regmap = rdev->regmap; 31262306a36Sopenharmony_ci int id = rdev_get_id(rdev); 31362306a36Sopenharmony_ci int reg, val = 0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci switch (id) { 31662306a36Sopenharmony_ci case ACT8865_ID_DCDC1: 31762306a36Sopenharmony_ci reg = ACT8865_DCDC1_CTRL; 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci case ACT8865_ID_DCDC2: 32062306a36Sopenharmony_ci reg = ACT8865_DCDC2_CTRL; 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci case ACT8865_ID_DCDC3: 32362306a36Sopenharmony_ci reg = ACT8865_DCDC3_CTRL; 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case ACT8865_ID_LDO1: 32662306a36Sopenharmony_ci reg = ACT8865_LDO1_CTRL; 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci case ACT8865_ID_LDO2: 32962306a36Sopenharmony_ci reg = ACT8865_LDO2_CTRL; 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci case ACT8865_ID_LDO3: 33262306a36Sopenharmony_ci reg = ACT8865_LDO3_CTRL; 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci case ACT8865_ID_LDO4: 33562306a36Sopenharmony_ci reg = ACT8865_LDO4_CTRL; 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci default: 33862306a36Sopenharmony_ci return -EINVAL; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci switch (mode) { 34262306a36Sopenharmony_ci case REGULATOR_MODE_FAST: 34362306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 34462306a36Sopenharmony_ci if (id <= ACT8865_ID_DCDC3) 34562306a36Sopenharmony_ci val = BIT(5); 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 34862306a36Sopenharmony_ci if (id > ACT8865_ID_DCDC3) 34962306a36Sopenharmony_ci val = BIT(5); 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci default: 35262306a36Sopenharmony_ci return -EINVAL; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return regmap_update_bits(regmap, reg, BIT(5), val); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic unsigned int act8865_get_mode(struct regulator_dev *rdev) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct regmap *regmap = rdev->regmap; 36162306a36Sopenharmony_ci int id = rdev_get_id(rdev); 36262306a36Sopenharmony_ci int reg, ret, val = 0; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci switch (id) { 36562306a36Sopenharmony_ci case ACT8865_ID_DCDC1: 36662306a36Sopenharmony_ci reg = ACT8865_DCDC1_CTRL; 36762306a36Sopenharmony_ci break; 36862306a36Sopenharmony_ci case ACT8865_ID_DCDC2: 36962306a36Sopenharmony_ci reg = ACT8865_DCDC2_CTRL; 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci case ACT8865_ID_DCDC3: 37262306a36Sopenharmony_ci reg = ACT8865_DCDC3_CTRL; 37362306a36Sopenharmony_ci break; 37462306a36Sopenharmony_ci case ACT8865_ID_LDO1: 37562306a36Sopenharmony_ci reg = ACT8865_LDO1_CTRL; 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case ACT8865_ID_LDO2: 37862306a36Sopenharmony_ci reg = ACT8865_LDO2_CTRL; 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci case ACT8865_ID_LDO3: 38162306a36Sopenharmony_ci reg = ACT8865_LDO3_CTRL; 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case ACT8865_ID_LDO4: 38462306a36Sopenharmony_ci reg = ACT8865_LDO4_CTRL; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci default: 38762306a36Sopenharmony_ci return -EINVAL; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ret = regmap_read(regmap, reg, &val); 39162306a36Sopenharmony_ci if (ret) 39262306a36Sopenharmony_ci return ret; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (id <= ACT8865_ID_DCDC3 && (val & BIT(5))) 39562306a36Sopenharmony_ci return REGULATOR_MODE_FAST; 39662306a36Sopenharmony_ci else if (id > ACT8865_ID_DCDC3 && !(val & BIT(5))) 39762306a36Sopenharmony_ci return REGULATOR_MODE_NORMAL; 39862306a36Sopenharmony_ci else 39962306a36Sopenharmony_ci return REGULATOR_MODE_STANDBY; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic const struct regulator_ops act8865_ops = { 40362306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 40462306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 40562306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 40662306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 40762306a36Sopenharmony_ci .enable = regulator_enable_regmap, 40862306a36Sopenharmony_ci .disable = regulator_disable_regmap, 40962306a36Sopenharmony_ci .set_mode = act8865_set_mode, 41062306a36Sopenharmony_ci .get_mode = act8865_get_mode, 41162306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 41262306a36Sopenharmony_ci .set_suspend_enable = act8865_set_suspend_enable, 41362306a36Sopenharmony_ci .set_suspend_disable = act8865_set_suspend_disable, 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic const struct regulator_ops act8865_ldo_ops = { 41762306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 41862306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 41962306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 42062306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 42162306a36Sopenharmony_ci .enable = regulator_enable_regmap, 42262306a36Sopenharmony_ci .disable = regulator_disable_regmap, 42362306a36Sopenharmony_ci .set_mode = act8865_set_mode, 42462306a36Sopenharmony_ci .get_mode = act8865_get_mode, 42562306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 42662306a36Sopenharmony_ci .set_suspend_enable = act8865_set_suspend_enable, 42762306a36Sopenharmony_ci .set_suspend_disable = act8865_set_suspend_disable, 42862306a36Sopenharmony_ci .set_pull_down = regulator_set_pull_down_regmap, 42962306a36Sopenharmony_ci}; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic const struct regulator_ops act8865_fixed_ldo_ops = { 43262306a36Sopenharmony_ci .enable = regulator_enable_regmap, 43362306a36Sopenharmony_ci .disable = regulator_disable_regmap, 43462306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 43562306a36Sopenharmony_ci}; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci#define ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, _ops) \ 43862306a36Sopenharmony_ci [_family##_ID_##_id] = { \ 43962306a36Sopenharmony_ci .name = _name, \ 44062306a36Sopenharmony_ci .of_match = of_match_ptr(_name), \ 44162306a36Sopenharmony_ci .of_map_mode = act8865_of_map_mode, \ 44262306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 44362306a36Sopenharmony_ci .supply_name = _supply, \ 44462306a36Sopenharmony_ci .id = _family##_ID_##_id, \ 44562306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 44662306a36Sopenharmony_ci .ops = _ops, \ 44762306a36Sopenharmony_ci .n_voltages = ACT8865_VOLTAGE_NUM, \ 44862306a36Sopenharmony_ci .linear_ranges = act8865_voltage_ranges, \ 44962306a36Sopenharmony_ci .n_linear_ranges = ARRAY_SIZE(act8865_voltage_ranges), \ 45062306a36Sopenharmony_ci .vsel_reg = _family##_##_id##_##_vsel_reg, \ 45162306a36Sopenharmony_ci .vsel_mask = ACT8865_VSEL_MASK, \ 45262306a36Sopenharmony_ci .enable_reg = _family##_##_id##_CTRL, \ 45362306a36Sopenharmony_ci .enable_mask = ACT8865_ENA, \ 45462306a36Sopenharmony_ci .pull_down_reg = _family##_##_id##_CTRL, \ 45562306a36Sopenharmony_ci .pull_down_mask = ACT8865_DIS, \ 45662306a36Sopenharmony_ci .owner = THIS_MODULE, \ 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply) \ 46062306a36Sopenharmony_ci ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, &act8865_ops) 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci#define ACT88xx_LDO(_name, _family, _id, _vsel_reg, _supply) \ 46362306a36Sopenharmony_ci ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, &act8865_ldo_ops) 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic const struct regulator_desc act8600_regulators[] = { 46662306a36Sopenharmony_ci ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET, "vp1"), 46762306a36Sopenharmony_ci ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET, "vp2"), 46862306a36Sopenharmony_ci ACT88xx_REG("DCDC3", ACT8600, DCDC3, VSET, "vp3"), 46962306a36Sopenharmony_ci { 47062306a36Sopenharmony_ci .name = "SUDCDC_REG4", 47162306a36Sopenharmony_ci .of_match = of_match_ptr("SUDCDC_REG4"), 47262306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 47362306a36Sopenharmony_ci .id = ACT8600_ID_SUDCDC4, 47462306a36Sopenharmony_ci .ops = &act8865_ops, 47562306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 47662306a36Sopenharmony_ci .n_voltages = ACT8600_SUDCDC_VOLTAGE_NUM, 47762306a36Sopenharmony_ci .linear_ranges = act8600_sudcdc_voltage_ranges, 47862306a36Sopenharmony_ci .n_linear_ranges = ARRAY_SIZE(act8600_sudcdc_voltage_ranges), 47962306a36Sopenharmony_ci .vsel_reg = ACT8600_SUDCDC4_VSET, 48062306a36Sopenharmony_ci .vsel_mask = ACT8600_SUDCDC_VSEL_MASK, 48162306a36Sopenharmony_ci .enable_reg = ACT8600_SUDCDC4_CTRL, 48262306a36Sopenharmony_ci .enable_mask = ACT8865_ENA, 48362306a36Sopenharmony_ci .owner = THIS_MODULE, 48462306a36Sopenharmony_ci }, 48562306a36Sopenharmony_ci ACT88xx_REG("LDO5", ACT8600, LDO5, VSET, "inl"), 48662306a36Sopenharmony_ci ACT88xx_REG("LDO6", ACT8600, LDO6, VSET, "inl"), 48762306a36Sopenharmony_ci ACT88xx_REG("LDO7", ACT8600, LDO7, VSET, "inl"), 48862306a36Sopenharmony_ci ACT88xx_REG("LDO8", ACT8600, LDO8, VSET, "inl"), 48962306a36Sopenharmony_ci { 49062306a36Sopenharmony_ci .name = "LDO_REG9", 49162306a36Sopenharmony_ci .of_match = of_match_ptr("LDO_REG9"), 49262306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 49362306a36Sopenharmony_ci .id = ACT8600_ID_LDO9, 49462306a36Sopenharmony_ci .ops = &act8865_fixed_ldo_ops, 49562306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 49662306a36Sopenharmony_ci .n_voltages = 1, 49762306a36Sopenharmony_ci .fixed_uV = 3300000, 49862306a36Sopenharmony_ci .enable_reg = ACT8600_LDO910_CTRL, 49962306a36Sopenharmony_ci .enable_mask = ACT8865_ENA, 50062306a36Sopenharmony_ci .owner = THIS_MODULE, 50162306a36Sopenharmony_ci }, 50262306a36Sopenharmony_ci { 50362306a36Sopenharmony_ci .name = "LDO_REG10", 50462306a36Sopenharmony_ci .of_match = of_match_ptr("LDO_REG10"), 50562306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 50662306a36Sopenharmony_ci .id = ACT8600_ID_LDO10, 50762306a36Sopenharmony_ci .ops = &act8865_fixed_ldo_ops, 50862306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 50962306a36Sopenharmony_ci .n_voltages = 1, 51062306a36Sopenharmony_ci .fixed_uV = 1200000, 51162306a36Sopenharmony_ci .enable_reg = ACT8600_LDO910_CTRL, 51262306a36Sopenharmony_ci .enable_mask = ACT8600_LDO10_ENA, 51362306a36Sopenharmony_ci .owner = THIS_MODULE, 51462306a36Sopenharmony_ci }, 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic const struct regulator_desc act8846_regulators[] = { 51862306a36Sopenharmony_ci ACT88xx_REG("REG1", ACT8846, REG1, VSET, "vp1"), 51962306a36Sopenharmony_ci ACT88xx_REG("REG2", ACT8846, REG2, VSET0, "vp2"), 52062306a36Sopenharmony_ci ACT88xx_REG("REG3", ACT8846, REG3, VSET0, "vp3"), 52162306a36Sopenharmony_ci ACT88xx_REG("REG4", ACT8846, REG4, VSET0, "vp4"), 52262306a36Sopenharmony_ci ACT88xx_REG("REG5", ACT8846, REG5, VSET, "inl1"), 52362306a36Sopenharmony_ci ACT88xx_REG("REG6", ACT8846, REG6, VSET, "inl1"), 52462306a36Sopenharmony_ci ACT88xx_REG("REG7", ACT8846, REG7, VSET, "inl1"), 52562306a36Sopenharmony_ci ACT88xx_REG("REG8", ACT8846, REG8, VSET, "inl2"), 52662306a36Sopenharmony_ci ACT88xx_REG("REG9", ACT8846, REG9, VSET, "inl2"), 52762306a36Sopenharmony_ci ACT88xx_REG("REG10", ACT8846, REG10, VSET, "inl3"), 52862306a36Sopenharmony_ci ACT88xx_REG("REG11", ACT8846, REG11, VSET, "inl3"), 52962306a36Sopenharmony_ci ACT88xx_REG("REG12", ACT8846, REG12, VSET, "inl3"), 53062306a36Sopenharmony_ci}; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic const struct regulator_desc act8865_regulators[] = { 53362306a36Sopenharmony_ci ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1, "vp1"), 53462306a36Sopenharmony_ci ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1, "vp2"), 53562306a36Sopenharmony_ci ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1, "vp3"), 53662306a36Sopenharmony_ci ACT88xx_LDO("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), 53762306a36Sopenharmony_ci ACT88xx_LDO("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), 53862306a36Sopenharmony_ci ACT88xx_LDO("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), 53962306a36Sopenharmony_ci ACT88xx_LDO("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), 54062306a36Sopenharmony_ci}; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic const struct regulator_desc act8865_alt_regulators[] = { 54362306a36Sopenharmony_ci ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET2, "vp1"), 54462306a36Sopenharmony_ci ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET2, "vp2"), 54562306a36Sopenharmony_ci ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET2, "vp3"), 54662306a36Sopenharmony_ci ACT88xx_LDO("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), 54762306a36Sopenharmony_ci ACT88xx_LDO("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), 54862306a36Sopenharmony_ci ACT88xx_LDO("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), 54962306a36Sopenharmony_ci ACT88xx_LDO("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), 55062306a36Sopenharmony_ci}; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci#ifdef CONFIG_OF 55362306a36Sopenharmony_cistatic const struct of_device_id act8865_dt_ids[] = { 55462306a36Sopenharmony_ci { .compatible = "active-semi,act8600", .data = (void *)ACT8600 }, 55562306a36Sopenharmony_ci { .compatible = "active-semi,act8846", .data = (void *)ACT8846 }, 55662306a36Sopenharmony_ci { .compatible = "active-semi,act8865", .data = (void *)ACT8865 }, 55762306a36Sopenharmony_ci { } 55862306a36Sopenharmony_ci}; 55962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, act8865_dt_ids); 56062306a36Sopenharmony_ci#endif 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic struct act8865_regulator_data *act8865_get_regulator_data( 56362306a36Sopenharmony_ci int id, struct act8865_platform_data *pdata) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci int i; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci for (i = 0; i < pdata->num_regulators; i++) { 56862306a36Sopenharmony_ci if (pdata->regulators[i].id == id) 56962306a36Sopenharmony_ci return &pdata->regulators[i]; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return NULL; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic struct i2c_client *act8865_i2c_client; 57662306a36Sopenharmony_cistatic void act8865_power_off(void) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct act8865 *act8865; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci act8865 = i2c_get_clientdata(act8865_i2c_client); 58162306a36Sopenharmony_ci regmap_write(act8865->regmap, act8865->off_reg, act8865->off_mask); 58262306a36Sopenharmony_ci while (1); 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int act8600_charger_get_status(struct regmap *map) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci unsigned int val; 58862306a36Sopenharmony_ci int ret; 58962306a36Sopenharmony_ci u8 state0, state1; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci ret = regmap_read(map, ACT8600_APCH_STAT, &val); 59262306a36Sopenharmony_ci if (ret < 0) 59362306a36Sopenharmony_ci return ret; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci state0 = val & ACT8600_APCH_CSTATE0; 59662306a36Sopenharmony_ci state1 = val & ACT8600_APCH_CSTATE1; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (state0 && !state1) 59962306a36Sopenharmony_ci return POWER_SUPPLY_STATUS_CHARGING; 60062306a36Sopenharmony_ci if (!state0 && state1) 60162306a36Sopenharmony_ci return POWER_SUPPLY_STATUS_NOT_CHARGING; 60262306a36Sopenharmony_ci if (!state0 && !state1) 60362306a36Sopenharmony_ci return POWER_SUPPLY_STATUS_DISCHARGING; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci return POWER_SUPPLY_STATUS_UNKNOWN; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic int act8600_charger_get_property(struct power_supply *psy, 60962306a36Sopenharmony_ci enum power_supply_property psp, union power_supply_propval *val) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct regmap *map = power_supply_get_drvdata(psy); 61262306a36Sopenharmony_ci int ret; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci switch (psp) { 61562306a36Sopenharmony_ci case POWER_SUPPLY_PROP_STATUS: 61662306a36Sopenharmony_ci ret = act8600_charger_get_status(map); 61762306a36Sopenharmony_ci if (ret < 0) 61862306a36Sopenharmony_ci return ret; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci val->intval = ret; 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci default: 62362306a36Sopenharmony_ci return -EINVAL; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci return 0; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic enum power_supply_property act8600_charger_properties[] = { 63062306a36Sopenharmony_ci POWER_SUPPLY_PROP_STATUS, 63162306a36Sopenharmony_ci}; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic const struct power_supply_desc act8600_charger_desc = { 63462306a36Sopenharmony_ci .name = "act8600-charger", 63562306a36Sopenharmony_ci .type = POWER_SUPPLY_TYPE_BATTERY, 63662306a36Sopenharmony_ci .properties = act8600_charger_properties, 63762306a36Sopenharmony_ci .num_properties = ARRAY_SIZE(act8600_charger_properties), 63862306a36Sopenharmony_ci .get_property = act8600_charger_get_property, 63962306a36Sopenharmony_ci}; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int act8600_charger_probe(struct device *dev, struct regmap *regmap) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct power_supply *charger; 64462306a36Sopenharmony_ci struct power_supply_config cfg = { 64562306a36Sopenharmony_ci .drv_data = regmap, 64662306a36Sopenharmony_ci .of_node = dev->of_node, 64762306a36Sopenharmony_ci }; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci charger = devm_power_supply_register(dev, &act8600_charger_desc, &cfg); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(charger); 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic int act8865_pmic_probe(struct i2c_client *client) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci const struct i2c_device_id *i2c_id = i2c_client_get_device_id(client); 65762306a36Sopenharmony_ci const struct regulator_desc *regulators; 65862306a36Sopenharmony_ci struct act8865_platform_data *pdata = NULL; 65962306a36Sopenharmony_ci struct device *dev = &client->dev; 66062306a36Sopenharmony_ci int i, ret, num_regulators; 66162306a36Sopenharmony_ci struct act8865 *act8865; 66262306a36Sopenharmony_ci const struct regmap_config *regmap_config; 66362306a36Sopenharmony_ci unsigned long type; 66462306a36Sopenharmony_ci int off_reg, off_mask; 66562306a36Sopenharmony_ci int voltage_select = 0; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (dev->of_node) { 66862306a36Sopenharmony_ci const struct of_device_id *id; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci id = of_match_device(of_match_ptr(act8865_dt_ids), dev); 67162306a36Sopenharmony_ci if (!id) 67262306a36Sopenharmony_ci return -ENODEV; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci type = (unsigned long) id->data; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci voltage_select = !!of_get_property(dev->of_node, 67762306a36Sopenharmony_ci "active-semi,vsel-high", 67862306a36Sopenharmony_ci NULL); 67962306a36Sopenharmony_ci } else { 68062306a36Sopenharmony_ci type = i2c_id->driver_data; 68162306a36Sopenharmony_ci pdata = dev_get_platdata(dev); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci switch (type) { 68562306a36Sopenharmony_ci case ACT8600: 68662306a36Sopenharmony_ci regulators = act8600_regulators; 68762306a36Sopenharmony_ci num_regulators = ARRAY_SIZE(act8600_regulators); 68862306a36Sopenharmony_ci regmap_config = &act8600_regmap_config; 68962306a36Sopenharmony_ci off_reg = -1; 69062306a36Sopenharmony_ci off_mask = -1; 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci case ACT8846: 69362306a36Sopenharmony_ci regulators = act8846_regulators; 69462306a36Sopenharmony_ci num_regulators = ARRAY_SIZE(act8846_regulators); 69562306a36Sopenharmony_ci regmap_config = &act8865_regmap_config; 69662306a36Sopenharmony_ci off_reg = ACT8846_GLB_OFF_CTRL; 69762306a36Sopenharmony_ci off_mask = ACT8846_OFF_SYSMASK; 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci case ACT8865: 70062306a36Sopenharmony_ci if (voltage_select) { 70162306a36Sopenharmony_ci regulators = act8865_alt_regulators; 70262306a36Sopenharmony_ci num_regulators = ARRAY_SIZE(act8865_alt_regulators); 70362306a36Sopenharmony_ci } else { 70462306a36Sopenharmony_ci regulators = act8865_regulators; 70562306a36Sopenharmony_ci num_regulators = ARRAY_SIZE(act8865_regulators); 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci regmap_config = &act8865_regmap_config; 70862306a36Sopenharmony_ci off_reg = ACT8865_SYS_CTRL; 70962306a36Sopenharmony_ci off_mask = ACT8865_MSTROFF; 71062306a36Sopenharmony_ci break; 71162306a36Sopenharmony_ci default: 71262306a36Sopenharmony_ci dev_err(dev, "invalid device id %lu\n", type); 71362306a36Sopenharmony_ci return -EINVAL; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci act8865 = devm_kzalloc(dev, sizeof(struct act8865), GFP_KERNEL); 71762306a36Sopenharmony_ci if (!act8865) 71862306a36Sopenharmony_ci return -ENOMEM; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci act8865->regmap = devm_regmap_init_i2c(client, regmap_config); 72162306a36Sopenharmony_ci if (IS_ERR(act8865->regmap)) { 72262306a36Sopenharmony_ci ret = PTR_ERR(act8865->regmap); 72362306a36Sopenharmony_ci dev_err(dev, "Failed to allocate register map: %d\n", ret); 72462306a36Sopenharmony_ci return ret; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (of_device_is_system_power_controller(dev->of_node)) { 72862306a36Sopenharmony_ci if (!pm_power_off && (off_reg > 0)) { 72962306a36Sopenharmony_ci act8865_i2c_client = client; 73062306a36Sopenharmony_ci act8865->off_reg = off_reg; 73162306a36Sopenharmony_ci act8865->off_mask = off_mask; 73262306a36Sopenharmony_ci pm_power_off = act8865_power_off; 73362306a36Sopenharmony_ci } else { 73462306a36Sopenharmony_ci dev_err(dev, "Failed to set poweroff capability, already defined\n"); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* Finally register devices */ 73962306a36Sopenharmony_ci for (i = 0; i < num_regulators; i++) { 74062306a36Sopenharmony_ci const struct regulator_desc *desc = ®ulators[i]; 74162306a36Sopenharmony_ci struct regulator_config config = { }; 74262306a36Sopenharmony_ci struct regulator_dev *rdev; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci config.dev = dev; 74562306a36Sopenharmony_ci config.driver_data = act8865; 74662306a36Sopenharmony_ci config.regmap = act8865->regmap; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (pdata) { 74962306a36Sopenharmony_ci struct act8865_regulator_data *rdata; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci rdata = act8865_get_regulator_data(desc->id, pdata); 75262306a36Sopenharmony_ci if (rdata) { 75362306a36Sopenharmony_ci config.init_data = rdata->init_data; 75462306a36Sopenharmony_ci config.of_node = rdata->of_node; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci rdev = devm_regulator_register(dev, desc, &config); 75962306a36Sopenharmony_ci if (IS_ERR(rdev)) { 76062306a36Sopenharmony_ci dev_err(dev, "failed to register %s\n", desc->name); 76162306a36Sopenharmony_ci return PTR_ERR(rdev); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (type == ACT8600) { 76662306a36Sopenharmony_ci ret = act8600_charger_probe(dev, act8865->regmap); 76762306a36Sopenharmony_ci if (ret < 0) { 76862306a36Sopenharmony_ci if (ret != -EPROBE_DEFER) 76962306a36Sopenharmony_ci dev_err(dev, "Failed to probe charger"); 77062306a36Sopenharmony_ci return ret; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci i2c_set_clientdata(client, act8865); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* Unlock expert registers for ACT8865. */ 77762306a36Sopenharmony_ci return type != ACT8865 ? 0 : regmap_write(act8865->regmap, 77862306a36Sopenharmony_ci ACT8865_SYS_UNLK_REGS, 0xef); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic const struct i2c_device_id act8865_ids[] = { 78262306a36Sopenharmony_ci { .name = "act8600", .driver_data = ACT8600 }, 78362306a36Sopenharmony_ci { .name = "act8846", .driver_data = ACT8846 }, 78462306a36Sopenharmony_ci { .name = "act8865", .driver_data = ACT8865 }, 78562306a36Sopenharmony_ci { }, 78662306a36Sopenharmony_ci}; 78762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, act8865_ids); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic struct i2c_driver act8865_pmic_driver = { 79062306a36Sopenharmony_ci .driver = { 79162306a36Sopenharmony_ci .name = "act8865", 79262306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 79362306a36Sopenharmony_ci }, 79462306a36Sopenharmony_ci .probe = act8865_pmic_probe, 79562306a36Sopenharmony_ci .id_table = act8865_ids, 79662306a36Sopenharmony_ci}; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cimodule_i2c_driver(act8865_pmic_driver); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ciMODULE_DESCRIPTION("active-semi act88xx voltage regulator driver"); 80162306a36Sopenharmony_ciMODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); 80262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 803