Blame view

drivers/regulator/aat2870-regulator.c 4.92 KB
2b27bdcc2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
f7eb6c5e8   Jin Park   regulator: aat287...
2
3
4
5
6
  /*
   * linux/drivers/regulator/aat2870-regulator.c
   *
   * Copyright (c) 2011, NVIDIA Corporation.
   * Author: Jin Park <jinyoungp@nvidia.com>
f7eb6c5e8   Jin Park   regulator: aat287...
7
8
9
10
11
   */
  
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/err.h>
3a7d021b5   Randy Dunlap   regulator: aat287...
12
  #include <linux/module.h>
f7eb6c5e8   Jin Park   regulator: aat287...
13
  #include <linux/slab.h>
f7eb6c5e8   Jin Park   regulator: aat287...
14
15
16
17
18
19
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/machine.h>
  #include <linux/mfd/aat2870.h>
  
  struct aat2870_regulator {
b21bcd1ad   Axel Lin   regulator: Add a ...
20
  	struct aat2870_data *aat2870;
f7eb6c5e8   Jin Park   regulator: aat287...
21
  	struct regulator_desc desc;
f7eb6c5e8   Jin Park   regulator: aat287...
22
23
24
25
26
27
28
29
  	u8 enable_addr;
  	u8 enable_shift;
  	u8 enable_mask;
  
  	u8 voltage_addr;
  	u8 voltage_shift;
  	u8 voltage_mask;
  };
f7eb6c5e8   Jin Park   regulator: aat287...
30
31
32
33
  static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev,
  				       unsigned selector)
  {
  	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
b21bcd1ad   Axel Lin   regulator: Add a ...
34
  	struct aat2870_data *aat2870 = ri->aat2870;
f7eb6c5e8   Jin Park   regulator: aat287...
35
36
  
  	return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask,
a5228d2e5   Axel Lin   regulator: aat287...
37
  			       selector << ri->voltage_shift);
f7eb6c5e8   Jin Park   regulator: aat287...
38
39
40
41
42
  }
  
  static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev)
  {
  	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
b21bcd1ad   Axel Lin   regulator: Add a ...
43
  	struct aat2870_data *aat2870 = ri->aat2870;
f7eb6c5e8   Jin Park   regulator: aat287...
44
45
46
47
48
49
50
51
52
53
54
55
56
  	u8 val;
  	int ret;
  
  	ret = aat2870->read(aat2870, ri->voltage_addr, &val);
  	if (ret)
  		return ret;
  
  	return (val & ri->voltage_mask) >> ri->voltage_shift;
  }
  
  static int aat2870_ldo_enable(struct regulator_dev *rdev)
  {
  	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
b21bcd1ad   Axel Lin   regulator: Add a ...
57
  	struct aat2870_data *aat2870 = ri->aat2870;
f7eb6c5e8   Jin Park   regulator: aat287...
58
59
60
61
62
63
64
65
  
  	return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask,
  			       ri->enable_mask);
  }
  
  static int aat2870_ldo_disable(struct regulator_dev *rdev)
  {
  	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
b21bcd1ad   Axel Lin   regulator: Add a ...
66
  	struct aat2870_data *aat2870 = ri->aat2870;
f7eb6c5e8   Jin Park   regulator: aat287...
67
68
69
70
71
72
73
  
  	return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0);
  }
  
  static int aat2870_ldo_is_enabled(struct regulator_dev *rdev)
  {
  	struct aat2870_regulator *ri = rdev_get_drvdata(rdev);
b21bcd1ad   Axel Lin   regulator: Add a ...
74
  	struct aat2870_data *aat2870 = ri->aat2870;
f7eb6c5e8   Jin Park   regulator: aat287...
75
76
77
78
79
80
81
82
83
  	u8 val;
  	int ret;
  
  	ret = aat2870->read(aat2870, ri->enable_addr, &val);
  	if (ret)
  		return ret;
  
  	return val & ri->enable_mask ? 1 : 0;
  }
2abf29af9   Bhumika Goyal   regulator: aat287...
84
  static const struct regulator_ops aat2870_ldo_ops = {
4506c6d5e   Axel Lin   regulator: aat287...
85
  	.list_voltage = regulator_list_voltage_table,
08d6da291   Axel Lin   regulator: aat287...
86
  	.map_voltage = regulator_map_voltage_ascend,
f7eb6c5e8   Jin Park   regulator: aat287...
87
88
89
90
91
92
  	.set_voltage_sel = aat2870_ldo_set_voltage_sel,
  	.get_voltage_sel = aat2870_ldo_get_voltage_sel,
  	.enable = aat2870_ldo_enable,
  	.disable = aat2870_ldo_disable,
  	.is_enabled = aat2870_ldo_is_enabled,
  };
4506c6d5e   Axel Lin   regulator: aat287...
93
  static const unsigned int aat2870_ldo_voltages[] = {
f7eb6c5e8   Jin Park   regulator: aat287...
94
95
96
97
98
99
100
101
102
103
104
105
  	1200000, 1300000, 1500000, 1600000,
  	1800000, 2000000, 2200000, 2500000,
  	2600000, 2700000, 2800000, 2900000,
  	3000000, 3100000, 3200000, 3300000,
  };
  
  #define AAT2870_LDO(ids)				\
  	{						\
  		.desc = {				\
  			.name = #ids,			\
  			.id = AAT2870_ID_##ids,		\
  			.n_voltages = ARRAY_SIZE(aat2870_ldo_voltages),	\
4506c6d5e   Axel Lin   regulator: aat287...
106
  			.volt_table = aat2870_ldo_voltages, \
f7eb6c5e8   Jin Park   regulator: aat287...
107
108
109
110
  			.ops = &aat2870_ldo_ops,	\
  			.type = REGULATOR_VOLTAGE,	\
  			.owner = THIS_MODULE,		\
  		},					\
f7eb6c5e8   Jin Park   regulator: aat287...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  	}
  
  static struct aat2870_regulator aat2870_regulators[] = {
  	AAT2870_LDO(LDOA),
  	AAT2870_LDO(LDOB),
  	AAT2870_LDO(LDOC),
  	AAT2870_LDO(LDOD),
  };
  
  static struct aat2870_regulator *aat2870_get_regulator(int id)
  {
  	struct aat2870_regulator *ri = NULL;
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) {
  		ri = &aat2870_regulators[i];
  		if (ri->desc.id == id)
  			break;
  	}
d4d6373c1   Axel Lin   regulator: aat287...
130
  	if (i == ARRAY_SIZE(aat2870_regulators))
f7eb6c5e8   Jin Park   regulator: aat287...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  		return NULL;
  
  	ri->enable_addr = AAT2870_LDO_EN;
  	ri->enable_shift = id - AAT2870_ID_LDOA;
  	ri->enable_mask = 0x1 << ri->enable_shift;
  
  	ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ?
  			   AAT2870_LDO_CD : AAT2870_LDO_AB;
  	ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4;
  	ri->voltage_mask = 0xF << ri->voltage_shift;
  
  	return ri;
  }
  
  static int aat2870_regulator_probe(struct platform_device *pdev)
  {
  	struct aat2870_regulator *ri;
e4c5288e4   Mark Brown   regulator: aat287...
148
  	struct regulator_config config = { };
f7eb6c5e8   Jin Park   regulator: aat287...
149
150
151
152
153
154
155
156
  	struct regulator_dev *rdev;
  
  	ri = aat2870_get_regulator(pdev->id);
  	if (!ri) {
  		dev_err(&pdev->dev, "Invalid device ID, %d
  ", pdev->id);
  		return -EINVAL;
  	}
b21bcd1ad   Axel Lin   regulator: Add a ...
157
  	ri->aat2870 = dev_get_drvdata(pdev->dev.parent);
f7eb6c5e8   Jin Park   regulator: aat287...
158

c172708d3   Mark Brown   regulator: core: ...
159
160
  	config.dev = &pdev->dev;
  	config.driver_data = ri;
dff91d0b7   Jingoo Han   regulator: use de...
161
  	config.init_data = dev_get_platdata(&pdev->dev);
c172708d3   Mark Brown   regulator: core: ...
162

b1a613d50   Axel Lin   regulator: aat287...
163
  	rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config);
f7eb6c5e8   Jin Park   regulator: aat287...
164
165
166
167
168
169
170
171
172
173
  	if (IS_ERR(rdev)) {
  		dev_err(&pdev->dev, "Failed to register regulator %s
  ",
  			ri->desc.name);
  		return PTR_ERR(rdev);
  	}
  	platform_set_drvdata(pdev, rdev);
  
  	return 0;
  }
f7eb6c5e8   Jin Park   regulator: aat287...
174
175
176
  static struct platform_driver aat2870_regulator_driver = {
  	.driver = {
  		.name	= "aat2870-regulator",
f7eb6c5e8   Jin Park   regulator: aat287...
177
178
  	},
  	.probe	= aat2870_regulator_probe,
f7eb6c5e8   Jin Park   regulator: aat287...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  };
  
  static int __init aat2870_regulator_init(void)
  {
  	return platform_driver_register(&aat2870_regulator_driver);
  }
  subsys_initcall(aat2870_regulator_init);
  
  static void __exit aat2870_regulator_exit(void)
  {
  	platform_driver_unregister(&aat2870_regulator_driver);
  }
  module_exit(aat2870_regulator_exit);
  
  MODULE_DESCRIPTION("AnalogicTech AAT2870 Regulator");
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
ad9c5ffea   Mark Brown   regulator: aat287...
196
  MODULE_ALIAS("platform:aat2870-regulator");