Blame view

drivers/regulator/tps65086-regulator.c 7.97 KB
d2a2e729a   Andrew F. Davis   regulator: tps650...
1
  /*
2ca76b3e4   Alexander A. Klimov   regulator: Replac...
2
   * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
d2a2e729a   Andrew F. Davis   regulator: tps650...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   *
   * Author: Andrew F. Davis <afd@ti.com>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   * This program is distributed "as is" WITHOUT ANY WARRANTY of any
   * kind, whether expressed or implied; without even the implied warranty
   * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License version 2 for more details.
   *
   * Based on the TPS65912 driver
   */
  
  #include <linux/module.h>
7f9354f26   Andrew F. Davis   regulator: tps650...
19
  #include <linux/of.h>
d2a2e729a   Andrew F. Davis   regulator: tps650...
20
21
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
d2a2e729a   Andrew F. Davis   regulator: tps650...
22
23
24
25
26
27
28
29
30
31
32
  
  #include <linux/mfd/tps65086.h>
  
  enum tps65086_regulators { BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, LDOA1,
  	LDOA2, LDOA3, SWA1, SWB1, SWB2, VTT };
  
  #define TPS65086_REGULATOR(_name, _of, _id, _nv, _vr, _vm, _er, _em, _lr, _dr, _dm)	\
  	[_id] = {							\
  		.desc = {						\
  			.name			= _name,		\
  			.of_match		= of_match_ptr(_of),	\
7f9354f26   Andrew F. Davis   regulator: tps650...
33
  			.regulators_node	= "regulators",		\
d2a2e729a   Andrew F. Davis   regulator: tps650...
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  			.of_parse_cb		= tps65086_of_parse_cb,	\
  			.id			= _id,			\
  			.ops			= &reg_ops,		\
  			.n_voltages		= _nv,			\
  			.type			= REGULATOR_VOLTAGE,	\
  			.owner			= THIS_MODULE,		\
  			.vsel_reg		= _vr,			\
  			.vsel_mask		= _vm,			\
  			.enable_reg		= _er,			\
  			.enable_mask		= _em,			\
  			.volt_table		= NULL,			\
  			.linear_ranges		= _lr,			\
  			.n_linear_ranges	= ARRAY_SIZE(_lr),	\
  		},							\
  		.decay_reg = _dr,					\
  		.decay_mask = _dm,					\
  	}
  
  #define TPS65086_SWITCH(_name, _of, _id, _er, _em)			\
  	[_id] = {							\
  		.desc = {						\
  			.name			= _name,		\
  			.of_match		= of_match_ptr(_of),	\
7f9354f26   Andrew F. Davis   regulator: tps650...
57
  			.regulators_node	= "regulators",		\
d2a2e729a   Andrew F. Davis   regulator: tps650...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  			.of_parse_cb		= tps65086_of_parse_cb,	\
  			.id			= _id,			\
  			.ops			= &switch_ops,		\
  			.type			= REGULATOR_VOLTAGE,	\
  			.owner			= THIS_MODULE,		\
  			.enable_reg		= _er,			\
  			.enable_mask		= _em,			\
  		},							\
  	}
  
  struct tps65086_regulator {
  	struct regulator_desc desc;
  	unsigned int decay_reg;
  	unsigned int decay_mask;
  };
60ab7f415   Matti Vaittinen   regulator: use li...
73
  static const struct linear_range tps65086_10mv_ranges[] = {
d2a2e729a   Andrew F. Davis   regulator: tps650...
74
75
76
  	REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
  	REGULATOR_LINEAR_RANGE(410000, 0x1, 0x7F, 10000),
  };
60ab7f415   Matti Vaittinen   regulator: use li...
77
  static const struct linear_range tps65086_buck126_25mv_ranges[] = {
f8192880a   Andrew F. Davis   regulator: tps650...
78
79
  	REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
  	REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x18, 0),
d2a2e729a   Andrew F. Davis   regulator: tps650...
80
81
  	REGULATOR_LINEAR_RANGE(1025000, 0x19, 0x7F, 25000),
  };
60ab7f415   Matti Vaittinen   regulator: use li...
82
  static const struct linear_range tps65086_buck345_25mv_ranges[] = {
d2a2e729a   Andrew F. Davis   regulator: tps650...
83
84
85
  	REGULATOR_LINEAR_RANGE(0, 0x0, 0x0, 0),
  	REGULATOR_LINEAR_RANGE(425000, 0x1, 0x7F, 25000),
  };
60ab7f415   Matti Vaittinen   regulator: use li...
86
  static const struct linear_range tps65086_ldoa1_ranges[] = {
d2a2e729a   Andrew F. Davis   regulator: tps650...
87
88
  	REGULATOR_LINEAR_RANGE(1350000, 0x0, 0x0, 0),
  	REGULATOR_LINEAR_RANGE(1500000, 0x1, 0x7, 100000),
e69b39470   Axel Lin   regulator: tps650...
89
90
  	REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xB, 100000),
  	REGULATOR_LINEAR_RANGE(2850000, 0xC, 0xD, 150000),
d2a2e729a   Andrew F. Davis   regulator: tps650...
91
92
  	REGULATOR_LINEAR_RANGE(3300000, 0xE, 0xE, 0),
  };
60ab7f415   Matti Vaittinen   regulator: use li...
93
  static const struct linear_range tps65086_ldoa23_ranges[] = {
d2a2e729a   Andrew F. Davis   regulator: tps650...
94
95
96
97
98
  	REGULATOR_LINEAR_RANGE(700000, 0x0, 0xD, 50000),
  	REGULATOR_LINEAR_RANGE(1400000, 0xE, 0xF, 100000),
  };
  
  /* Operations permitted on regulators */
2e6d9db83   Rikard Falkeborn   regulator: tps650...
99
  static const struct regulator_ops reg_ops = {
d2a2e729a   Andrew F. Davis   regulator: tps650...
100
101
102
103
104
105
106
107
108
109
  	.enable			= regulator_enable_regmap,
  	.disable		= regulator_disable_regmap,
  	.is_enabled		= regulator_is_enabled_regmap,
  	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
  	.map_voltage		= regulator_map_voltage_linear_range,
  	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
  	.list_voltage		= regulator_list_voltage_linear_range,
  };
  
  /* Operations permitted on load switches */
2e6d9db83   Rikard Falkeborn   regulator: tps650...
110
  static const struct regulator_ops switch_ops = {
d2a2e729a   Andrew F. Davis   regulator: tps650...
111
112
113
114
115
116
117
118
119
120
121
122
  	.enable			= regulator_enable_regmap,
  	.disable		= regulator_disable_regmap,
  	.is_enabled		= regulator_is_enabled_regmap,
  };
  
  static int tps65086_of_parse_cb(struct device_node *dev,
  				const struct regulator_desc *desc,
  				struct regulator_config *config);
  
  static struct tps65086_regulator regulators[] = {
  	TPS65086_REGULATOR("BUCK1", "buck1", BUCK1, 0x80, TPS65086_BUCK1CTRL,
  			   BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(0),
d8ca5bd15   Andrew F. Davis   regulator: tps650...
123
  			   tps65086_10mv_ranges, TPS65086_BUCK1CTRL,
d2a2e729a   Andrew F. Davis   regulator: tps650...
124
125
126
  			   BIT(0)),
  	TPS65086_REGULATOR("BUCK2", "buck2", BUCK2, 0x80, TPS65086_BUCK2CTRL,
  			   BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(1),
d8ca5bd15   Andrew F. Davis   regulator: tps650...
127
  			   tps65086_10mv_ranges, TPS65086_BUCK2CTRL,
d2a2e729a   Andrew F. Davis   regulator: tps650...
128
129
130
  			   BIT(0)),
  	TPS65086_REGULATOR("BUCK3", "buck3", BUCK3, 0x80, TPS65086_BUCK3VID,
  			   BUCK_VID_MASK, TPS65086_BUCK123CTRL, BIT(2),
d8ca5bd15   Andrew F. Davis   regulator: tps650...
131
  			   tps65086_10mv_ranges, TPS65086_BUCK3DECAY,
d2a2e729a   Andrew F. Davis   regulator: tps650...
132
133
134
  			   BIT(0)),
  	TPS65086_REGULATOR("BUCK4", "buck4", BUCK4, 0x80, TPS65086_BUCK4VID,
  			   BUCK_VID_MASK, TPS65086_BUCK4CTRL, BIT(0),
d8ca5bd15   Andrew F. Davis   regulator: tps650...
135
  			   tps65086_10mv_ranges, TPS65086_BUCK4VID,
d2a2e729a   Andrew F. Davis   regulator: tps650...
136
137
138
  			   BIT(0)),
  	TPS65086_REGULATOR("BUCK5", "buck5", BUCK5, 0x80, TPS65086_BUCK5VID,
  			   BUCK_VID_MASK, TPS65086_BUCK5CTRL, BIT(0),
d8ca5bd15   Andrew F. Davis   regulator: tps650...
139
  			   tps65086_10mv_ranges, TPS65086_BUCK5CTRL,
d2a2e729a   Andrew F. Davis   regulator: tps650...
140
141
142
  			   BIT(0)),
  	TPS65086_REGULATOR("BUCK6", "buck6", BUCK6, 0x80, TPS65086_BUCK6VID,
  			   BUCK_VID_MASK, TPS65086_BUCK6CTRL, BIT(0),
d8ca5bd15   Andrew F. Davis   regulator: tps650...
143
  			   tps65086_10mv_ranges, TPS65086_BUCK6CTRL,
d2a2e729a   Andrew F. Davis   regulator: tps650...
144
145
146
147
148
149
150
151
152
153
154
  			   BIT(0)),
  	TPS65086_REGULATOR("LDOA1", "ldoa1", LDOA1, 0xF, TPS65086_LDOA1CTRL,
  			   VDOA1_VID_MASK, TPS65086_LDOA1CTRL, BIT(0),
  			   tps65086_ldoa1_ranges, 0, 0),
  	TPS65086_REGULATOR("LDOA2", "ldoa2", LDOA2, 0x10, TPS65086_LDOA2VID,
  			   VDOA23_VID_MASK, TPS65086_LDOA2CTRL, BIT(0),
  			   tps65086_ldoa23_ranges, 0, 0),
  	TPS65086_REGULATOR("LDOA3", "ldoa3", LDOA3, 0x10, TPS65086_LDOA3VID,
  			   VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0),
  			   tps65086_ldoa23_ranges, 0, 0),
  	TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)),
1c47f7c31   Andrew F. Davis   regulator: tps650...
155
156
  	TPS65086_SWITCH("SWB1", "swb1", SWB1, TPS65086_SWVTT_EN, BIT(6)),
  	TPS65086_SWITCH("SWB2", "swb2", SWB2, TPS65086_SWVTT_EN, BIT(7)),
d2a2e729a   Andrew F. Davis   regulator: tps650...
157
158
  	TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)),
  };
6308f1787   Andrew F. Davis   regulator: tps650...
159
  static int tps65086_of_parse_cb(struct device_node *node,
d2a2e729a   Andrew F. Davis   regulator: tps650...
160
161
162
163
164
165
  				const struct regulator_desc *desc,
  				struct regulator_config *config)
  {
  	int ret;
  
  	/* Check for 25mV step mode */
6308f1787   Andrew F. Davis   regulator: tps650...
166
  	if (of_property_read_bool(node, "ti,regulator-step-size-25mv")) {
d8ca5bd15   Andrew F. Davis   regulator: tps650...
167
168
169
170
171
  		switch (desc->id) {
  		case BUCK1:
  		case BUCK2:
  		case BUCK6:
  			regulators[desc->id].desc.linear_ranges =
d2a2e729a   Andrew F. Davis   regulator: tps650...
172
  				tps65086_buck126_25mv_ranges;
d8ca5bd15   Andrew F. Davis   regulator: tps650...
173
  			regulators[desc->id].desc.n_linear_ranges =
d2a2e729a   Andrew F. Davis   regulator: tps650...
174
  				ARRAY_SIZE(tps65086_buck126_25mv_ranges);
d8ca5bd15   Andrew F. Davis   regulator: tps650...
175
176
177
178
179
180
181
182
183
184
185
186
187
  			break;
  		case BUCK3:
  		case BUCK4:
  		case BUCK5:
  			regulators[desc->id].desc.linear_ranges =
  				tps65086_buck345_25mv_ranges;
  			regulators[desc->id].desc.n_linear_ranges =
  				ARRAY_SIZE(tps65086_buck345_25mv_ranges);
  			break;
  		default:
  			dev_warn(config->dev, "25mV step mode only valid for BUCK regulators
  ");
  		}
d2a2e729a   Andrew F. Davis   regulator: tps650...
188
189
190
  	}
  
  	/* Check for decay mode */
6308f1787   Andrew F. Davis   regulator: tps650...
191
  	if (desc->id <= BUCK6 && of_property_read_bool(node, "ti,regulator-decay")) {
d2a2e729a   Andrew F. Davis   regulator: tps650...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  		ret = regmap_write_bits(config->regmap,
  					regulators[desc->id].decay_reg,
  					regulators[desc->id].decay_mask,
  					regulators[desc->id].decay_mask);
  		if (ret) {
  			dev_err(config->dev, "Error setting decay
  ");
  			return ret;
  		}
  	}
  
  	return 0;
  }
  
  static int tps65086_regulator_probe(struct platform_device *pdev)
  {
  	struct tps65086 *tps = dev_get_drvdata(pdev->dev.parent);
  	struct regulator_config config = { };
  	struct regulator_dev *rdev;
  	int i;
  
  	platform_set_drvdata(pdev, tps);
  
  	config.dev = &pdev->dev;
7f9354f26   Andrew F. Davis   regulator: tps650...
216
  	config.dev->of_node = tps->dev->of_node;
d2a2e729a   Andrew F. Davis   regulator: tps650...
217
  	config.driver_data = tps;
d2a2e729a   Andrew F. Davis   regulator: tps650...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  	config.regmap = tps->regmap;
  
  	for (i = 0; i < ARRAY_SIZE(regulators); i++) {
  		rdev = devm_regulator_register(&pdev->dev, &regulators[i].desc,
  					       &config);
  		if (IS_ERR(rdev)) {
  			dev_err(tps->dev, "failed to register %s regulator
  ",
  				pdev->name);
  			return PTR_ERR(rdev);
  		}
  	}
  
  	return 0;
  }
  
  static const struct platform_device_id tps65086_regulator_id_table[] = {
  	{ "tps65086-regulator", },
  	{ /* sentinel */ }
  };
  MODULE_DEVICE_TABLE(platform, tps65086_regulator_id_table);
  
  static struct platform_driver tps65086_regulator_driver = {
  	.driver = {
  		.name = "tps65086-regulator",
  	},
  	.probe = tps65086_regulator_probe,
  	.id_table = tps65086_regulator_id_table,
  };
  module_platform_driver(tps65086_regulator_driver);
  
  MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
  MODULE_DESCRIPTION("TPS65086 Regulator driver");
  MODULE_LICENSE("GPL v2");