// SPDX-License-Identifier: GPL-2.0+
//
// max8998.c - Voltage regulator driver for the Maxim 8998
//
// Copyright (C) 2009-2010 Samsung Electronics
// Kyungmin Park <kyungmin.park@samsung.com>
// Marek Szyprowski <m.szyprowski@samsung.com>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/max8998.h>
#include <linux/mfd/max8998-private.h>
struct max8998_data {
struct device *dev;
struct max8998_dev *iodev;
int num_regulators;
u8 buck1_vol[4]; /* voltages for selection */
u8 buck2_vol[2];
unsigned int buck1_idx; /* index to last changed voltage */
/* value in a set */
unsigned int buck2_idx;
};
static const unsigned int charger_current_table[] = {
90000, 380000, 475000, 550000, 570000, 600000, 700000, 800000,
};
static int max8998_get_enable_register(struct regulator_dev *rdev,
int *reg, int *shift)
{
int ldo = rdev_get_id(rdev);
switch (ldo) {
case MAX8998_LDO2 ... MAX8998_LDO5:
*reg = MAX8998_REG_ONOFF1;
*shift = 3 - (ldo - MAX8998_LDO2);
break;
case MAX8998_LDO6 ... MAX8998_LDO13:
*reg = MAX8998_REG_ONOFF2;
*shift = 7 - (ldo - MAX8998_LDO6);
break;
case MAX8998_LDO14 ... MAX8998_LDO17:
*reg = MAX8998_REG_ONOFF3;
*shift = 7 - (ldo - MAX8998_LDO14);
break;
case MAX8998_BUCK1 ... MAX8998_BUCK4:
*reg = MAX8998_REG_ONOFF1;
*shift = 7 - (ldo - MAX8998_BUCK1);
break;
case MAX8998_EN32KHZ_AP ... MAX8998_ENVICHG:
*reg = MAX8998_REG_ONOFF4;
*shift = 7 - (ldo - MAX8998_EN32KHZ_AP);
break;
case MAX8998_ESAFEOUT1 ... MAX8998_ESAFEOUT2:
*reg = MAX8998_REG_CHGR2;
*shift = 7 - (ldo - MAX8998_ESAFEOUT1);
break;
case MAX8998_CHARGER:
*reg = MAX8998_REG_CHGR2;
*shift = 0;
break;
default:
return -EINVAL;
}
return 0;
}
static int max8998_ldo_is_enabled(struct regulator_dev *rdev)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
struct i2c_client *i2c = max8998->iodev->i2c;
int ret, reg, shift = 8;
u8 val;
ret = max8998_get_enable_register(rdev, ®, &shift);
if (ret)
return ret;
ret = max8998_read_reg(i2c, reg, &val);
if (ret)
return ret;
return val & (1 << shift);
}
static int max8998_ldo_is_enabled_inverted(struct regulator_dev *rdev)
{
return (!max8998_ldo_is_enabled(rdev));
}
static int max8998_ldo_enable(struct regulator_dev *rdev)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
struct i2c_client *i2c = max8998->iodev->i2c;
int reg, shift = 8, ret;
ret = max8998_get_enable_register(rdev, ®, &shift);
if (ret)
return ret;
return max8998_update_reg(i2c, reg, 1<<shift, 1<<shift);
}
static int max8998_ldo_disable(struct regulator_dev *rdev)
{
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
struct i2c_client *i2c = max8998->iodev->i2c;
int reg, shift = 8, ret;
ret = max8998_get_enable_register(rdev, ®, &shift);
if (ret)
return ret;
return max8998_update_reg(i2c, reg, 0, 1<<shift);
}
static int max8998_get_voltage_register(struct regulator_dev *rdev,
int *_reg, int *_shift, int *_mask)
{
int ldo = rdev_get_id(rdev);
struct max8998_data *max8998 = rdev_get_drvdata(rdev);
int reg, shift = 0, mask = 0xff;
switch (ldo) {
case MAX8998_LDO2 ... MAX8998_LDO3:
reg = MAX8998_REG_LDO2_LDO3;
mask = 0xf;
if (ldo == MAX8998_LDO2)
shift = 4;
else
shift = 0;
break;
case MAX8998_LDO4 ... MAX8998_LDO7:
reg = MAX8998_REG_LDO4 + (ldo - MAX8998_LDO4);
break;
case MAX8998_LDO8 ... MAX8998_LDO9:
reg = MAX8998_REG_LDO8_LDO9;
mask = 0xf;
if (ldo == MAX8998_LDO8)
shift = 4;
else
shift = 0;
break;
case MAX8998_LDO10 ... MAX8998_LDO11:
reg = MAX8998_REG_LDO10_LDO11;
if (ldo