rk8xx.c 9.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright (C) 2015 Google, Inc
 * Written by Simon Glass <sjg@chromium.org>
 *
 * Based on Rockchip's drivers/power/pmic/pmic_rk808.c:
 * Copyright (C) 2012 rockchips
 * zyw <zyw@rock-chips.com>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <dm.h>
#include <errno.h>
J
Jacob Chen 已提交
15
#include <power/rk8xx_pmic.h>
16 17 18 19 20 21 22
#include <power/pmic.h>
#include <power/regulator.h>

#ifndef CONFIG_SPL_BUILD
#define ENABLE_DRIVER
#endif

23 24 25 26 27
/* Field Definitions */
#define RK808_BUCK_VSEL_MASK	0x3f
#define RK808_BUCK4_VSEL_MASK	0xf
#define RK808_LDO_VSEL_MASK	0x1f

28 29 30 31 32
#define RK818_BUCK_VSEL_MASK		0x3f
#define RK818_BUCK4_VSEL_MASK		0x1f
#define RK818_LDO_VSEL_MASK		0x1f
#define RK818_LDO3_ON_VSEL_MASK	0xf
#define RK818_BOOST_ON_VSEL_MASK	0xe0
33 34 35
#define RK818_USB_ILIM_SEL_MASK		0x0f
#define RK818_USB_CHG_SD_VSEL_MASK	0x70

36

J
Jacob Chen 已提交
37
struct rk8xx_reg_info {
38 39 40
	uint min_uv;
	uint step_uv;
	s8 vsel_reg;
41
	u8 vsel_mask;
42 43
};

J
Jacob Chen 已提交
44
static const struct rk8xx_reg_info rk808_buck[] = {
45 46 47 48
	{ 712500, 12500, REG_BUCK1_ON_VSEL, RK808_BUCK_VSEL_MASK, },
	{ 712500, 12500, REG_BUCK2_ON_VSEL, RK808_BUCK_VSEL_MASK, },
	{ 712500, 12500, -1, RK808_BUCK_VSEL_MASK, },
	{ 1800000, 100000, REG_BUCK4_ON_VSEL, RK808_BUCK4_VSEL_MASK, },
49 50
};

51 52 53 54 55 56 57 58
static const struct rk8xx_reg_info rk818_buck[] = {
	{ 712500, 12500, REG_BUCK1_ON_VSEL, RK818_BUCK_VSEL_MASK, },
	{ 712500, 12500, REG_BUCK2_ON_VSEL, RK818_BUCK_VSEL_MASK, },
	{ 712500, 12500, -1, RK818_BUCK_VSEL_MASK, },
	{ 1800000, 100000, REG_BUCK4_ON_VSEL, RK818_BUCK4_VSEL_MASK, },
};

#ifdef ENABLE_DRIVER
J
Jacob Chen 已提交
59
static const struct rk8xx_reg_info rk808_ldo[] = {
60 61 62 63 64 65 66 67
	{ 1800000, 100000, REG_LDO1_ON_VSEL, RK808_LDO_VSEL_MASK, },
	{ 1800000, 100000, REG_LDO2_ON_VSEL, RK808_LDO_VSEL_MASK, },
	{ 800000, 100000, REG_LDO3_ON_VSEL, RK808_BUCK4_VSEL_MASK, },
	{ 1800000, 100000, REG_LDO4_ON_VSEL, RK808_LDO_VSEL_MASK, },
	{ 1800000, 100000, REG_LDO5_ON_VSEL, RK808_LDO_VSEL_MASK, },
	{ 800000, 100000, REG_LDO6_ON_VSEL, RK808_LDO_VSEL_MASK, },
	{ 800000, 100000, REG_LDO7_ON_VSEL, RK808_LDO_VSEL_MASK, },
	{ 1800000, 100000, REG_LDO8_ON_VSEL, RK808_LDO_VSEL_MASK, },
68 69
};

J
Jacob Chen 已提交
70
static const struct rk8xx_reg_info rk818_ldo[] = {
71 72 73 74 75 76 77 78 79
	{ 1800000, 100000, REG_LDO1_ON_VSEL, RK818_LDO_VSEL_MASK, },
	{ 1800000, 100000, REG_LDO2_ON_VSEL, RK818_LDO_VSEL_MASK, },
	{ 800000, 100000, REG_LDO3_ON_VSEL, RK818_LDO3_ON_VSEL_MASK, },
	{ 1800000, 100000, REG_LDO4_ON_VSEL, RK818_LDO_VSEL_MASK, },
	{ 1800000, 100000, REG_LDO5_ON_VSEL, RK818_LDO_VSEL_MASK, },
	{ 800000, 100000, REG_LDO6_ON_VSEL, RK818_LDO_VSEL_MASK, },
	{ 800000, 100000, REG_LDO7_ON_VSEL, RK818_LDO_VSEL_MASK, },
	{ 1800000, 100000, REG_LDO8_ON_VSEL, RK818_LDO_VSEL_MASK, },
};
80
#endif
81

82 83 84 85 86 87 88 89
static const u16 rk818_chrg_cur_input_array[] = {
	450, 800, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000
};

static const uint rk818_chrg_shutdown_vsel_array[] = {
	2780000, 2850000, 2920000, 2990000, 3060000, 3130000, 3190000, 3260000
};

J
Jacob Chen 已提交
90
static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
91 92
					     int num)
{
J
Jacob Chen 已提交
93 94
	struct rk8xx_priv *priv = dev_get_priv(pmic);
	switch (priv->variant) {
95 96 97 98 99 100 101
	case RK818_ID:
		return &rk818_buck[num];
	default:
		return &rk808_buck[num];
	}
}

102 103
static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
{
J
Jacob Chen 已提交
104
	const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck - 1);
105
	int mask = info->vsel_mask;
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
	int val;

	if (info->vsel_reg == -1)
		return -ENOSYS;
	val = (uvolt - info->min_uv) / info->step_uv;
	debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask,
	      val);

	return pmic_clrsetbits(pmic, info->vsel_reg, mask, val);
}

static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
{
	uint mask;
	int ret;

	buck--;
	mask = 1 << buck;
	if (enable) {
125
		ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX, 0, 3 << (buck * 2));
126 127 128 129 130 131 132 133 134 135 136
		if (ret)
			return ret;
		ret = pmic_clrsetbits(pmic, REG_DCDC_UV_ACT, 1 << buck, 0);
		if (ret)
			return ret;
	}

	return pmic_clrsetbits(pmic, REG_DCDC_EN, mask, enable ? mask : 0);
}

#ifdef ENABLE_DRIVER
137 138 139 140 141 142 143 144 145 146 147 148
static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
					     int num)
{
	struct rk8xx_priv *priv = dev_get_priv(pmic);
	switch (priv->variant) {
	case RK818_ID:
		return &rk818_ldo[num];
	default:
		return &rk808_ldo[num];
	}
}

149 150 151
static int buck_get_value(struct udevice *dev)
{
	int buck = dev->driver_data - 1;
J
Jacob Chen 已提交
152
	const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck);
153
	int mask = info->vsel_mask;
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
	int ret, val;

	if (info->vsel_reg == -1)
		return -ENOSYS;
	ret = pmic_reg_read(dev->parent, info->vsel_reg);
	if (ret < 0)
		return ret;
	val = ret & mask;

	return info->min_uv + val * info->step_uv;
}

static int buck_set_value(struct udevice *dev, int uvolt)
{
	int buck = dev->driver_data;

	return _buck_set_value(dev->parent, buck, uvolt);
}

static int buck_set_enable(struct udevice *dev, bool enable)
{
	int buck = dev->driver_data;

	return _buck_set_enable(dev->parent, buck, enable);
}

static bool buck_get_enable(struct udevice *dev)
{
	int buck = dev->driver_data - 1;
	int ret;
	uint mask;

	mask = 1 << buck;

	ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
	if (ret < 0)
		return ret;

	return ret & mask ? true : false;
}

static int ldo_get_value(struct udevice *dev)
{
	int ldo = dev->driver_data - 1;
J
Jacob Chen 已提交
198
	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo);
199
	int mask = info->vsel_mask;
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
	int ret, val;

	if (info->vsel_reg == -1)
		return -ENOSYS;
	ret = pmic_reg_read(dev->parent, info->vsel_reg);
	if (ret < 0)
		return ret;
	val = ret & mask;

	return info->min_uv + val * info->step_uv;
}

static int ldo_set_value(struct udevice *dev, int uvolt)
{
	int ldo = dev->driver_data - 1;
J
Jacob Chen 已提交
215
	const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo);
216
	int mask = info->vsel_mask;
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
	int val;

	if (info->vsel_reg == -1)
		return -ENOSYS;
	val = (uvolt - info->min_uv) / info->step_uv;
	debug("%s: reg=%x, mask=%x, val=%x\n", __func__, info->vsel_reg, mask,
	      val);

	return pmic_clrsetbits(dev->parent, info->vsel_reg, mask, val);
}

static int ldo_set_enable(struct udevice *dev, bool enable)
{
	int ldo = dev->driver_data - 1;
	uint mask;

	mask = 1 << ldo;

	return pmic_clrsetbits(dev->parent, REG_LDO_EN, mask,
			       enable ? mask : 0);
}

static bool ldo_get_enable(struct udevice *dev)
{
	int ldo = dev->driver_data - 1;
	int ret;
	uint mask;

	mask = 1 << ldo;

	ret = pmic_reg_read(dev->parent, REG_LDO_EN);
	if (ret < 0)
		return ret;

	return ret & mask ? true : false;
}

static int switch_set_enable(struct udevice *dev, bool enable)
{
	int sw = dev->driver_data - 1;
	uint mask;

	mask = 1 << (sw + 5);

	return pmic_clrsetbits(dev->parent, REG_DCDC_EN, mask,
			       enable ? mask : 0);
}

static bool switch_get_enable(struct udevice *dev)
{
	int sw = dev->driver_data - 1;
	int ret;
	uint mask;

	mask = 1 << (sw + 5);

	ret = pmic_reg_read(dev->parent, REG_DCDC_EN);
	if (ret < 0)
		return ret;

	return ret & mask ? true : false;
}

J
Jacob Chen 已提交
280
static int rk8xx_buck_probe(struct udevice *dev)
281 282 283 284 285 286 287 288 289 290 291
{
	struct dm_regulator_uclass_platdata *uc_pdata;

	uc_pdata = dev_get_uclass_platdata(dev);

	uc_pdata->type = REGULATOR_TYPE_BUCK;
	uc_pdata->mode_count = 0;

	return 0;
}

J
Jacob Chen 已提交
292
static int rk8xx_ldo_probe(struct udevice *dev)
293 294 295 296 297 298 299 300 301 302 303
{
	struct dm_regulator_uclass_platdata *uc_pdata;

	uc_pdata = dev_get_uclass_platdata(dev);

	uc_pdata->type = REGULATOR_TYPE_LDO;
	uc_pdata->mode_count = 0;

	return 0;
}

J
Jacob Chen 已提交
304
static int rk8xx_switch_probe(struct udevice *dev)
305 306 307 308 309 310 311 312 313 314 315
{
	struct dm_regulator_uclass_platdata *uc_pdata;

	uc_pdata = dev_get_uclass_platdata(dev);

	uc_pdata->type = REGULATOR_TYPE_FIXED;
	uc_pdata->mode_count = 0;

	return 0;
}

J
Jacob Chen 已提交
316
static const struct dm_regulator_ops rk8xx_buck_ops = {
317 318 319 320 321 322
	.get_value  = buck_get_value,
	.set_value  = buck_set_value,
	.get_enable = buck_get_enable,
	.set_enable = buck_set_enable,
};

J
Jacob Chen 已提交
323
static const struct dm_regulator_ops rk8xx_ldo_ops = {
324 325 326 327 328 329
	.get_value  = ldo_get_value,
	.set_value  = ldo_set_value,
	.get_enable = ldo_get_enable,
	.set_enable = ldo_set_enable,
};

J
Jacob Chen 已提交
330
static const struct dm_regulator_ops rk8xx_switch_ops = {
331 332 333 334
	.get_enable = switch_get_enable,
	.set_enable = switch_set_enable,
};

J
Jacob Chen 已提交
335 336
U_BOOT_DRIVER(rk8xx_buck) = {
	.name = "rk8xx_buck",
337
	.id = UCLASS_REGULATOR,
J
Jacob Chen 已提交
338 339
	.ops = &rk8xx_buck_ops,
	.probe = rk8xx_buck_probe,
340 341
};

J
Jacob Chen 已提交
342 343
U_BOOT_DRIVER(rk8xx_ldo) = {
	.name = "rk8xx_ldo",
344
	.id = UCLASS_REGULATOR,
J
Jacob Chen 已提交
345 346
	.ops = &rk8xx_ldo_ops,
	.probe = rk8xx_ldo_probe,
347 348
};

J
Jacob Chen 已提交
349 350
U_BOOT_DRIVER(rk8xx_switch) = {
	.name = "rk8xx_switch",
351
	.id = UCLASS_REGULATOR,
J
Jacob Chen 已提交
352 353
	.ops = &rk8xx_switch_ops,
	.probe = rk8xx_switch_probe,
354 355 356
};
#endif

J
Jacob Chen 已提交
357
int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
358 359 360 361 362 363 364 365 366
{
	int ret;

	ret = _buck_set_value(pmic, buck, uvolt);
	if (ret)
		return ret;

	return _buck_set_enable(pmic, buck, true);
}
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389

int rk818_spl_configure_usb_input_current(struct udevice *pmic, int current_ma)
{
	uint i;

	for (i = 0; i < ARRAY_SIZE(rk818_chrg_cur_input_array); i++)
		if (current_ma <= rk818_chrg_cur_input_array[i])
			break;

	return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_ILIM_SEL_MASK, i);
}

int rk818_spl_configure_usb_chrg_shutdown(struct udevice *pmic, int uvolt)
{
	uint i;

	for (i = 0; i < ARRAY_SIZE(rk818_chrg_shutdown_vsel_array); i++)
		if (uvolt <= rk818_chrg_shutdown_vsel_array[i])
			break;

	return pmic_clrsetbits(pmic, REG_USB_CTRL, RK818_USB_CHG_SD_VSEL_MASK,
			       i);
}