1da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown/*
2da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown * wm8350.c  --  Voltage and current regulation for the Wolfson WM8350 PMIC
3da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown *
4da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown * Copyright 2007, 2008 Wolfson Microelectronics PLC.
5da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown *
6da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown * Author: Liam Girdwood
7da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown *         linux@wolfsonmicro.com
8da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown *
9da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown *  This program is free software; you can redistribute  it and/or modify it
10da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown *  under  the terms of  the GNU General  Public License as published by the
11da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown *  Free Software Foundation;  either version 2 of the  License, or (at your
12da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown *  option) any later version.
13da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown */
14da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
15da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/module.h>
16da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/moduleparam.h>
17da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/init.h>
18da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/bitops.h>
19da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/err.h>
20da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/i2c.h>
21da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/mfd/wm8350/core.h>
22da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/mfd/wm8350/pmic.h>
23da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/platform_device.h>
24da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/regulator/driver.h>
25da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown#include <linux/regulator/machine.h>
26da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
27221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown/* Maximum value possible for VSEL */
28221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown#define WM8350_DCDC_MAX_VSEL 0x66
29221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown
30da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown/* Microamps */
31da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic const int isink_cur[] = {
32da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	4,
33da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	5,
34da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	6,
35da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	7,
36da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	8,
37da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	10,
38da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	11,
39da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	14,
40da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	16,
41da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	19,
42da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	23,
43da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	27,
44da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	32,
45da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	39,
46da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	46,
47da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	54,
48da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	65,
49da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	77,
50da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	92,
51da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	109,
52da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	130,
53da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	154,
54da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	183,
55da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	218,
56da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	259,
57da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	308,
58da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	367,
59da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	436,
60da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	518,
61da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	616,
62da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	733,
63da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	872,
64da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	1037,
65da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	1233,
66da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	1466,
67da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	1744,
68da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	2073,
69da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	2466,
70da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	2933,
71da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	3487,
72da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	4147,
73da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	4932,
74da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	5865,
75da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	6975,
76da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	8294,
77da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	9864,
78da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	11730,
79da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	13949,
80da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	16589,
81da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	19728,
82da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	23460,
83da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	27899,
84da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	33178,
85da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	39455,
86da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	46920,
87da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	55798,
88da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	66355,
89da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	78910,
90da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	93840,
91da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	111596,
92da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	132710,
93da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	157820,
94da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	187681,
95da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	223191
96da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
97da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
98da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int get_isink_val(int min_uA, int max_uA, u16 *setting)
99da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
100da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int i;
101da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1023a744038b3709cd467b693f3e146c6d5b8120a18Axel Lin	for (i = 0; i < ARRAY_SIZE(isink_cur); i++) {
103da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		if (min_uA <= isink_cur[i] && max_uA >= isink_cur[i]) {
104da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			*setting = i;
105da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			return 0;
106da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		}
107da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
108da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return -EINVAL;
109da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
110da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
111da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic inline int wm8350_ldo_val_to_mvolts(unsigned int val)
112da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
113da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (val < 16)
114da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return (val * 50) + 900;
115da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	else
116da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return ((val - 16) * 100) + 1800;
117da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
118da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
119da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
120da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
121da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
122da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (mV < 1800)
123da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return (mV - 900) / 50;
124da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	else
125da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return ((mV - 1800) / 100) + 16;
126da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
127da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
128da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
129da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
130da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return (val * 25) + 850;
131da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
132da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
133da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
134da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
135da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return (mV - 850) / 25;
136da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
137da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
138da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
139da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int max_uA)
140da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
141da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
142da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int isink = rdev_get_id(rdev);
143da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val, setting;
144da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int ret;
145da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
146da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	ret = get_isink_val(min_uA, max_uA, &setting);
147da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (ret != 0)
148da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return ret;
149da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
150da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (isink) {
151da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_A:
152da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
153da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    ~WM8350_CS1_ISEL_MASK;
154da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_A,
155da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 val | setting);
156da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
157da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_B:
158da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
159da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    ~WM8350_CS1_ISEL_MASK;
160da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_B,
161da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 val | setting);
162da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
163da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
164da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
165da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
166da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
167da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
168da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
169da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
170da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_isink_get_current(struct regulator_dev *rdev)
171da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
172da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
173da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int isink = rdev_get_id(rdev);
174da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
175da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
176da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (isink) {
177da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_A:
178da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
179da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    WM8350_CS1_ISEL_MASK;
180da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
181da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_B:
182da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
183da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    WM8350_CS1_ISEL_MASK;
184da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
185da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
186da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return 0;
187da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
188da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
189fa5a97bb0c65cb8d0382b72a55e2b87e15268289Axel Lin	return isink_cur[val];
190da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
191da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
192da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown/* turn on ISINK followed by DCDC */
193da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_isink_enable(struct regulator_dev *rdev)
194da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
195da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
196da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int isink = rdev_get_id(rdev);
197da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
198da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (isink) {
199da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_A:
200da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		switch (wm8350->pmic.isink_A_dcdc) {
201da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		case WM8350_DCDC_2:
202da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		case WM8350_DCDC_5:
203da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
204da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					WM8350_CS1_ENA);
205da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_set_bits(wm8350, WM8350_CSA_FLASH_CONTROL,
206da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					WM8350_CS1_DRIVE);
207da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
208da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					1 << (wm8350->pmic.isink_A_dcdc -
209da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					      WM8350_DCDC_1));
210da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			break;
211da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		default:
212da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			return -EINVAL;
213da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		}
214da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
215da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_B:
216da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		switch (wm8350->pmic.isink_B_dcdc) {
217da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		case WM8350_DCDC_2:
218da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		case WM8350_DCDC_5:
219da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
220da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					WM8350_CS2_ENA);
221da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_set_bits(wm8350, WM8350_CSB_FLASH_CONTROL,
222da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					WM8350_CS2_DRIVE);
223da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
224da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					1 << (wm8350->pmic.isink_B_dcdc -
225da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					      WM8350_DCDC_1));
226da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			break;
227da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		default:
228da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			return -EINVAL;
229da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		}
230da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
231da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
232da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
233da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
234da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
235da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
236da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
237da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_isink_disable(struct regulator_dev *rdev)
238da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
239da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
240da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int isink = rdev_get_id(rdev);
241da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
242da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (isink) {
243da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_A:
244da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		switch (wm8350->pmic.isink_A_dcdc) {
245da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		case WM8350_DCDC_2:
246da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		case WM8350_DCDC_5:
247da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
248da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					  1 << (wm8350->pmic.isink_A_dcdc -
249da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown						WM8350_DCDC_1));
250da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
251da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					  WM8350_CS1_ENA);
252da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			break;
253da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		default:
254da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			return -EINVAL;
255da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		}
256da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
257da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_B:
258da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		switch (wm8350->pmic.isink_B_dcdc) {
259da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		case WM8350_DCDC_2:
260da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		case WM8350_DCDC_5:
261da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
262da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					  1 << (wm8350->pmic.isink_B_dcdc -
263da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown						WM8350_DCDC_1));
264da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
265da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					  WM8350_CS2_ENA);
266da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			break;
267da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		default:
268da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			return -EINVAL;
269da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		}
270da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
271da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
272da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
273da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
274da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
275da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
276da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
277da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_isink_is_enabled(struct regulator_dev *rdev)
278da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
279da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
280da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int isink = rdev_get_id(rdev);
281da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
282da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (isink) {
283da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_A:
284da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
285da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    0x8000;
286da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_B:
287da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
288da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    0x8000;
289da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
290da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return -EINVAL;
291da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
292da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
29375c8ac22e4b8ebea8169a090e64d034a96758644Mark Brownstatic int wm8350_isink_enable_time(struct regulator_dev *rdev)
29475c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown{
29575c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
29675c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	int isink = rdev_get_id(rdev);
29775c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	int reg;
29875c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown
29975c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	switch (isink) {
30075c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	case WM8350_ISINK_A:
30175c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		reg = wm8350_reg_read(wm8350, WM8350_CSA_FLASH_CONTROL);
30275c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		break;
30375c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	case WM8350_ISINK_B:
30475c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		reg = wm8350_reg_read(wm8350, WM8350_CSB_FLASH_CONTROL);
30575c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		break;
30675c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	default:
30775c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		return -EINVAL;
30875c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	}
30975c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown
31075c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	if (reg & WM8350_CS1_FLASH_MODE) {
31175c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		switch (reg & WM8350_CS1_ON_RAMP_MASK) {
31275c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		case 0:
31375c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown			return 0;
31475c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		case 1:
31575c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown			return 1950;
31675c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		case 2:
31775c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown			return 3910;
31875c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		case 3:
31975c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown			return 7800;
32075c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		}
32175c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	} else {
32275c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		switch (reg & WM8350_CS1_ON_RAMP_MASK) {
32375c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		case 0:
32475c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown			return 0;
32575c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		case 1:
32675c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown			return 250000;
32775c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		case 2:
32875c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown			return 500000;
32975c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		case 3:
33075c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown			return 1000000;
33175c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown		}
33275c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	}
33375c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown
33475c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	return -EINVAL;
33575c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown}
33675c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown
33775c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown
338da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownint wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
339da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			   u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
340da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			   u16 drive)
341da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
342da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (isink) {
343da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_A:
344da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_CSA_FLASH_CONTROL,
345da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (mode ? WM8350_CS1_FLASH_MODE : 0) |
346da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (trigger ? WM8350_CS1_TRIGSRC : 0) |
347da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 duration | on_ramp | off_ramp | drive);
348da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
349da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_ISINK_B:
350da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_CSB_FLASH_CONTROL,
351da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (mode ? WM8350_CS2_FLASH_MODE : 0) |
352da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (trigger ? WM8350_CS2_TRIGSRC : 0) |
353da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 duration | on_ramp | off_ramp | drive);
354da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
355da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
356da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
357da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
358da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
359da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
360da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark BrownEXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
361da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
362da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
3633a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown				   int max_uV, unsigned *selector)
364da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
365da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
366da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int volt_reg, dcdc = rdev_get_id(rdev), mV,
367da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		min_mV = min_uV / 1000, max_mV = max_uV / 1000;
368da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
369da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
370da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (min_mV < 850 || min_mV > 4025)
371da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
372da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (max_mV < 850 || max_mV > 4025)
373da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
374da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
375da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* step size is 25mV */
376da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	mV = (min_mV - 826) / 25;
377da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
378da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
379da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
380da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
381da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
382da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
383da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC1_CONTROL;
384da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
385da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
386da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC3_CONTROL;
387da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
388da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
389da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC4_CONTROL;
390da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
391da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
392da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC6_CONTROL;
393da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
394da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
395da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
396da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
397da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
398da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
399da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
4003a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown	*selector = mV;
4013a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown
402da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* all DCDCs have same mV bits */
403da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
404da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_reg_write(wm8350, volt_reg, val | mV);
405da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
406da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
407da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
408c24516a1d674b1d9d847fd736feca444bc249b12Mark Brownstatic int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev)
409da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
410da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
411da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int volt_reg, dcdc = rdev_get_id(rdev);
412da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
413da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
414da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
415da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC1_CONTROL;
416da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
417da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
418da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC3_CONTROL;
419da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
420da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
421da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC4_CONTROL;
422da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
423da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
424da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC6_CONTROL;
425da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
426da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
427da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
428da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
429da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
430da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
431da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
432da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* all DCDCs have same mV bits */
433c24516a1d674b1d9d847fd736feca444bc249b12Mark Brown	return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
434da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
435da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
436221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brownstatic int wm8350_dcdc_list_voltage(struct regulator_dev *rdev,
437221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown				    unsigned selector)
438221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown{
439221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown	if (selector > WM8350_DCDC_MAX_VSEL)
440221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		return -EINVAL;
441221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown	return wm8350_dcdc_val_to_mvolts(selector) * 1000;
442221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown}
443221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown
444da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
445da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
446da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
447da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
448da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
449da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
450da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
451da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
452da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (mV && (mV < 850 || mV > 4025)) {
453da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		dev_err(wm8350->dev,
454da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			"DCDC%d suspend voltage %d mV out of range\n",
455da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			dcdc, mV);
456da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
457da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
458da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (mV == 0)
459da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mV = 850;
460da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
461da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
462da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
463da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC1_LOW_POWER;
464da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
465da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
466da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC3_LOW_POWER;
467da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
468da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
469da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC4_LOW_POWER;
470da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
471da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
472da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_DCDC6_LOW_POWER;
473da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
474da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
475da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
476da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
477da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
478da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
479da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
480da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* all DCDCs have same mV bits */
481da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
482da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_reg_write(wm8350, volt_reg,
483da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			 val | wm8350_dcdc_mvolts_to_val(mV));
484da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
485da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
486da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
487da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_set_suspend_enable(struct regulator_dev *rdev)
488da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
489da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
490da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
491da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
492da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
493da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
494da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
495da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER)
496da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			& ~WM8350_DCDC_HIB_MODE_MASK;
497da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
498eb4168158f79237498e4d3ddcef6e9436db15a4aAxel Lin			val | wm8350->pmic.dcdc1_hib_mode);
499da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
500da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
501da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER)
502da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			& ~WM8350_DCDC_HIB_MODE_MASK;
503da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
504eb4168158f79237498e4d3ddcef6e9436db15a4aAxel Lin			val | wm8350->pmic.dcdc3_hib_mode);
505da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
506da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
507da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER)
508da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			& ~WM8350_DCDC_HIB_MODE_MASK;
509da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
510eb4168158f79237498e4d3ddcef6e9436db15a4aAxel Lin			val | wm8350->pmic.dcdc4_hib_mode);
511da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
512da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
513da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER)
514da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			& ~WM8350_DCDC_HIB_MODE_MASK;
515da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
516eb4168158f79237498e4d3ddcef6e9436db15a4aAxel Lin			val | wm8350->pmic.dcdc6_hib_mode);
517da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
518da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
519da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
520da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
521da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
522da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
523da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
524da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
525da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
526da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
527da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev)
528da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
529da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
530da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
531da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
532da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
533da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
534da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
535da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
536da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
537da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
538cee1a799eb044657922c4d63003d7bf71f8c8b8dAxel Lin				 val | WM8350_DCDC_HIB_MODE_DIS);
539da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
540da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
541da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
542da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
543da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
544cee1a799eb044657922c4d63003d7bf71f8c8b8dAxel Lin				 val | WM8350_DCDC_HIB_MODE_DIS);
545da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
546da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
547da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
548da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
549da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
550cee1a799eb044657922c4d63003d7bf71f8c8b8dAxel Lin				 val | WM8350_DCDC_HIB_MODE_DIS);
551da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
552da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
553da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
554da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
555da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
556cee1a799eb044657922c4d63003d7bf71f8c8b8dAxel Lin				 val | WM8350_DCDC_HIB_MODE_DIS);
557da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
558da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
559da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
560da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
561da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
562da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
563da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
564da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
565da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
566da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
567da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc25_set_suspend_enable(struct regulator_dev *rdev)
568da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
569da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
570da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
571da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
572da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
573da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
574da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
575da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
576da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    & ~WM8350_DC2_HIB_MODE_MASK;
577da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
5789300928692f835f76f5604b3b51c3085977edf68Axel Lin		    (WM8350_DC2_HIB_MODE_ACTIVE << WM8350_DC2_HIB_MODE_SHIFT));
579da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
580da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
581da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
5829300928692f835f76f5604b3b51c3085977edf68Axel Lin		    & ~WM8350_DC5_HIB_MODE_MASK;
583da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
5849300928692f835f76f5604b3b51c3085977edf68Axel Lin		    (WM8350_DC5_HIB_MODE_ACTIVE << WM8350_DC5_HIB_MODE_SHIFT));
585da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
586da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
587da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
588da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
589da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
590da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
591da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
592da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev)
593da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
594da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
595da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
596da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
597da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
598da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
599da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
600da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
601da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    & ~WM8350_DC2_HIB_MODE_MASK;
602da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
6039300928692f835f76f5604b3b51c3085977edf68Axel Lin		    (WM8350_DC2_HIB_MODE_DISABLE << WM8350_DC2_HIB_MODE_SHIFT));
604da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
605da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
606da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
6079300928692f835f76f5604b3b51c3085977edf68Axel Lin		    & ~WM8350_DC5_HIB_MODE_MASK;
608da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
6099300928692f835f76f5604b3b51c3085977edf68Axel Lin		    (WM8350_DC5_HIB_MODE_DISABLE << WM8350_DC5_HIB_MODE_SHIFT));
610da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
611da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
612da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
613da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
614da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
615da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
616da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
617da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
618da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	unsigned int mode)
619da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
620da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
621da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
622da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 *hib_mode;
623da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
624da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
625da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
626da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		hib_mode = &wm8350->pmic.dcdc1_hib_mode;
627da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
628da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
629da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		hib_mode = &wm8350->pmic.dcdc3_hib_mode;
630da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
631da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
632da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		hib_mode = &wm8350->pmic.dcdc4_hib_mode;
633da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
634da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
635da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		hib_mode = &wm8350->pmic.dcdc6_hib_mode;
636da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
637da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
638da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
639da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
640da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
641da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
642da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
643da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (mode) {
644da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case REGULATOR_MODE_NORMAL:
645da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		*hib_mode = WM8350_DCDC_HIB_MODE_IMAGE;
646da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
647da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case REGULATOR_MODE_IDLE:
648da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		*hib_mode = WM8350_DCDC_HIB_MODE_STANDBY;
649da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
650da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case REGULATOR_MODE_STANDBY:
651da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		*hib_mode = WM8350_DCDC_HIB_MODE_LDO_IM;
652da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
653da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
654da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
655da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
656da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
657da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
658da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
659da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
660da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
661da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
662da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
663da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
664da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
665da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
666da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
667da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
668da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (mV < 900 || mV > 3300) {
669da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
670da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			ldo, mV);
671da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
672da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
673da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
674da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (ldo) {
675da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_1:
676da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO1_LOW_POWER;
677da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
678da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_2:
679da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO2_LOW_POWER;
680da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
681da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_3:
682da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO3_LOW_POWER;
683da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
684da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_4:
685da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO4_LOW_POWER;
686da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
687da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
688da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
689da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
690da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
691da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* all LDOs have same mV bits */
692da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
693da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_reg_write(wm8350, volt_reg,
694da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			 val | wm8350_ldo_mvolts_to_val(mV));
695da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
696da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
697da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
698da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_ldo_set_suspend_enable(struct regulator_dev *rdev)
699da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
700da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
701da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int volt_reg, ldo = rdev_get_id(rdev);
702da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
703da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
704da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (ldo) {
705da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_1:
706da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO1_LOW_POWER;
707da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
708da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_2:
709da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO2_LOW_POWER;
710da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
711da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_3:
712da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO3_LOW_POWER;
713da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
714da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_4:
715da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO4_LOW_POWER;
716da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
717da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
718da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
719da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
720da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
721da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* all LDOs have same mV bits */
722da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
723da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_reg_write(wm8350, volt_reg, val);
724da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
725da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
726da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
727da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
728da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
729da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
730da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int volt_reg, ldo = rdev_get_id(rdev);
731da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
732da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
733da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (ldo) {
734da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_1:
735da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO1_LOW_POWER;
736da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
737da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_2:
738da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO2_LOW_POWER;
739da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
740da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_3:
741da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO3_LOW_POWER;
742da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
743da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_4:
744da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO4_LOW_POWER;
745da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
746da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
747da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
748da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
749da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
750da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* all LDOs have same mV bits */
751da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
752cee1a799eb044657922c4d63003d7bf71f8c8b8dAxel Lin	wm8350_reg_write(wm8350, volt_reg, val | WM8350_LDO1_HIB_MODE_DIS);
753da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
754da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
755da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
756da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
7573a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown				  int max_uV, unsigned *selector)
758da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
759da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
760da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
761da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		max_mV = max_uV / 1000;
762da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
763da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
764da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (min_mV < 900 || min_mV > 3300)
765da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
766da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (max_mV < 900 || max_mV > 3300)
767da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
768da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
769da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (min_mV < 1800) {
770da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		/* step size is 50mV < 1800mV */
771da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mV = (min_mV - 851) / 50;
772da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
773da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			return -EINVAL;
774da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
775da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	} else {
776da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		/* step size is 100mV > 1800mV */
777da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mV = ((min_mV - 1701) / 100) + 16;
778da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
779da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			return -EINVAL;
780da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
781da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
782da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
783da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (ldo) {
784da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_1:
785da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO1_CONTROL;
786da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
787da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_2:
788da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO2_CONTROL;
789da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
790da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_3:
791da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO3_CONTROL;
792da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
793da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_4:
794da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO4_CONTROL;
795da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
796da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
797da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
798da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
799da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
8003a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown	*selector = mV;
8013a93f2a9f4d8f73d74c0e552feb68a10f778a219Mark Brown
802da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* all LDOs have same mV bits */
803da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
804da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_reg_write(wm8350, volt_reg, val | mV);
805da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
806da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
807da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
808c24516a1d674b1d9d847fd736feca444bc249b12Mark Brownstatic int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev)
809da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
810da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
811da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int volt_reg, ldo = rdev_get_id(rdev);
812da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
813da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (ldo) {
814da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_1:
815da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO1_CONTROL;
816da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
817da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_2:
818da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO2_CONTROL;
819da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
820da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_3:
821da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO3_CONTROL;
822da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
823da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_4:
824da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		volt_reg = WM8350_LDO4_CONTROL;
825da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
826da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
827da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
828da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
829da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
830da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* all LDOs have same mV bits */
831c24516a1d674b1d9d847fd736feca444bc249b12Mark Brown	return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
832da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
833da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
834221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brownstatic int wm8350_ldo_list_voltage(struct regulator_dev *rdev,
835221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown				    unsigned selector)
836221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown{
837221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown	if (selector > WM8350_LDO1_VSEL_MASK)
838221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		return -EINVAL;
839221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown	return wm8350_ldo_val_to_mvolts(selector) * 1000;
840221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown}
841221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown
842da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownint wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
843da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			 u16 stop, u16 fault)
844da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
845da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int slot_reg;
846da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
847da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
848da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
849da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		__func__, dcdc, start, stop);
850da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
851da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* slot valid ? */
852da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (start > 15 || stop > 15)
853da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
854da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
855da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
856da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
857da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_DCDC1_TIMEOUTS;
858da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
859da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
860da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_DCDC2_TIMEOUTS;
861da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
862da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
863da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_DCDC3_TIMEOUTS;
864da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
865da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
866da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_DCDC4_TIMEOUTS;
867da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
868da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
869da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_DCDC5_TIMEOUTS;
870da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
871da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
872da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_DCDC6_TIMEOUTS;
873da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
874da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
875da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
876da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
877da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
878da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = wm8350_reg_read(wm8350, slot_reg) &
879da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	    ~(WM8350_DC1_ENSLOT_MASK | WM8350_DC1_SDSLOT_MASK |
880da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	      WM8350_DC1_ERRACT_MASK);
881da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_reg_write(wm8350, slot_reg,
882da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			 val | (start << WM8350_DC1_ENSLOT_SHIFT) |
883da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			 (stop << WM8350_DC1_SDSLOT_SHIFT) |
884da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			 (fault << WM8350_DC1_ERRACT_SHIFT));
885da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
886da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
887da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
888da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark BrownEXPORT_SYMBOL_GPL(wm8350_dcdc_set_slot);
889da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
890da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownint wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop)
891da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
892da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int slot_reg;
893da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
894da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
895da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
896da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		__func__, ldo, start, stop);
897da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
898da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* slot valid ? */
899da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (start > 15 || stop > 15)
900da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
901da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
902da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (ldo) {
903da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_1:
904da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_LDO1_TIMEOUTS;
905da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
906da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_2:
907da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_LDO2_TIMEOUTS;
908da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
909da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_3:
910da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_LDO3_TIMEOUTS;
911da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
912da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_LDO_4:
913da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		slot_reg = WM8350_LDO4_TIMEOUTS;
914da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
915da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
916da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
917da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
918da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
919da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = wm8350_reg_read(wm8350, slot_reg) & ~WM8350_LDO1_SDSLOT_MASK;
920da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_reg_write(wm8350, slot_reg, val | ((start << 10) | (stop << 6)));
921da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
922da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
923da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark BrownEXPORT_SYMBOL_GPL(wm8350_ldo_set_slot);
924da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
925da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownint wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
926da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			   u16 ilim, u16 ramp, u16 feedback)
927da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
928da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
929da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
930da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	dev_dbg(wm8350->dev, "%s %d mode: %s %s\n", __func__, dcdc,
931da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mode ? "normal" : "boost", ilim ? "low" : "normal");
932da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
933da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
934da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_2:
935da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
936da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    & ~(WM8350_DC2_MODE_MASK | WM8350_DC2_ILIM_MASK |
937da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			WM8350_DC2_RMP_MASK | WM8350_DC2_FBSRC_MASK);
938da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
939da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (mode << WM8350_DC2_MODE_SHIFT) |
940da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (ilim << WM8350_DC2_ILIM_SHIFT) |
941da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (ramp << WM8350_DC2_RMP_SHIFT) |
942da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (feedback << WM8350_DC2_FBSRC_SHIFT));
943da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
944da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_5:
945da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
946da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		    & ~(WM8350_DC5_MODE_MASK | WM8350_DC5_ILIM_MASK |
947da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			WM8350_DC5_RMP_MASK | WM8350_DC5_FBSRC_MASK);
948da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
949da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (mode << WM8350_DC5_MODE_SHIFT) |
950da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (ilim << WM8350_DC5_ILIM_SHIFT) |
951da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (ramp << WM8350_DC5_RMP_SHIFT) |
952da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown				 (feedback << WM8350_DC5_FBSRC_SHIFT));
953da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
954da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
955da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
956da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
957da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
958da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
959da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
960da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark BrownEXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
961da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
962da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_enable(struct regulator_dev *rdev)
963da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
964da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
965da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
966da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 shift;
967da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
968da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
969da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
970da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
971da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	shift = dcdc - WM8350_DCDC_1;
972da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
973da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
974da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
975da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
976da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_disable(struct regulator_dev *rdev)
977da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
978da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
979da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
980da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 shift;
981da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
982da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
983da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
984da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
985da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	shift = dcdc - WM8350_DCDC_1;
986da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
987da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
988da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
989da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
990da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
991da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_ldo_enable(struct regulator_dev *rdev)
992da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
993da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
994da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int ldo = rdev_get_id(rdev);
995da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 shift;
996da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
997da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
998da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
999da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1000da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	shift = (ldo - WM8350_LDO_1) + 8;
1001da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
1002da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
1003da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1004da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1005da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_ldo_disable(struct regulator_dev *rdev)
1006da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1007da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
1008da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int ldo = rdev_get_id(rdev);
1009da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 shift;
1010da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1011da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
1012da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
1013da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1014da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	shift = (ldo - WM8350_LDO_1) + 8;
1015da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
1016da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
1017da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1018da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1019da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
1020da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1021da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int reg = 0, ret;
1022da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1023da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
1024da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
1025da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		reg = WM8350_DCDC1_FORCE_PWM;
1026da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1027da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
1028da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		reg = WM8350_DCDC3_FORCE_PWM;
1029da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1030da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
1031da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		reg = WM8350_DCDC4_FORCE_PWM;
1032da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1033da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
1034da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		reg = WM8350_DCDC6_FORCE_PWM;
1035da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1036da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
1037da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
1038da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
1039da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1040da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (enable)
1041da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		ret = wm8350_set_bits(wm8350, reg,
1042da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			WM8350_DCDC1_FORCE_PWM_ENA);
1043da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	else
1044da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		ret = wm8350_clear_bits(wm8350, reg,
1045da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			WM8350_DCDC1_FORCE_PWM_ENA);
1046da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return ret;
1047da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1048da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1049da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
1050da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1051da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
1052da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
1053da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
1054da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1055da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
1056da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
1057da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1058da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
1059da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
1060da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1061da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	val = 1 << (dcdc - WM8350_DCDC_1);
1062da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1063da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (mode) {
1064da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case REGULATOR_MODE_FAST:
1065da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		/* force continuous mode */
1066da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
1067da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
1068da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		force_continuous_enable(wm8350, dcdc, 1);
1069da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1070da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case REGULATOR_MODE_NORMAL:
1071da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		/* active / pulse skipping */
1072da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
1073da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
1074da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		force_continuous_enable(wm8350, dcdc, 0);
1075da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1076da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case REGULATOR_MODE_IDLE:
1077da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		/* standby mode */
1078da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		force_continuous_enable(wm8350, dcdc, 0);
1079da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
1080da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
1081da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1082da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case REGULATOR_MODE_STANDBY:
1083da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		/* LDO mode */
1084da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		force_continuous_enable(wm8350, dcdc, 0);
1085da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
1086da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1087da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
1088da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1089da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
1090da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1091da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1092da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
1093da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1094da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
1095da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev);
1096da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 mask, sleep, active, force;
1097da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int mode = REGULATOR_MODE_NORMAL;
109833f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	int reg;
1099da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
110033f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	switch (dcdc) {
110133f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	case WM8350_DCDC_1:
110233f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown		reg = WM8350_DCDC1_FORCE_PWM;
110333f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown		break;
110433f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	case WM8350_DCDC_3:
110533f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown		reg = WM8350_DCDC3_FORCE_PWM;
110633f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown		break;
110733f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	case WM8350_DCDC_4:
110833f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown		reg = WM8350_DCDC4_FORCE_PWM;
110933f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown		break;
111033f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	case WM8350_DCDC_6:
111133f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown		reg = WM8350_DCDC6_FORCE_PWM;
111233f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown		break;
111333f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	default:
1114da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
111533f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	}
1116da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1117da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	mask = 1 << (dcdc - WM8350_DCDC_1);
1118da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
111933f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown	force = wm8350_reg_read(wm8350, reg) & WM8350_DCDC1_FORCE_PWM_ENA;
1120da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
112133f301af0c56971e3c0f4a4eb4b92f7e80230f49Mark Brown
1122da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
1123da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mask, active, sleep, force);
1124da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1125da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (active && !sleep) {
1126da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		if (force)
1127da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			mode = REGULATOR_MODE_FAST;
1128da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		else
1129da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			mode = REGULATOR_MODE_NORMAL;
1130da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	} else if (!active && !sleep)
1131da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mode = REGULATOR_MODE_IDLE;
11328ecee36adc9d2cf19471c395af6ef70264dec251Axel Lin	else if (sleep)
1133da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mode = REGULATOR_MODE_STANDBY;
1134da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1135da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return mode;
1136da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1137da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1138da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic unsigned int wm8350_ldo_get_mode(struct regulator_dev *rdev)
1139da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1140da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return REGULATOR_MODE_NORMAL;
1141da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1142da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1143da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstruct wm8350_dcdc_efficiency {
1144da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int uA_load_min;
1145da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int uA_load_max;
1146da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	unsigned int mode;
1147da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1148da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1149da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic const struct wm8350_dcdc_efficiency dcdc1_6_efficiency[] = {
1150da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{0, 10000, REGULATOR_MODE_STANDBY},       /* 0 - 10mA - LDO */
1151da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{10000, 100000, REGULATOR_MODE_IDLE},     /* 10mA - 100mA - Standby */
1152da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{100000, 1000000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
1153da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{-1, -1, REGULATOR_MODE_NORMAL},
1154da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1155da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1156da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic const struct wm8350_dcdc_efficiency dcdc3_4_efficiency[] = {
1157da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{0, 10000, REGULATOR_MODE_STANDBY},      /* 0 - 10mA - LDO */
1158da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{10000, 100000, REGULATOR_MODE_IDLE},    /* 10mA - 100mA - Standby */
1159da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{100000, 800000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
1160da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{-1, -1, REGULATOR_MODE_NORMAL},
1161da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1162da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1163da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic unsigned int get_mode(int uA, const struct wm8350_dcdc_efficiency *eff)
1164da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1165da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int i = 0;
1166da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1167da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	while (eff[i].uA_load_min != -1) {
1168da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		if (uA >= eff[i].uA_load_min && uA <= eff[i].uA_load_max)
1169da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			return eff[i].mode;
1170da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
1171da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return REGULATOR_MODE_NORMAL;
1172da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1173da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1174da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown/* Query the regulator for it's most efficient mode @ uV,uA
1175da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown * WM8350 regulator efficiency is pretty similar over
1176da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown * different input and output uV.
1177da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown */
1178da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
1179da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown						 int input_uV, int output_uV,
1180da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown						 int output_uA)
1181da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1182da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev), mode;
1183da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1184da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (dcdc) {
1185da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
1186da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
1187da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mode = get_mode(output_uA, dcdc1_6_efficiency);
1188da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1189da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
1190da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
1191da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mode = get_mode(output_uA, dcdc3_4_efficiency);
1192da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1193da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	default:
1194da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		mode = REGULATOR_MODE_NORMAL;
1195da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1196da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
1197da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return mode;
1198da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1199da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1200da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
1201da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1202da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
1203da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int dcdc = rdev_get_id(rdev), shift;
1204da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1205da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
1206da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
1207da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1208da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	shift = dcdc - WM8350_DCDC_1;
1209da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
1210da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	    & (1 << shift);
1211da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1212da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1213da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
1214da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1215da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
1216da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int ldo = rdev_get_id(rdev), shift;
1217da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1218da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
1219da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EINVAL;
1220da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1221da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	shift = (ldo - WM8350_LDO_1) + 8;
1222da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
1223da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	    & (1 << shift);
1224da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1225da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1226da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic struct regulator_ops wm8350_dcdc_ops = {
1227da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_voltage = wm8350_dcdc_set_voltage,
1228c24516a1d674b1d9d847fd736feca444bc249b12Mark Brown	.get_voltage_sel = wm8350_dcdc_get_voltage_sel,
1229221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown	.list_voltage = wm8350_dcdc_list_voltage,
1230da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.enable = wm8350_dcdc_enable,
1231da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.disable = wm8350_dcdc_disable,
1232da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.get_mode = wm8350_dcdc_get_mode,
1233da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_mode = wm8350_dcdc_set_mode,
1234da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.get_optimum_mode = wm8350_dcdc_get_optimum_mode,
1235da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.is_enabled = wm8350_dcdc_is_enabled,
1236da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
1237da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_enable = wm8350_dcdc_set_suspend_enable,
1238da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_disable = wm8350_dcdc_set_suspend_disable,
1239da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_mode = wm8350_dcdc_set_suspend_mode,
1240da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1241da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1242da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic struct regulator_ops wm8350_dcdc2_5_ops = {
1243da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.enable = wm8350_dcdc_enable,
1244da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.disable = wm8350_dcdc_disable,
1245da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.is_enabled = wm8350_dcdc_is_enabled,
1246da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
1247da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
1248da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1249da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1250da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic struct regulator_ops wm8350_ldo_ops = {
1251da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_voltage = wm8350_ldo_set_voltage,
1252c24516a1d674b1d9d847fd736feca444bc249b12Mark Brown	.get_voltage_sel = wm8350_ldo_get_voltage_sel,
1253221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown	.list_voltage = wm8350_ldo_list_voltage,
1254da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.enable = wm8350_ldo_enable,
1255da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.disable = wm8350_ldo_disable,
1256da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.is_enabled = wm8350_ldo_is_enabled,
1257da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.get_mode = wm8350_ldo_get_mode,
1258da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
1259da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_enable = wm8350_ldo_set_suspend_enable,
1260da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_suspend_disable = wm8350_ldo_set_suspend_disable,
1261da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1262da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1263da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic struct regulator_ops wm8350_isink_ops = {
1264da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.set_current_limit = wm8350_isink_set_current,
1265da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.get_current_limit = wm8350_isink_get_current,
1266da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.enable = wm8350_isink_enable,
1267da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.disable = wm8350_isink_disable,
1268da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.is_enabled = wm8350_isink_is_enabled,
126975c8ac22e4b8ebea8169a090e64d034a96758644Mark Brown	.enable_time = wm8350_isink_enable_time,
1270da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1271da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1272da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
1273da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1274da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "DCDC1",
1275da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_DCDC_1,
1276da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_dcdc_ops,
1277da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_DC1,
1278da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1279221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
1280da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1281da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1282da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1283da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "DCDC2",
1284da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_DCDC_2,
1285da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_dcdc2_5_ops,
1286da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_DC2,
1287da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1288da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1289da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1290da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1291da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "DCDC3",
1292da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_DCDC_3,
1293da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_dcdc_ops,
1294da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_DC3,
1295da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1296221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
1297da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1298da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1299da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1300da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "DCDC4",
1301da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_DCDC_4,
1302da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_dcdc_ops,
1303da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_DC4,
1304da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1305221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
1306da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1307da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1308da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1309da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "DCDC5",
1310da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_DCDC_5,
1311da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_dcdc2_5_ops,
1312da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_DC5,
1313da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1314da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1315da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	 },
1316da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1317da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "DCDC6",
1318da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_DCDC_6,
1319da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_dcdc_ops,
1320da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_DC6,
1321da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1322221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		.n_voltages = WM8350_DCDC_MAX_VSEL + 1,
1323da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1324da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1325da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1326da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "LDO1",
1327da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_LDO_1,
1328da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_ldo_ops,
1329da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_LDO1,
1330da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1331221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		.n_voltages = WM8350_LDO1_VSEL_MASK + 1,
1332da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1333da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1334da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1335da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "LDO2",
1336da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_LDO_2,
1337da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_ldo_ops,
1338da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_LDO2,
1339da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1340221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		.n_voltages = WM8350_LDO2_VSEL_MASK + 1,
1341da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1342da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1343da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1344da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "LDO3",
1345da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_LDO_3,
1346da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_ldo_ops,
1347da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_LDO3,
1348da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1349221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		.n_voltages = WM8350_LDO3_VSEL_MASK + 1,
1350da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1351da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1352da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1353da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "LDO4",
1354da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_LDO_4,
1355da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_ldo_ops,
1356da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_UV_LDO4,
1357da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_VOLTAGE,
1358221a7c7c9c88bf9d3ea4e191b35c7da709ca30b7Mark Brown		.n_voltages = WM8350_LDO4_VSEL_MASK + 1,
1359da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1360da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1361da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1362da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "ISINKA",
1363da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_ISINK_A,
1364da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_isink_ops,
1365da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_CS1,
1366da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_CURRENT,
1367da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1368da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	 },
1369da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	{
1370da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name = "ISINKB",
1371da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.id = WM8350_ISINK_B,
1372da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.ops = &wm8350_isink_ops,
1373da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.irq = WM8350_IRQ_CS2,
1374da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.type = REGULATOR_CURRENT,
1375da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.owner = THIS_MODULE,
1376da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	 },
1377da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1378da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
13795a65edbc12b6b34ef912114f1fc8215786f85b25Mark Brownstatic irqreturn_t pmic_uv_handler(int irq, void *data)
1380da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1381da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct regulator_dev *rdev = (struct regulator_dev *)data;
13825a65edbc12b6b34ef912114f1fc8215786f85b25Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
1383da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1384b136fb4463d13eea129bf090a8a465bba6bf0003Jonathan Cameron	mutex_lock(&rdev->mutex);
1385da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
1386da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		regulator_notifier_call_chain(rdev,
1387da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					      REGULATOR_EVENT_REGULATION_OUT,
1388da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					      wm8350);
1389da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	else
1390da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		regulator_notifier_call_chain(rdev,
1391da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					      REGULATOR_EVENT_UNDER_VOLTAGE,
1392da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown					      wm8350);
1393b136fb4463d13eea129bf090a8a465bba6bf0003Jonathan Cameron	mutex_unlock(&rdev->mutex);
13945a65edbc12b6b34ef912114f1fc8215786f85b25Mark Brown
13955a65edbc12b6b34ef912114f1fc8215786f85b25Mark Brown	return IRQ_HANDLED;
1396da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1397da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1398da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_regulator_probe(struct platform_device *pdev)
1399da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1400da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
1401da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct regulator_dev *rdev;
1402da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int ret;
1403da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	u16 val;
1404da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1405da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (pdev->id < WM8350_DCDC_1 || pdev->id > WM8350_ISINK_B)
1406da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -ENODEV;
1407da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1408da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* do any regulatior specific init */
1409da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	switch (pdev->id) {
1410da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_1:
1411da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
1412da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
1413da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1414da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_3:
1415da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
1416da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
1417da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1418da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_4:
1419da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
1420da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
1421da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1422da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	case WM8350_DCDC_6:
1423da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
1424da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
1425da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		break;
1426da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
1427da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1428da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* register regulator */
1429da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
14300527100fd11d9710c7e153d791da78824b7b46faMark Brown				  pdev->dev.platform_data,
14312c043bcbf287dc69848054d5c02c55c20f7a7bc5Rajendra Nayak				  dev_get_drvdata(&pdev->dev), NULL);
1432da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (IS_ERR(rdev)) {
1433da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		dev_err(&pdev->dev, "failed to register %s\n",
1434da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_reg[pdev->id].name);
1435da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return PTR_ERR(rdev);
1436da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
1437da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1438da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	/* register regulator IRQ */
1439da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
14405a65edbc12b6b34ef912114f1fc8215786f85b25Mark Brown				  pmic_uv_handler, 0, "UV", rdev);
1441da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (ret < 0) {
1442da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		regulator_unregister(rdev);
1443da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
1444da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			wm8350_reg[pdev->id].name);
1445da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return ret;
1446da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
1447da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1448da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
1449da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1450da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1451da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int wm8350_regulator_remove(struct platform_device *pdev)
1452da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1453da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct regulator_dev *rdev = platform_get_drvdata(pdev);
1454da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
1455da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1456f99344fc69c3df46786a39ea4283a4175ea40b3fMark Brown	wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev);
1457da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1458da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	regulator_unregister(rdev);
1459da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1460da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return 0;
1461da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1462da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1463da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownint wm8350_register_regulator(struct wm8350 *wm8350, int reg,
1464da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			      struct regulator_init_data *initdata)
1465da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1466da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	struct platform_device *pdev;
1467da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	int ret;
14684dee4d441d3f90cd8cec10a9eb222d8a4f2fa2a3Roel Kluin	if (reg < 0 || reg >= NUM_WM8350_REGULATORS)
14694dee4d441d3f90cd8cec10a9eb222d8a4f2fa2a3Roel Kluin		return -EINVAL;
1470da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1471da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (wm8350->pmic.pdev[reg])
1472da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -EBUSY;
1473da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1474645524a9c6e1e42dc4fe03217befb20e2fc4d43eMark Brown	if (reg >= WM8350_DCDC_1 && reg <= WM8350_DCDC_6 &&
1475645524a9c6e1e42dc4fe03217befb20e2fc4d43eMark Brown	    reg > wm8350->pmic.max_dcdc)
1476645524a9c6e1e42dc4fe03217befb20e2fc4d43eMark Brown		return -ENODEV;
1477645524a9c6e1e42dc4fe03217befb20e2fc4d43eMark Brown	if (reg >= WM8350_ISINK_A && reg <= WM8350_ISINK_B &&
1478645524a9c6e1e42dc4fe03217befb20e2fc4d43eMark Brown	    reg > wm8350->pmic.max_isink)
1479645524a9c6e1e42dc4fe03217befb20e2fc4d43eMark Brown		return -ENODEV;
1480645524a9c6e1e42dc4fe03217befb20e2fc4d43eMark Brown
1481da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	pdev = platform_device_alloc("wm8350-regulator", reg);
1482da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (!pdev)
1483da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		return -ENOMEM;
1484da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1485da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	wm8350->pmic.pdev[reg] = pdev;
1486da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1487da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	initdata->driver_data = wm8350;
1488da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1489da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	pdev->dev.platform_data = initdata;
1490da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	pdev->dev.parent = wm8350->dev;
1491da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	platform_set_drvdata(pdev, wm8350);
1492da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1493da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	ret = platform_device_add(pdev);
1494da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1495da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	if (ret != 0) {
1496da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		dev_err(wm8350->dev, "Failed to register regulator %d: %d\n",
1497da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown			reg, ret);
1498e9a1c5129de1caf4526b8df5f200ff628b2ffab4Axel Lin		platform_device_put(pdev);
1499da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		wm8350->pmic.pdev[reg] = NULL;
1500da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	}
1501da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1502da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return ret;
1503da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1504da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark BrownEXPORT_SYMBOL_GPL(wm8350_register_regulator);
1505da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
15060081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown/**
15070081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * wm8350_register_led - Register a WM8350 LED output
15080081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown *
15090081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * @param wm8350 The WM8350 device to configure.
15100081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * @param lednum LED device index to create.
15110081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * @param dcdc The DCDC to use for the LED.
15120081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * @param isink The ISINK to use for the LED.
15130081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * @param pdata Configuration for the LED.
15140081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown *
15150081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * The WM8350 supports the use of an ISINK together with a DCDC to
15160081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * provide a power-efficient LED driver.  This function registers the
15170081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * regulators and instantiates the platform device for a LED.  The
15180081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * operating modes for the LED regulators must be configured using
15190081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * wm8350_isink_set_flash(), wm8350_dcdc25_set_mode() and
15200081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown * wm8350_dcdc_set_slot() prior to calling this function.
15210081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown */
15220081e8020ebd814a99e45720a10e869a54ee08a6Mark Brownint wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink,
15230081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown			struct wm8350_led_platform_data *pdata)
15240081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown{
15250081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	struct wm8350_led *led;
15260081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	struct platform_device *pdev;
15270081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	int ret;
15280081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
15298dd2c9e3128a5784a01084b52d5bb7efd4371ac6Roel Kluin	if (lednum >= ARRAY_SIZE(wm8350->pmic.led) || lednum < 0) {
15300081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		dev_err(wm8350->dev, "Invalid LED index %d\n", lednum);
15310081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		return -ENODEV;
15320081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	}
15330081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
15340081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led = &wm8350->pmic.led[lednum];
15350081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
15360081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	if (led->pdev) {
15370081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		dev_err(wm8350->dev, "LED %d already allocated\n", lednum);
15380081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		return -EINVAL;
15390081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	}
15400081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
15410081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	pdev = platform_device_alloc("wm8350-led", lednum);
15420081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	if (pdev == NULL) {
15430081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		dev_err(wm8350->dev, "Failed to allocate LED %d\n", lednum);
15440081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		return -ENOMEM;
15450081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	}
15460081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
154734ce8d07e63baa37d21aeca87f3248b008114899Mark Brown	led->isink_consumer.dev_name = dev_name(&pdev->dev);
15480081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->isink_consumer.supply = "led_isink";
15490081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->isink_init.num_consumer_supplies = 1;
15500081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->isink_init.consumer_supplies = &led->isink_consumer;
15510081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->isink_init.constraints.min_uA = 0;
15520081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->isink_init.constraints.max_uA = pdata->max_uA;
1553a2fad9bf26a1d44a8d31a5c4528108a2b9f468abMark Brown	led->isink_init.constraints.valid_ops_mask
1554a2fad9bf26a1d44a8d31a5c4528108a2b9f468abMark Brown		= REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS;
15550081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->isink_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
15560081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	ret = wm8350_register_regulator(wm8350, isink, &led->isink_init);
15570081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	if (ret != 0) {
15580081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		platform_device_put(pdev);
15590081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		return ret;
15600081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	}
15610081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
156234ce8d07e63baa37d21aeca87f3248b008114899Mark Brown	led->dcdc_consumer.dev_name = dev_name(&pdev->dev);
15630081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->dcdc_consumer.supply = "led_vcc";
15640081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->dcdc_init.num_consumer_supplies = 1;
15650081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->dcdc_init.consumer_supplies = &led->dcdc_consumer;
15660081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->dcdc_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
1567a2fad9bf26a1d44a8d31a5c4528108a2b9f468abMark Brown	led->dcdc_init.constraints.valid_ops_mask =  REGULATOR_CHANGE_STATUS;
15680081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	ret = wm8350_register_regulator(wm8350, dcdc, &led->dcdc_init);
15690081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	if (ret != 0) {
15700081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		platform_device_put(pdev);
15710081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		return ret;
15720081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	}
15730081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
15740081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	switch (isink) {
15750081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	case WM8350_ISINK_A:
15760081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		wm8350->pmic.isink_A_dcdc = dcdc;
15770081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		break;
15780081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	case WM8350_ISINK_B:
15790081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		wm8350->pmic.isink_B_dcdc = dcdc;
15800081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		break;
15810081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	}
15820081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
15830081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	pdev->dev.platform_data = pdata;
15840081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	pdev->dev.parent = wm8350->dev;
15850081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	ret = platform_device_add(pdev);
15860081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	if (ret != 0) {
15870081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		dev_err(wm8350->dev, "Failed to register LED %d: %d\n",
15880081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown			lednum, ret);
15890081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		platform_device_put(pdev);
15900081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown		return ret;
15910081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	}
15920081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
15930081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	led->pdev = pdev;
15940081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
15950081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown	return 0;
15960081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown}
15970081e8020ebd814a99e45720a10e869a54ee08a6Mark BrownEXPORT_SYMBOL_GPL(wm8350_register_led);
15980081e8020ebd814a99e45720a10e869a54ee08a6Mark Brown
1599da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic struct platform_driver wm8350_regulator_driver = {
1600da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.probe = wm8350_regulator_probe,
1601da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.remove = wm8350_regulator_remove,
1602da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	.driver		= {
1603da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown		.name	= "wm8350-regulator",
1604da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	},
1605da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown};
1606da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1607da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic int __init wm8350_regulator_init(void)
1608da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1609da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	return platform_driver_register(&wm8350_regulator_driver);
1610da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1611da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownsubsys_initcall(wm8350_regulator_init);
1612da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1613da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownstatic void __exit wm8350_regulator_exit(void)
1614da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown{
1615da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown	platform_driver_unregister(&wm8350_regulator_driver);
1616da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown}
1617da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brownmodule_exit(wm8350_regulator_exit);
1618da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown
1619da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark Brown/* Module information */
1620da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark BrownMODULE_AUTHOR("Liam Girdwood");
1621da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark BrownMODULE_DESCRIPTION("WM8350 voltage and current regulator driver");
1622da09155ac8d3f04c299b3d82a6ab0df8d03da632Mark BrownMODULE_LICENSE("GPL");
162338c53c89139e6140b895b419b18c586e8593a6e8Mark BrownMODULE_ALIAS("platform:wm8350-regulator");
1624