162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (C) 2020 ROHM Semiconductors 362306a36Sopenharmony_ci// ROHM BD9576MUF/BD9573MUF regulator driver 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/err.h> 662306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 762306a36Sopenharmony_ci#include <linux/interrupt.h> 862306a36Sopenharmony_ci#include <linux/jiffies.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/mfd/rohm-bd957x.h> 1162306a36Sopenharmony_ci#include <linux/mfd/rohm-generic.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/property.h> 1662306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1762306a36Sopenharmony_ci#include <linux/regulator/machine.h> 1862306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/spinlock.h> 2162306a36Sopenharmony_ci#include <linux/workqueue.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define BD957X_VOUTS1_VOLT 3300000 2462306a36Sopenharmony_ci#define BD957X_VOUTS4_BASE_VOLT 1030000 2562306a36Sopenharmony_ci#define BD957X_VOUTS34_NUM_VOLT 32 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define BD9576_THERM_IRQ_MASK_TW BIT(5) 2862306a36Sopenharmony_ci#define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5) 2962306a36Sopenharmony_ci#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6) 3062306a36Sopenharmony_ci#define BD9576_xVD_IRQ_MASK_VOUT1TO4 0x0F 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic const unsigned int vout1_volt_table[] = { 3362306a36Sopenharmony_ci 5000000, 4900000, 4800000, 4700000, 4600000, 3462306a36Sopenharmony_ci 4500000, 4500000, 4500000, 5000000, 5100000, 3562306a36Sopenharmony_ci 5200000, 5300000, 5400000, 5500000, 5500000, 3662306a36Sopenharmony_ci 5500000 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const unsigned int vout2_volt_table[] = { 4062306a36Sopenharmony_ci 1800000, 1780000, 1760000, 1740000, 1720000, 4162306a36Sopenharmony_ci 1700000, 1680000, 1660000, 1800000, 1820000, 4262306a36Sopenharmony_ci 1840000, 1860000, 1880000, 1900000, 1920000, 4362306a36Sopenharmony_ci 1940000 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const unsigned int voutl1_volt_table[] = { 4762306a36Sopenharmony_ci 2500000, 2540000, 2580000, 2620000, 2660000, 4862306a36Sopenharmony_ci 2700000, 2740000, 2780000, 2500000, 2460000, 4962306a36Sopenharmony_ci 2420000, 2380000, 2340000, 2300000, 2260000, 5062306a36Sopenharmony_ci 2220000 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const struct linear_range vout1_xvd_ranges[] = { 5462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0), 5562306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000), 5662306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0), 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic const struct linear_range vout234_xvd_ranges[] = { 6062306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0), 6162306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000), 6262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(110000, 0x6e, 0x7f, 0), 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const struct linear_range voutL1_xvd_ranges[] = { 6662306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0), 6762306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000), 6862306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(220000, 0x6e, 0x7f, 0), 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic struct linear_range voutS1_ocw_ranges_internal[] = { 7262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(200000, 0x01, 0x04, 0), 7362306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(250000, 0x05, 0x18, 50000), 7462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1200000, 0x19, 0x3f, 0), 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic struct linear_range voutS1_ocw_ranges[] = { 7862306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(50000, 0x01, 0x04, 0), 7962306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(60000, 0x05, 0x18, 10000), 8062306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(250000, 0x19, 0x3f, 0), 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic struct linear_range voutS1_ocp_ranges_internal[] = { 8462306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(300000, 0x01, 0x06, 0), 8562306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(350000, 0x7, 0x1b, 50000), 8662306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1350000, 0x1c, 0x3f, 0), 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic struct linear_range voutS1_ocp_ranges[] = { 9062306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(70000, 0x01, 0x06, 0), 9162306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(80000, 0x7, 0x1b, 10000), 9262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(280000, 0x1c, 0x3f, 0), 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistruct bd957x_regulator_data { 9662306a36Sopenharmony_ci struct regulator_desc desc; 9762306a36Sopenharmony_ci int base_voltage; 9862306a36Sopenharmony_ci struct regulator_dev *rdev; 9962306a36Sopenharmony_ci int ovd_notif; 10062306a36Sopenharmony_ci int uvd_notif; 10162306a36Sopenharmony_ci int temp_notif; 10262306a36Sopenharmony_ci int ovd_err; 10362306a36Sopenharmony_ci int uvd_err; 10462306a36Sopenharmony_ci int temp_err; 10562306a36Sopenharmony_ci const struct linear_range *xvd_ranges; 10662306a36Sopenharmony_ci int num_xvd_ranges; 10762306a36Sopenharmony_ci bool oc_supported; 10862306a36Sopenharmony_ci unsigned int ovd_reg; 10962306a36Sopenharmony_ci unsigned int uvd_reg; 11062306a36Sopenharmony_ci unsigned int xvd_mask; 11162306a36Sopenharmony_ci unsigned int ocp_reg; 11262306a36Sopenharmony_ci unsigned int ocp_mask; 11362306a36Sopenharmony_ci unsigned int ocw_reg; 11462306a36Sopenharmony_ci unsigned int ocw_mask; 11562306a36Sopenharmony_ci unsigned int ocw_rfet; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#define BD9576_NUM_REGULATORS 6 11962306a36Sopenharmony_ci#define BD9576_NUM_OVD_REGULATORS 5 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistruct bd957x_data { 12262306a36Sopenharmony_ci struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS]; 12362306a36Sopenharmony_ci struct regmap *regmap; 12462306a36Sopenharmony_ci struct delayed_work therm_irq_suppress; 12562306a36Sopenharmony_ci struct delayed_work ovd_irq_suppress; 12662306a36Sopenharmony_ci struct delayed_work uvd_irq_suppress; 12762306a36Sopenharmony_ci unsigned int therm_irq; 12862306a36Sopenharmony_ci unsigned int ovd_irq; 12962306a36Sopenharmony_ci unsigned int uvd_irq; 13062306a36Sopenharmony_ci spinlock_t err_lock; 13162306a36Sopenharmony_ci int regulator_global_err; 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int bd957x_vout34_list_voltage(struct regulator_dev *rdev, 13562306a36Sopenharmony_ci unsigned int selector) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci const struct regulator_desc *desc = rdev->desc; 13862306a36Sopenharmony_ci int multiplier = selector & desc->vsel_mask & 0x7f; 13962306a36Sopenharmony_ci int tune; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* VOUT3 and 4 has 10mV step */ 14262306a36Sopenharmony_ci tune = multiplier * 10000; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (!(selector & 0x80)) 14562306a36Sopenharmony_ci return desc->fixed_uV - tune; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return desc->fixed_uV + tune; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int bd957x_list_voltage(struct regulator_dev *rdev, 15162306a36Sopenharmony_ci unsigned int selector) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci const struct regulator_desc *desc = rdev->desc; 15462306a36Sopenharmony_ci int index = selector & desc->vsel_mask & 0x7f; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (!(selector & 0x80)) 15762306a36Sopenharmony_ci index += desc->n_voltages/2; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (index >= desc->n_voltages) 16062306a36Sopenharmony_ci return -EINVAL; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return desc->volt_table[index]; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void bd9576_fill_ovd_flags(struct bd957x_regulator_data *data, 16662306a36Sopenharmony_ci bool warn) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci if (warn) { 16962306a36Sopenharmony_ci data->ovd_notif = REGULATOR_EVENT_OVER_VOLTAGE_WARN; 17062306a36Sopenharmony_ci data->ovd_err = REGULATOR_ERROR_OVER_VOLTAGE_WARN; 17162306a36Sopenharmony_ci } else { 17262306a36Sopenharmony_ci data->ovd_notif = REGULATOR_EVENT_REGULATION_OUT; 17362306a36Sopenharmony_ci data->ovd_err = REGULATOR_ERROR_REGULATION_OUT; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void bd9576_fill_ocp_flags(struct bd957x_regulator_data *data, 17862306a36Sopenharmony_ci bool warn) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci if (warn) { 18162306a36Sopenharmony_ci data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT_WARN; 18262306a36Sopenharmony_ci data->uvd_err = REGULATOR_ERROR_OVER_CURRENT_WARN; 18362306a36Sopenharmony_ci } else { 18462306a36Sopenharmony_ci data->uvd_notif = REGULATOR_EVENT_OVER_CURRENT; 18562306a36Sopenharmony_ci data->uvd_err = REGULATOR_ERROR_OVER_CURRENT; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void bd9576_fill_uvd_flags(struct bd957x_regulator_data *data, 19062306a36Sopenharmony_ci bool warn) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci if (warn) { 19362306a36Sopenharmony_ci data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE_WARN; 19462306a36Sopenharmony_ci data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE_WARN; 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci data->uvd_notif = REGULATOR_EVENT_UNDER_VOLTAGE; 19762306a36Sopenharmony_ci data->uvd_err = REGULATOR_ERROR_UNDER_VOLTAGE; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic void bd9576_fill_temp_flags(struct bd957x_regulator_data *data, 20262306a36Sopenharmony_ci bool enable, bool warn) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci if (!enable) { 20562306a36Sopenharmony_ci data->temp_notif = 0; 20662306a36Sopenharmony_ci data->temp_err = 0; 20762306a36Sopenharmony_ci } else if (warn) { 20862306a36Sopenharmony_ci data->temp_notif = REGULATOR_EVENT_OVER_TEMP_WARN; 20962306a36Sopenharmony_ci data->temp_err = REGULATOR_ERROR_OVER_TEMP_WARN; 21062306a36Sopenharmony_ci } else { 21162306a36Sopenharmony_ci data->temp_notif = REGULATOR_EVENT_OVER_TEMP; 21262306a36Sopenharmony_ci data->temp_err = REGULATOR_ERROR_OVER_TEMP; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int bd9576_set_limit(const struct linear_range *r, int num_ranges, 21762306a36Sopenharmony_ci struct regmap *regmap, int reg, int mask, int lim) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci int ret; 22062306a36Sopenharmony_ci bool found; 22162306a36Sopenharmony_ci int sel = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (lim) { 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ret = linear_range_get_selector_low_array(r, num_ranges, 22662306a36Sopenharmony_ci lim, &sel, &found); 22762306a36Sopenharmony_ci if (ret) 22862306a36Sopenharmony_ci return ret; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (!found) 23162306a36Sopenharmony_ci dev_warn(regmap_get_device(regmap), 23262306a36Sopenharmony_ci "limit %d out of range. Setting lower\n", 23362306a36Sopenharmony_ci lim); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return regmap_update_bits(regmap, reg, mask, sel); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic bool check_ocp_flag_mismatch(struct regulator_dev *rdev, int severity, 24062306a36Sopenharmony_ci struct bd957x_regulator_data *r) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci if ((severity == REGULATOR_SEVERITY_ERR && 24362306a36Sopenharmony_ci r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT) || 24462306a36Sopenharmony_ci (severity == REGULATOR_SEVERITY_WARN && 24562306a36Sopenharmony_ci r->uvd_notif != REGULATOR_EVENT_OVER_CURRENT_WARN)) { 24662306a36Sopenharmony_ci dev_warn(rdev_get_dev(rdev), 24762306a36Sopenharmony_ci "Can't support both OCP WARN and ERR\n"); 24862306a36Sopenharmony_ci /* Do not overwrite ERR config with WARN */ 24962306a36Sopenharmony_ci if (severity == REGULATOR_SEVERITY_WARN) 25062306a36Sopenharmony_ci return true; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci bd9576_fill_ocp_flags(r, 0); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return false; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic bool check_uvd_flag_mismatch(struct regulator_dev *rdev, int severity, 25962306a36Sopenharmony_ci struct bd957x_regulator_data *r) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci if ((severity == REGULATOR_SEVERITY_ERR && 26262306a36Sopenharmony_ci r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE) || 26362306a36Sopenharmony_ci (severity == REGULATOR_SEVERITY_WARN && 26462306a36Sopenharmony_ci r->uvd_notif != REGULATOR_EVENT_UNDER_VOLTAGE_WARN)) { 26562306a36Sopenharmony_ci dev_warn(rdev_get_dev(rdev), 26662306a36Sopenharmony_ci "Can't support both UVD WARN and ERR\n"); 26762306a36Sopenharmony_ci if (severity == REGULATOR_SEVERITY_WARN) 26862306a36Sopenharmony_ci return true; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci bd9576_fill_uvd_flags(r, 0); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return false; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic bool check_ovd_flag_mismatch(struct regulator_dev *rdev, int severity, 27762306a36Sopenharmony_ci struct bd957x_regulator_data *r) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci if ((severity == REGULATOR_SEVERITY_ERR && 28062306a36Sopenharmony_ci r->ovd_notif != REGULATOR_EVENT_REGULATION_OUT) || 28162306a36Sopenharmony_ci (severity == REGULATOR_SEVERITY_WARN && 28262306a36Sopenharmony_ci r->ovd_notif != REGULATOR_EVENT_OVER_VOLTAGE_WARN)) { 28362306a36Sopenharmony_ci dev_warn(rdev_get_dev(rdev), 28462306a36Sopenharmony_ci "Can't support both OVD WARN and ERR\n"); 28562306a36Sopenharmony_ci if (severity == REGULATOR_SEVERITY_WARN) 28662306a36Sopenharmony_ci return true; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci bd9576_fill_ovd_flags(r, 0); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return false; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic bool check_temp_flag_mismatch(struct regulator_dev *rdev, int severity, 29562306a36Sopenharmony_ci struct bd957x_regulator_data *r) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci if ((severity == REGULATOR_SEVERITY_ERR && 29862306a36Sopenharmony_ci r->temp_notif != REGULATOR_EVENT_OVER_TEMP) || 29962306a36Sopenharmony_ci (severity == REGULATOR_SEVERITY_WARN && 30062306a36Sopenharmony_ci r->temp_notif != REGULATOR_EVENT_OVER_TEMP_WARN)) { 30162306a36Sopenharmony_ci dev_warn(rdev_get_dev(rdev), 30262306a36Sopenharmony_ci "Can't support both thermal WARN and ERR\n"); 30362306a36Sopenharmony_ci if (severity == REGULATOR_SEVERITY_WARN) 30462306a36Sopenharmony_ci return true; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return false; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int bd9576_set_ocp(struct regulator_dev *rdev, int lim_uA, int severity, 31162306a36Sopenharmony_ci bool enable) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct bd957x_data *d; 31462306a36Sopenharmony_ci struct bd957x_regulator_data *r; 31562306a36Sopenharmony_ci int reg, mask; 31662306a36Sopenharmony_ci int Vfet, rfet; 31762306a36Sopenharmony_ci const struct linear_range *range; 31862306a36Sopenharmony_ci int num_ranges; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if ((lim_uA && !enable) || (!lim_uA && enable)) 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci r = container_of(rdev->desc, struct bd957x_regulator_data, desc); 32462306a36Sopenharmony_ci if (!r->oc_supported) 32562306a36Sopenharmony_ci return -EINVAL; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci d = rdev_get_drvdata(rdev); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (severity == REGULATOR_SEVERITY_PROT) { 33062306a36Sopenharmony_ci reg = r->ocp_reg; 33162306a36Sopenharmony_ci mask = r->ocp_mask; 33262306a36Sopenharmony_ci if (r->ocw_rfet) { 33362306a36Sopenharmony_ci range = voutS1_ocp_ranges; 33462306a36Sopenharmony_ci num_ranges = ARRAY_SIZE(voutS1_ocp_ranges); 33562306a36Sopenharmony_ci rfet = r->ocw_rfet / 1000; 33662306a36Sopenharmony_ci } else { 33762306a36Sopenharmony_ci range = voutS1_ocp_ranges_internal; 33862306a36Sopenharmony_ci num_ranges = ARRAY_SIZE(voutS1_ocp_ranges_internal); 33962306a36Sopenharmony_ci /* Internal values are already micro-amperes */ 34062306a36Sopenharmony_ci rfet = 1000; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } else { 34362306a36Sopenharmony_ci reg = r->ocw_reg; 34462306a36Sopenharmony_ci mask = r->ocw_mask; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (r->ocw_rfet) { 34762306a36Sopenharmony_ci range = voutS1_ocw_ranges; 34862306a36Sopenharmony_ci num_ranges = ARRAY_SIZE(voutS1_ocw_ranges); 34962306a36Sopenharmony_ci rfet = r->ocw_rfet / 1000; 35062306a36Sopenharmony_ci } else { 35162306a36Sopenharmony_ci range = voutS1_ocw_ranges_internal; 35262306a36Sopenharmony_ci num_ranges = ARRAY_SIZE(voutS1_ocw_ranges_internal); 35362306a36Sopenharmony_ci /* Internal values are already micro-amperes */ 35462306a36Sopenharmony_ci rfet = 1000; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* We abuse uvd fields for OCW on VoutS1 */ 35862306a36Sopenharmony_ci if (r->uvd_notif) { 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * If both warning and error are requested, prioritize 36162306a36Sopenharmony_ci * ERROR configuration 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci if (check_ocp_flag_mismatch(rdev, severity, r)) 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci } else { 36662306a36Sopenharmony_ci bool warn = severity == REGULATOR_SEVERITY_WARN; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci bd9576_fill_ocp_flags(r, warn); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * limits are given in uA, rfet is mOhm 37462306a36Sopenharmony_ci * Divide lim_uA by 1000 to get Vfet in uV. 37562306a36Sopenharmony_ci * (We expect both Rfet and limit uA to be magnitude of hundreds of 37662306a36Sopenharmony_ci * milli Amperes & milli Ohms => we should still have decent accuracy) 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci Vfet = lim_uA/1000 * rfet; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return bd9576_set_limit(range, num_ranges, d->regmap, 38162306a36Sopenharmony_ci reg, mask, Vfet); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int bd9576_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity, 38562306a36Sopenharmony_ci bool enable) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct bd957x_data *d; 38862306a36Sopenharmony_ci struct bd957x_regulator_data *r; 38962306a36Sopenharmony_ci int mask, reg; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (severity == REGULATOR_SEVERITY_PROT) { 39262306a36Sopenharmony_ci if (!enable || lim_uV) 39362306a36Sopenharmony_ci return -EINVAL; 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* 39862306a36Sopenharmony_ci * BD9576 has enable control as a special value in limit reg. Can't 39962306a36Sopenharmony_ci * set limit but keep feature disabled or enable W/O given limit. 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci if ((lim_uV && !enable) || (!lim_uV && enable)) 40262306a36Sopenharmony_ci return -EINVAL; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci r = container_of(rdev->desc, struct bd957x_regulator_data, desc); 40562306a36Sopenharmony_ci d = rdev_get_drvdata(rdev); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci mask = r->xvd_mask; 40862306a36Sopenharmony_ci reg = r->uvd_reg; 40962306a36Sopenharmony_ci /* 41062306a36Sopenharmony_ci * Check that there is no mismatch for what the detection IRQs are to 41162306a36Sopenharmony_ci * be used. 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci if (r->uvd_notif) { 41462306a36Sopenharmony_ci if (check_uvd_flag_mismatch(rdev, severity, r)) 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci } else { 41762306a36Sopenharmony_ci bd9576_fill_uvd_flags(r, severity == REGULATOR_SEVERITY_WARN); 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap, 42162306a36Sopenharmony_ci reg, mask, lim_uV); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int bd9576_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity, 42562306a36Sopenharmony_ci bool enable) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct bd957x_data *d; 42862306a36Sopenharmony_ci struct bd957x_regulator_data *r; 42962306a36Sopenharmony_ci int mask, reg; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (severity == REGULATOR_SEVERITY_PROT) { 43262306a36Sopenharmony_ci if (!enable || lim_uV) 43362306a36Sopenharmony_ci return -EINVAL; 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* 43862306a36Sopenharmony_ci * BD9576 has enable control as a special value in limit reg. Can't 43962306a36Sopenharmony_ci * set limit but keep feature disabled or enable W/O given limit. 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_ci if ((lim_uV && !enable) || (!lim_uV && enable)) 44262306a36Sopenharmony_ci return -EINVAL; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci r = container_of(rdev->desc, struct bd957x_regulator_data, desc); 44562306a36Sopenharmony_ci d = rdev_get_drvdata(rdev); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci mask = r->xvd_mask; 44862306a36Sopenharmony_ci reg = r->ovd_reg; 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * Check that there is no mismatch for what the detection IRQs are to 45162306a36Sopenharmony_ci * be used. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci if (r->ovd_notif) { 45462306a36Sopenharmony_ci if (check_ovd_flag_mismatch(rdev, severity, r)) 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci } else { 45762306a36Sopenharmony_ci bd9576_fill_ovd_flags(r, severity == REGULATOR_SEVERITY_WARN); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return bd9576_set_limit(r->xvd_ranges, r->num_xvd_ranges, d->regmap, 46162306a36Sopenharmony_ci reg, mask, lim_uV); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int bd9576_set_tw(struct regulator_dev *rdev, int lim, int severity, 46662306a36Sopenharmony_ci bool enable) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct bd957x_data *d; 46962306a36Sopenharmony_ci struct bd957x_regulator_data *r; 47062306a36Sopenharmony_ci int i; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* 47362306a36Sopenharmony_ci * BD9576MUF has fixed temperature limits 47462306a36Sopenharmony_ci * The detection can only be enabled/disabled 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci if (lim) 47762306a36Sopenharmony_ci return -EINVAL; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Protection can't be disabled */ 48062306a36Sopenharmony_ci if (severity == REGULATOR_SEVERITY_PROT) { 48162306a36Sopenharmony_ci if (!enable) 48262306a36Sopenharmony_ci return -EINVAL; 48362306a36Sopenharmony_ci else 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci r = container_of(rdev->desc, struct bd957x_regulator_data, desc); 48862306a36Sopenharmony_ci d = rdev_get_drvdata(rdev); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* 49162306a36Sopenharmony_ci * Check that there is no mismatch for what the detection IRQs are to 49262306a36Sopenharmony_ci * be used. 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci if (r->temp_notif) 49562306a36Sopenharmony_ci if (check_temp_flag_mismatch(rdev, severity, r)) 49662306a36Sopenharmony_ci return 0; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci bd9576_fill_temp_flags(r, enable, severity == REGULATOR_SEVERITY_WARN); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (enable) 50162306a36Sopenharmony_ci return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK, 50262306a36Sopenharmony_ci BD9576_THERM_IRQ_MASK_TW, 0); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* 50562306a36Sopenharmony_ci * If any of the regulators is interested in thermal warning we keep IRQ 50662306a36Sopenharmony_ci * enabled. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ci for (i = 0; i < BD9576_NUM_REGULATORS; i++) 50962306a36Sopenharmony_ci if (d->regulator_data[i].temp_notif) 51062306a36Sopenharmony_ci return 0; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK, 51362306a36Sopenharmony_ci BD9576_THERM_IRQ_MASK_TW, 51462306a36Sopenharmony_ci BD9576_THERM_IRQ_MASK_TW); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic const struct regulator_ops bd9573_vout34_ops = { 51862306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 51962306a36Sopenharmony_ci .list_voltage = bd957x_vout34_list_voltage, 52062306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 52162306a36Sopenharmony_ci}; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic const struct regulator_ops bd9576_vout34_ops = { 52462306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 52562306a36Sopenharmony_ci .list_voltage = bd957x_vout34_list_voltage, 52662306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 52762306a36Sopenharmony_ci .set_over_voltage_protection = bd9576_set_ovp, 52862306a36Sopenharmony_ci .set_under_voltage_protection = bd9576_set_uvp, 52962306a36Sopenharmony_ci .set_thermal_protection = bd9576_set_tw, 53062306a36Sopenharmony_ci}; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic const struct regulator_ops bd9573_vouts1_regulator_ops = { 53362306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 53462306a36Sopenharmony_ci}; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic const struct regulator_ops bd9576_vouts1_regulator_ops = { 53762306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 53862306a36Sopenharmony_ci .set_over_current_protection = bd9576_set_ocp, 53962306a36Sopenharmony_ci}; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic const struct regulator_ops bd9573_ops = { 54262306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 54362306a36Sopenharmony_ci .list_voltage = bd957x_list_voltage, 54462306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 54562306a36Sopenharmony_ci}; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic const struct regulator_ops bd9576_ops = { 54862306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 54962306a36Sopenharmony_ci .list_voltage = bd957x_list_voltage, 55062306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 55162306a36Sopenharmony_ci .set_over_voltage_protection = bd9576_set_ovp, 55262306a36Sopenharmony_ci .set_under_voltage_protection = bd9576_set_uvp, 55362306a36Sopenharmony_ci .set_thermal_protection = bd9576_set_tw, 55462306a36Sopenharmony_ci}; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic const struct regulator_ops *bd9573_ops_arr[] = { 55762306a36Sopenharmony_ci [BD957X_VD50] = &bd9573_ops, 55862306a36Sopenharmony_ci [BD957X_VD18] = &bd9573_ops, 55962306a36Sopenharmony_ci [BD957X_VDDDR] = &bd9573_vout34_ops, 56062306a36Sopenharmony_ci [BD957X_VD10] = &bd9573_vout34_ops, 56162306a36Sopenharmony_ci [BD957X_VOUTL1] = &bd9573_ops, 56262306a36Sopenharmony_ci [BD957X_VOUTS1] = &bd9573_vouts1_regulator_ops, 56362306a36Sopenharmony_ci}; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic const struct regulator_ops *bd9576_ops_arr[] = { 56662306a36Sopenharmony_ci [BD957X_VD50] = &bd9576_ops, 56762306a36Sopenharmony_ci [BD957X_VD18] = &bd9576_ops, 56862306a36Sopenharmony_ci [BD957X_VDDDR] = &bd9576_vout34_ops, 56962306a36Sopenharmony_ci [BD957X_VD10] = &bd9576_vout34_ops, 57062306a36Sopenharmony_ci [BD957X_VOUTL1] = &bd9576_ops, 57162306a36Sopenharmony_ci [BD957X_VOUTS1] = &bd9576_vouts1_regulator_ops, 57262306a36Sopenharmony_ci}; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic int vouts1_get_fet_res(struct device_node *np, 57562306a36Sopenharmony_ci const struct regulator_desc *desc, 57662306a36Sopenharmony_ci struct regulator_config *cfg) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct bd957x_regulator_data *data; 57962306a36Sopenharmony_ci int ret; 58062306a36Sopenharmony_ci u32 uohms; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci data = container_of(desc, struct bd957x_regulator_data, desc); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci ret = of_property_read_u32(np, "rohm,ocw-fet-ron-micro-ohms", &uohms); 58562306a36Sopenharmony_ci if (ret) { 58662306a36Sopenharmony_ci if (ret != -EINVAL) 58762306a36Sopenharmony_ci return ret; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci return 0; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci data->ocw_rfet = uohms; 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic struct bd957x_data bd957x_regulators = { 59662306a36Sopenharmony_ci .regulator_data = { 59762306a36Sopenharmony_ci { 59862306a36Sopenharmony_ci .desc = { 59962306a36Sopenharmony_ci .name = "VD50", 60062306a36Sopenharmony_ci .of_match = of_match_ptr("regulator-vd50"), 60162306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 60262306a36Sopenharmony_ci .id = BD957X_VD50, 60362306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 60462306a36Sopenharmony_ci .volt_table = &vout1_volt_table[0], 60562306a36Sopenharmony_ci .n_voltages = ARRAY_SIZE(vout1_volt_table), 60662306a36Sopenharmony_ci .vsel_reg = BD957X_REG_VOUT1_TUNE, 60762306a36Sopenharmony_ci .vsel_mask = BD957X_MASK_VOUT1_TUNE, 60862306a36Sopenharmony_ci .enable_reg = BD957X_REG_POW_TRIGGER1, 60962306a36Sopenharmony_ci .enable_mask = BD957X_REGULATOR_EN_MASK, 61062306a36Sopenharmony_ci .enable_val = BD957X_REGULATOR_DIS_VAL, 61162306a36Sopenharmony_ci .enable_is_inverted = true, 61262306a36Sopenharmony_ci .owner = THIS_MODULE, 61362306a36Sopenharmony_ci }, 61462306a36Sopenharmony_ci .xvd_ranges = vout1_xvd_ranges, 61562306a36Sopenharmony_ci .num_xvd_ranges = ARRAY_SIZE(vout1_xvd_ranges), 61662306a36Sopenharmony_ci .ovd_reg = BD9576_REG_VOUT1_OVD, 61762306a36Sopenharmony_ci .uvd_reg = BD9576_REG_VOUT1_UVD, 61862306a36Sopenharmony_ci .xvd_mask = BD9576_MASK_XVD, 61962306a36Sopenharmony_ci }, 62062306a36Sopenharmony_ci { 62162306a36Sopenharmony_ci .desc = { 62262306a36Sopenharmony_ci .name = "VD18", 62362306a36Sopenharmony_ci .of_match = of_match_ptr("regulator-vd18"), 62462306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 62562306a36Sopenharmony_ci .id = BD957X_VD18, 62662306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 62762306a36Sopenharmony_ci .volt_table = &vout2_volt_table[0], 62862306a36Sopenharmony_ci .n_voltages = ARRAY_SIZE(vout2_volt_table), 62962306a36Sopenharmony_ci .vsel_reg = BD957X_REG_VOUT2_TUNE, 63062306a36Sopenharmony_ci .vsel_mask = BD957X_MASK_VOUT2_TUNE, 63162306a36Sopenharmony_ci .enable_reg = BD957X_REG_POW_TRIGGER2, 63262306a36Sopenharmony_ci .enable_mask = BD957X_REGULATOR_EN_MASK, 63362306a36Sopenharmony_ci .enable_val = BD957X_REGULATOR_DIS_VAL, 63462306a36Sopenharmony_ci .enable_is_inverted = true, 63562306a36Sopenharmony_ci .owner = THIS_MODULE, 63662306a36Sopenharmony_ci }, 63762306a36Sopenharmony_ci .xvd_ranges = vout234_xvd_ranges, 63862306a36Sopenharmony_ci .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), 63962306a36Sopenharmony_ci .ovd_reg = BD9576_REG_VOUT2_OVD, 64062306a36Sopenharmony_ci .uvd_reg = BD9576_REG_VOUT2_UVD, 64162306a36Sopenharmony_ci .xvd_mask = BD9576_MASK_XVD, 64262306a36Sopenharmony_ci }, 64362306a36Sopenharmony_ci { 64462306a36Sopenharmony_ci .desc = { 64562306a36Sopenharmony_ci .name = "VDDDR", 64662306a36Sopenharmony_ci .of_match = of_match_ptr("regulator-vdddr"), 64762306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 64862306a36Sopenharmony_ci .id = BD957X_VDDDR, 64962306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 65062306a36Sopenharmony_ci .n_voltages = BD957X_VOUTS34_NUM_VOLT, 65162306a36Sopenharmony_ci .vsel_reg = BD957X_REG_VOUT3_TUNE, 65262306a36Sopenharmony_ci .vsel_mask = BD957X_MASK_VOUT3_TUNE, 65362306a36Sopenharmony_ci .enable_reg = BD957X_REG_POW_TRIGGER3, 65462306a36Sopenharmony_ci .enable_mask = BD957X_REGULATOR_EN_MASK, 65562306a36Sopenharmony_ci .enable_val = BD957X_REGULATOR_DIS_VAL, 65662306a36Sopenharmony_ci .enable_is_inverted = true, 65762306a36Sopenharmony_ci .owner = THIS_MODULE, 65862306a36Sopenharmony_ci }, 65962306a36Sopenharmony_ci .ovd_reg = BD9576_REG_VOUT3_OVD, 66062306a36Sopenharmony_ci .uvd_reg = BD9576_REG_VOUT3_UVD, 66162306a36Sopenharmony_ci .xvd_mask = BD9576_MASK_XVD, 66262306a36Sopenharmony_ci .xvd_ranges = vout234_xvd_ranges, 66362306a36Sopenharmony_ci .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), 66462306a36Sopenharmony_ci }, 66562306a36Sopenharmony_ci { 66662306a36Sopenharmony_ci .desc = { 66762306a36Sopenharmony_ci .name = "VD10", 66862306a36Sopenharmony_ci .of_match = of_match_ptr("regulator-vd10"), 66962306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 67062306a36Sopenharmony_ci .id = BD957X_VD10, 67162306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 67262306a36Sopenharmony_ci .fixed_uV = BD957X_VOUTS4_BASE_VOLT, 67362306a36Sopenharmony_ci .n_voltages = BD957X_VOUTS34_NUM_VOLT, 67462306a36Sopenharmony_ci .vsel_reg = BD957X_REG_VOUT4_TUNE, 67562306a36Sopenharmony_ci .vsel_mask = BD957X_MASK_VOUT4_TUNE, 67662306a36Sopenharmony_ci .enable_reg = BD957X_REG_POW_TRIGGER4, 67762306a36Sopenharmony_ci .enable_mask = BD957X_REGULATOR_EN_MASK, 67862306a36Sopenharmony_ci .enable_val = BD957X_REGULATOR_DIS_VAL, 67962306a36Sopenharmony_ci .enable_is_inverted = true, 68062306a36Sopenharmony_ci .owner = THIS_MODULE, 68162306a36Sopenharmony_ci }, 68262306a36Sopenharmony_ci .xvd_ranges = vout234_xvd_ranges, 68362306a36Sopenharmony_ci .num_xvd_ranges = ARRAY_SIZE(vout234_xvd_ranges), 68462306a36Sopenharmony_ci .ovd_reg = BD9576_REG_VOUT4_OVD, 68562306a36Sopenharmony_ci .uvd_reg = BD9576_REG_VOUT4_UVD, 68662306a36Sopenharmony_ci .xvd_mask = BD9576_MASK_XVD, 68762306a36Sopenharmony_ci }, 68862306a36Sopenharmony_ci { 68962306a36Sopenharmony_ci .desc = { 69062306a36Sopenharmony_ci .name = "VOUTL1", 69162306a36Sopenharmony_ci .of_match = of_match_ptr("regulator-voutl1"), 69262306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 69362306a36Sopenharmony_ci .id = BD957X_VOUTL1, 69462306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 69562306a36Sopenharmony_ci .volt_table = &voutl1_volt_table[0], 69662306a36Sopenharmony_ci .n_voltages = ARRAY_SIZE(voutl1_volt_table), 69762306a36Sopenharmony_ci .vsel_reg = BD957X_REG_VOUTL1_TUNE, 69862306a36Sopenharmony_ci .vsel_mask = BD957X_MASK_VOUTL1_TUNE, 69962306a36Sopenharmony_ci .enable_reg = BD957X_REG_POW_TRIGGERL1, 70062306a36Sopenharmony_ci .enable_mask = BD957X_REGULATOR_EN_MASK, 70162306a36Sopenharmony_ci .enable_val = BD957X_REGULATOR_DIS_VAL, 70262306a36Sopenharmony_ci .enable_is_inverted = true, 70362306a36Sopenharmony_ci .owner = THIS_MODULE, 70462306a36Sopenharmony_ci }, 70562306a36Sopenharmony_ci .xvd_ranges = voutL1_xvd_ranges, 70662306a36Sopenharmony_ci .num_xvd_ranges = ARRAY_SIZE(voutL1_xvd_ranges), 70762306a36Sopenharmony_ci .ovd_reg = BD9576_REG_VOUTL1_OVD, 70862306a36Sopenharmony_ci .uvd_reg = BD9576_REG_VOUTL1_UVD, 70962306a36Sopenharmony_ci .xvd_mask = BD9576_MASK_XVD, 71062306a36Sopenharmony_ci }, 71162306a36Sopenharmony_ci { 71262306a36Sopenharmony_ci .desc = { 71362306a36Sopenharmony_ci .name = "VOUTS1", 71462306a36Sopenharmony_ci .of_match = of_match_ptr("regulator-vouts1"), 71562306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), 71662306a36Sopenharmony_ci .id = BD957X_VOUTS1, 71762306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, 71862306a36Sopenharmony_ci .n_voltages = 1, 71962306a36Sopenharmony_ci .fixed_uV = BD957X_VOUTS1_VOLT, 72062306a36Sopenharmony_ci .enable_reg = BD957X_REG_POW_TRIGGERS1, 72162306a36Sopenharmony_ci .enable_mask = BD957X_REGULATOR_EN_MASK, 72262306a36Sopenharmony_ci .enable_val = BD957X_REGULATOR_DIS_VAL, 72362306a36Sopenharmony_ci .enable_is_inverted = true, 72462306a36Sopenharmony_ci .owner = THIS_MODULE, 72562306a36Sopenharmony_ci .of_parse_cb = vouts1_get_fet_res, 72662306a36Sopenharmony_ci }, 72762306a36Sopenharmony_ci .oc_supported = true, 72862306a36Sopenharmony_ci .ocw_reg = BD9576_REG_VOUT1S_OCW, 72962306a36Sopenharmony_ci .ocw_mask = BD9576_MASK_VOUT1S_OCW, 73062306a36Sopenharmony_ci .ocp_reg = BD9576_REG_VOUT1S_OCP, 73162306a36Sopenharmony_ci .ocp_mask = BD9576_MASK_VOUT1S_OCP, 73262306a36Sopenharmony_ci }, 73362306a36Sopenharmony_ci }, 73462306a36Sopenharmony_ci}; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic int bd9576_renable(struct regulator_irq_data *rid, int reg, int mask) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci int val, ret; 73962306a36Sopenharmony_ci struct bd957x_data *d = (struct bd957x_data *)rid->data; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci ret = regmap_read(d->regmap, reg, &val); 74262306a36Sopenharmony_ci if (ret) 74362306a36Sopenharmony_ci return REGULATOR_FAILED_RETRY; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (rid->opaque && rid->opaque == (val & mask)) { 74662306a36Sopenharmony_ci /* 74762306a36Sopenharmony_ci * It seems we stil have same status. Ack and return 74862306a36Sopenharmony_ci * information that we are still out of limits and core 74962306a36Sopenharmony_ci * should not enable IRQ 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_ci regmap_write(d->regmap, reg, mask & val); 75262306a36Sopenharmony_ci return REGULATOR_ERROR_ON; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci rid->opaque = 0; 75562306a36Sopenharmony_ci /* 75662306a36Sopenharmony_ci * Status was changed. Either prolem was solved or we have new issues. 75762306a36Sopenharmony_ci * Let's re-enable IRQs and be prepared to report problems again 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_ci return REGULATOR_ERROR_CLEARED; 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic int bd9576_uvd_renable(struct regulator_irq_data *rid) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci return bd9576_renable(rid, BD957X_REG_INT_UVD_STAT, UVD_IRQ_VALID_MASK); 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int bd9576_ovd_renable(struct regulator_irq_data *rid) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci return bd9576_renable(rid, BD957X_REG_INT_OVD_STAT, OVD_IRQ_VALID_MASK); 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic int bd9576_temp_renable(struct regulator_irq_data *rid) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci return bd9576_renable(rid, BD957X_REG_INT_THERM_STAT, 77562306a36Sopenharmony_ci BD9576_THERM_IRQ_MASK_TW); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic int bd9576_uvd_handler(int irq, struct regulator_irq_data *rid, 77962306a36Sopenharmony_ci unsigned long *dev_mask) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci int val, ret, i; 78262306a36Sopenharmony_ci struct bd957x_data *d = (struct bd957x_data *)rid->data; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci ret = regmap_read(d->regmap, BD957X_REG_INT_UVD_STAT, &val); 78562306a36Sopenharmony_ci if (ret) 78662306a36Sopenharmony_ci return REGULATOR_FAILED_RETRY; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci *dev_mask = 0; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci rid->opaque = val & UVD_IRQ_VALID_MASK; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* 79362306a36Sopenharmony_ci * Go through the set status bits and report either error or warning 79462306a36Sopenharmony_ci * to the notifier depending on what was flagged in DT 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_ci *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4; 79762306a36Sopenharmony_ci /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */ 79862306a36Sopenharmony_ci *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1); 79962306a36Sopenharmony_ci /* 80062306a36Sopenharmony_ci * We (ab)use the uvd for OCW notification. DT parsing should 80162306a36Sopenharmony_ci * have added correct OCW flag to uvd_notif and uvd_err for S1 80262306a36Sopenharmony_ci */ 80362306a36Sopenharmony_ci *dev_mask |= ((val & BD9576_UVD_IRQ_MASK_VOUTS1_OCW) >> 1); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci for_each_set_bit(i, dev_mask, 6) { 80662306a36Sopenharmony_ci struct bd957x_regulator_data *rdata; 80762306a36Sopenharmony_ci struct regulator_err_state *stat; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci rdata = &d->regulator_data[i]; 81062306a36Sopenharmony_ci stat = &rid->states[i]; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci stat->notifs = rdata->uvd_notif; 81362306a36Sopenharmony_ci stat->errors = rdata->uvd_err; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci ret = regmap_write(d->regmap, BD957X_REG_INT_UVD_STAT, 81762306a36Sopenharmony_ci UVD_IRQ_VALID_MASK & val); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic int bd9576_ovd_handler(int irq, struct regulator_irq_data *rid, 82362306a36Sopenharmony_ci unsigned long *dev_mask) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci int val, ret, i; 82662306a36Sopenharmony_ci struct bd957x_data *d = (struct bd957x_data *)rid->data; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci ret = regmap_read(d->regmap, BD957X_REG_INT_OVD_STAT, &val); 82962306a36Sopenharmony_ci if (ret) 83062306a36Sopenharmony_ci return REGULATOR_FAILED_RETRY; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci rid->opaque = val & OVD_IRQ_VALID_MASK; 83362306a36Sopenharmony_ci *dev_mask = 0; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (!(val & OVD_IRQ_VALID_MASK)) 83662306a36Sopenharmony_ci return 0; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci *dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4; 83962306a36Sopenharmony_ci /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */ 84062306a36Sopenharmony_ci *dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci for_each_set_bit(i, dev_mask, 5) { 84362306a36Sopenharmony_ci struct bd957x_regulator_data *rdata; 84462306a36Sopenharmony_ci struct regulator_err_state *stat; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci rdata = &d->regulator_data[i]; 84762306a36Sopenharmony_ci stat = &rid->states[i]; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci stat->notifs = rdata->ovd_notif; 85062306a36Sopenharmony_ci stat->errors = rdata->ovd_err; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* Clear the sub-IRQ status */ 85462306a36Sopenharmony_ci regmap_write(d->regmap, BD957X_REG_INT_OVD_STAT, 85562306a36Sopenharmony_ci OVD_IRQ_VALID_MASK & val); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci#define BD9576_DEV_MASK_ALL_REGULATORS 0x3F 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic int bd9576_thermal_handler(int irq, struct regulator_irq_data *rid, 86362306a36Sopenharmony_ci unsigned long *dev_mask) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci int val, ret, i; 86662306a36Sopenharmony_ci struct bd957x_data *d = (struct bd957x_data *)rid->data; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci ret = regmap_read(d->regmap, BD957X_REG_INT_THERM_STAT, &val); 86962306a36Sopenharmony_ci if (ret) 87062306a36Sopenharmony_ci return REGULATOR_FAILED_RETRY; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (!(val & BD9576_THERM_IRQ_MASK_TW)) { 87362306a36Sopenharmony_ci *dev_mask = 0; 87462306a36Sopenharmony_ci return 0; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci *dev_mask = BD9576_DEV_MASK_ALL_REGULATORS; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci for (i = 0; i < BD9576_NUM_REGULATORS; i++) { 88062306a36Sopenharmony_ci struct bd957x_regulator_data *rdata; 88162306a36Sopenharmony_ci struct regulator_err_state *stat; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci rdata = &d->regulator_data[i]; 88462306a36Sopenharmony_ci stat = &rid->states[i]; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci stat->notifs = rdata->temp_notif; 88762306a36Sopenharmony_ci stat->errors = rdata->temp_err; 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* Clear the sub-IRQ status */ 89162306a36Sopenharmony_ci regmap_write(d->regmap, BD957X_REG_INT_THERM_STAT, 89262306a36Sopenharmony_ci BD9576_THERM_IRQ_MASK_TW); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci return 0; 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int bd957x_probe(struct platform_device *pdev) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci int i; 90062306a36Sopenharmony_ci unsigned int num_reg_data; 90162306a36Sopenharmony_ci bool vout_mode, ddr_sel, may_have_irqs = false; 90262306a36Sopenharmony_ci struct regmap *regmap; 90362306a36Sopenharmony_ci struct bd957x_data *ic_data; 90462306a36Sopenharmony_ci struct regulator_config config = { 0 }; 90562306a36Sopenharmony_ci /* All regulators are related to UVD and thermal IRQs... */ 90662306a36Sopenharmony_ci struct regulator_dev *rdevs[BD9576_NUM_REGULATORS]; 90762306a36Sopenharmony_ci /* ...But VoutS1 is not flagged by OVD IRQ */ 90862306a36Sopenharmony_ci struct regulator_dev *ovd_devs[BD9576_NUM_OVD_REGULATORS]; 90962306a36Sopenharmony_ci static const struct regulator_irq_desc bd9576_notif_uvd = { 91062306a36Sopenharmony_ci .name = "bd9576-uvd", 91162306a36Sopenharmony_ci .irq_off_ms = 1000, 91262306a36Sopenharmony_ci .map_event = bd9576_uvd_handler, 91362306a36Sopenharmony_ci .renable = bd9576_uvd_renable, 91462306a36Sopenharmony_ci .data = &bd957x_regulators, 91562306a36Sopenharmony_ci }; 91662306a36Sopenharmony_ci static const struct regulator_irq_desc bd9576_notif_ovd = { 91762306a36Sopenharmony_ci .name = "bd9576-ovd", 91862306a36Sopenharmony_ci .irq_off_ms = 1000, 91962306a36Sopenharmony_ci .map_event = bd9576_ovd_handler, 92062306a36Sopenharmony_ci .renable = bd9576_ovd_renable, 92162306a36Sopenharmony_ci .data = &bd957x_regulators, 92262306a36Sopenharmony_ci }; 92362306a36Sopenharmony_ci static const struct regulator_irq_desc bd9576_notif_temp = { 92462306a36Sopenharmony_ci .name = "bd9576-temp", 92562306a36Sopenharmony_ci .irq_off_ms = 1000, 92662306a36Sopenharmony_ci .map_event = bd9576_thermal_handler, 92762306a36Sopenharmony_ci .renable = bd9576_temp_renable, 92862306a36Sopenharmony_ci .data = &bd957x_regulators, 92962306a36Sopenharmony_ci }; 93062306a36Sopenharmony_ci enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci num_reg_data = ARRAY_SIZE(bd957x_regulators.regulator_data); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci ic_data = &bd957x_regulators; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci regmap = dev_get_regmap(pdev->dev.parent, NULL); 93762306a36Sopenharmony_ci if (!regmap) { 93862306a36Sopenharmony_ci dev_err(&pdev->dev, "No regmap\n"); 93962306a36Sopenharmony_ci return -EINVAL; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci ic_data->regmap = regmap; 94362306a36Sopenharmony_ci vout_mode = device_property_read_bool(pdev->dev.parent, 94462306a36Sopenharmony_ci "rohm,vout1-en-low"); 94562306a36Sopenharmony_ci if (vout_mode) { 94662306a36Sopenharmony_ci struct gpio_desc *en; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci dev_dbg(&pdev->dev, "GPIO controlled mode\n"); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci /* VOUT1 enable state judged by VOUT1_EN pin */ 95162306a36Sopenharmony_ci /* See if we have GPIO defined */ 95262306a36Sopenharmony_ci en = devm_fwnode_gpiod_get(&pdev->dev, 95362306a36Sopenharmony_ci dev_fwnode(pdev->dev.parent), 95462306a36Sopenharmony_ci "rohm,vout1-en", GPIOD_OUT_LOW, 95562306a36Sopenharmony_ci "vout1-en"); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci /* VOUT1_OPS gpio ctrl */ 95862306a36Sopenharmony_ci /* 95962306a36Sopenharmony_ci * Regulator core prioritizes the ena_gpio over 96062306a36Sopenharmony_ci * enable/disable/is_enabled callbacks so no need to clear them 96162306a36Sopenharmony_ci * even if GPIO is used. So, we can still use same ops. 96262306a36Sopenharmony_ci * 96362306a36Sopenharmony_ci * In theory it is possible someone wants to set vout1-en LOW 96462306a36Sopenharmony_ci * during OTP loading and set VOUT1 to be controlled by GPIO - 96562306a36Sopenharmony_ci * but control the GPIO from some where else than this driver. 96662306a36Sopenharmony_ci * For that to work we should unset the is_enabled callback 96762306a36Sopenharmony_ci * here. 96862306a36Sopenharmony_ci * 96962306a36Sopenharmony_ci * I believe such case where rohm,vout1-en-low is set and 97062306a36Sopenharmony_ci * vout1-en-gpios is not is likely to be a misconfiguration. 97162306a36Sopenharmony_ci * So let's just err out for now. 97262306a36Sopenharmony_ci */ 97362306a36Sopenharmony_ci if (!IS_ERR(en)) 97462306a36Sopenharmony_ci config.ena_gpiod = en; 97562306a36Sopenharmony_ci else 97662306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(en), 97762306a36Sopenharmony_ci "Failed to get VOUT1 control GPIO\n"); 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci /* 98162306a36Sopenharmony_ci * If more than one PMIC needs to be controlled by same processor then 98262306a36Sopenharmony_ci * allocate the regulator data array here and use bd9576_regulators as 98362306a36Sopenharmony_ci * template. At the moment I see no such use-case so I spare some 98462306a36Sopenharmony_ci * bytes and use bd9576_regulators directly for non-constant configs 98562306a36Sopenharmony_ci * like DDR voltage selection. 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_ci platform_set_drvdata(pdev, ic_data); 98862306a36Sopenharmony_ci ddr_sel = device_property_read_bool(pdev->dev.parent, 98962306a36Sopenharmony_ci "rohm,ddr-sel-low"); 99062306a36Sopenharmony_ci if (ddr_sel) 99162306a36Sopenharmony_ci ic_data->regulator_data[2].desc.fixed_uV = 1350000; 99262306a36Sopenharmony_ci else 99362306a36Sopenharmony_ci ic_data->regulator_data[2].desc.fixed_uV = 1500000; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci switch (chip) { 99662306a36Sopenharmony_ci case ROHM_CHIP_TYPE_BD9576: 99762306a36Sopenharmony_ci may_have_irqs = true; 99862306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Found BD9576MUF\n"); 99962306a36Sopenharmony_ci break; 100062306a36Sopenharmony_ci case ROHM_CHIP_TYPE_BD9573: 100162306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Found BD9573MUF\n"); 100262306a36Sopenharmony_ci break; 100362306a36Sopenharmony_ci default: 100462306a36Sopenharmony_ci dev_err(&pdev->dev, "Unsupported chip type\n"); 100562306a36Sopenharmony_ci return -EINVAL; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci for (i = 0; i < num_reg_data; i++) { 100962306a36Sopenharmony_ci struct regulator_desc *d; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci d = &ic_data->regulator_data[i].desc; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci if (may_have_irqs) { 101562306a36Sopenharmony_ci if (d->id >= ARRAY_SIZE(bd9576_ops_arr)) 101662306a36Sopenharmony_ci return -EINVAL; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci d->ops = bd9576_ops_arr[d->id]; 101962306a36Sopenharmony_ci } else { 102062306a36Sopenharmony_ci if (d->id >= ARRAY_SIZE(bd9573_ops_arr)) 102162306a36Sopenharmony_ci return -EINVAL; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci d->ops = bd9573_ops_arr[d->id]; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci config.dev = pdev->dev.parent; 102862306a36Sopenharmony_ci config.regmap = regmap; 102962306a36Sopenharmony_ci config.driver_data = ic_data; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci for (i = 0; i < num_reg_data; i++) { 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci struct bd957x_regulator_data *r = &ic_data->regulator_data[i]; 103462306a36Sopenharmony_ci const struct regulator_desc *desc = &r->desc; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci r->rdev = devm_regulator_register(&pdev->dev, desc, 103762306a36Sopenharmony_ci &config); 103862306a36Sopenharmony_ci if (IS_ERR(r->rdev)) 103962306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(r->rdev), 104062306a36Sopenharmony_ci "failed to register %s regulator\n", 104162306a36Sopenharmony_ci desc->name); 104262306a36Sopenharmony_ci /* 104362306a36Sopenharmony_ci * Clear the VOUT1 GPIO setting - rest of the regulators do not 104462306a36Sopenharmony_ci * support GPIO control 104562306a36Sopenharmony_ci */ 104662306a36Sopenharmony_ci config.ena_gpiod = NULL; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (!may_have_irqs) 104962306a36Sopenharmony_ci continue; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci rdevs[i] = r->rdev; 105262306a36Sopenharmony_ci if (i < BD957X_VOUTS1) 105362306a36Sopenharmony_ci ovd_devs[i] = r->rdev; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci if (may_have_irqs) { 105662306a36Sopenharmony_ci void *ret; 105762306a36Sopenharmony_ci /* 105862306a36Sopenharmony_ci * We can add both the possible error and warning flags here 105962306a36Sopenharmony_ci * because the core uses these only for status clearing and 106062306a36Sopenharmony_ci * if we use warnings - errors are always clear and the other 106162306a36Sopenharmony_ci * way around. We can also add CURRENT flag for all regulators 106262306a36Sopenharmony_ci * because it is never set if it is not supported. Same applies 106362306a36Sopenharmony_ci * to setting UVD for VoutS1 - it is not accidentally cleared 106462306a36Sopenharmony_ci * as it is never set. 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_ci int uvd_errs = REGULATOR_ERROR_UNDER_VOLTAGE | 106762306a36Sopenharmony_ci REGULATOR_ERROR_UNDER_VOLTAGE_WARN | 106862306a36Sopenharmony_ci REGULATOR_ERROR_OVER_CURRENT | 106962306a36Sopenharmony_ci REGULATOR_ERROR_OVER_CURRENT_WARN; 107062306a36Sopenharmony_ci int ovd_errs = REGULATOR_ERROR_OVER_VOLTAGE_WARN | 107162306a36Sopenharmony_ci REGULATOR_ERROR_REGULATION_OUT; 107262306a36Sopenharmony_ci int temp_errs = REGULATOR_ERROR_OVER_TEMP | 107362306a36Sopenharmony_ci REGULATOR_ERROR_OVER_TEMP_WARN; 107462306a36Sopenharmony_ci int irq; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci irq = platform_get_irq_byname(pdev, "bd9576-uvd"); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* Register notifiers - can fail if IRQ is not given */ 107962306a36Sopenharmony_ci ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_uvd, 108062306a36Sopenharmony_ci irq, 0, uvd_errs, NULL, 108162306a36Sopenharmony_ci &rdevs[0], 108262306a36Sopenharmony_ci BD9576_NUM_REGULATORS); 108362306a36Sopenharmony_ci if (IS_ERR(ret)) { 108462306a36Sopenharmony_ci if (PTR_ERR(ret) == -EPROBE_DEFER) 108562306a36Sopenharmony_ci return -EPROBE_DEFER; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci dev_warn(&pdev->dev, "UVD disabled %pe\n", ret); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci irq = platform_get_irq_byname(pdev, "bd9576-ovd"); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_ovd, 109362306a36Sopenharmony_ci irq, 0, ovd_errs, NULL, 109462306a36Sopenharmony_ci &ovd_devs[0], 109562306a36Sopenharmony_ci BD9576_NUM_OVD_REGULATORS); 109662306a36Sopenharmony_ci if (IS_ERR(ret)) { 109762306a36Sopenharmony_ci if (PTR_ERR(ret) == -EPROBE_DEFER) 109862306a36Sopenharmony_ci return -EPROBE_DEFER; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci dev_warn(&pdev->dev, "OVD disabled %pe\n", ret); 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci irq = platform_get_irq_byname(pdev, "bd9576-temp"); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_temp, 110562306a36Sopenharmony_ci irq, 0, temp_errs, NULL, 110662306a36Sopenharmony_ci &rdevs[0], 110762306a36Sopenharmony_ci BD9576_NUM_REGULATORS); 110862306a36Sopenharmony_ci if (IS_ERR(ret)) { 110962306a36Sopenharmony_ci if (PTR_ERR(ret) == -EPROBE_DEFER) 111062306a36Sopenharmony_ci return -EPROBE_DEFER; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci dev_warn(&pdev->dev, "Thermal warning disabled %pe\n", 111362306a36Sopenharmony_ci ret); 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci return 0; 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_cistatic const struct platform_device_id bd957x_pmic_id[] = { 112062306a36Sopenharmony_ci { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 }, 112162306a36Sopenharmony_ci { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 }, 112262306a36Sopenharmony_ci { }, 112362306a36Sopenharmony_ci}; 112462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, bd957x_pmic_id); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic struct platform_driver bd957x_regulator = { 112762306a36Sopenharmony_ci .driver = { 112862306a36Sopenharmony_ci .name = "bd957x-pmic", 112962306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 113062306a36Sopenharmony_ci }, 113162306a36Sopenharmony_ci .probe = bd957x_probe, 113262306a36Sopenharmony_ci .id_table = bd957x_pmic_id, 113362306a36Sopenharmony_ci}; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_cimodule_platform_driver(bd957x_regulator); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ciMODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 113862306a36Sopenharmony_ciMODULE_DESCRIPTION("ROHM BD9576/BD9573 voltage regulator driver"); 113962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 114062306a36Sopenharmony_ciMODULE_ALIAS("platform:bd957x-pmic"); 1141