aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2015-04-10 05:29:41 -0400
committerThierry Reding <treding@nvidia.com>2015-08-13 07:47:21 -0400
commit15372d4be7f099662dc84e4e35e844bd4373d959 (patch)
tree1654212589cad51d77aeb80bef21f5fe3c4c7b91
parent5e7752436e10427ba598de4f2f6b7889daf586cc (diff)
gpu: host1x: mipi: Power down regulators when unused
Keep track of the number of users of DSI and CSI pads and power down the regulators that supply the bricks when all users are gone. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/host1x/mipi.c110
1 files changed, 98 insertions, 12 deletions
diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c
index 0989b8151b4c..52a6fd224127 100644
--- a/drivers/gpu/host1x/mipi.c
+++ b/drivers/gpu/host1x/mipi.c
@@ -118,9 +118,12 @@ struct tegra_mipi_soc {
118 118
119struct tegra_mipi { 119struct tegra_mipi {
120 const struct tegra_mipi_soc *soc; 120 const struct tegra_mipi_soc *soc;
121 struct device *dev;
121 void __iomem *regs; 122 void __iomem *regs;
122 struct mutex lock; 123 struct mutex lock;
123 struct clk *clk; 124 struct clk *clk;
125
126 unsigned long usage_count;
124}; 127};
125 128
126struct tegra_mipi_device { 129struct tegra_mipi_device {
@@ -142,6 +145,67 @@ static inline void tegra_mipi_writel(struct tegra_mipi *mipi, u32 value,
142 writel(value, mipi->regs + (offset << 2)); 145 writel(value, mipi->regs + (offset << 2));
143} 146}
144 147
148static int tegra_mipi_power_up(struct tegra_mipi *mipi)
149{
150 u32 value;
151 int err;
152
153 err = clk_enable(mipi->clk);
154 if (err < 0)
155 return err;
156
157 value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0);
158 value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
159
160 if (mipi->soc->needs_vclamp_ref)
161 value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
162
163 tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
164
165 value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2);
166 value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
167 tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
168
169 clk_disable(mipi->clk);
170
171 return 0;
172}
173
174static int tegra_mipi_power_down(struct tegra_mipi *mipi)
175{
176 u32 value;
177 int err;
178
179 err = clk_enable(mipi->clk);
180 if (err < 0)
181 return err;
182
183 /*
184 * The MIPI_CAL_BIAS_PAD_PDVREG controls a voltage regulator that
185 * supplies the DSI pads. This must be kept enabled until none of the
186 * DSI lanes are used anymore.
187 */
188 value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG2);
189 value |= MIPI_CAL_BIAS_PAD_PDVREG;
190 tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
191
192 /*
193 * MIPI_CAL_BIAS_PAD_PDVCLAMP and MIPI_CAL_BIAS_PAD_E_VCLAMP_REF
194 * control a regulator that supplies current to the pre-driver logic.
195 * Powering down this regulator causes DSI to fail, so it must remain
196 * powered on until none of the DSI lanes are used anymore.
197 */
198 value = tegra_mipi_readl(mipi, MIPI_CAL_BIAS_PAD_CFG0);
199
200 if (mipi->soc->needs_vclamp_ref)
201 value &= ~MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
202
203 value |= MIPI_CAL_BIAS_PAD_PDVCLAMP;
204 tegra_mipi_writel(mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
205
206 return 0;
207}
208
145struct tegra_mipi_device *tegra_mipi_request(struct device *device) 209struct tegra_mipi_device *tegra_mipi_request(struct device *device)
146{ 210{
147 struct device_node *np = device->of_node; 211 struct device_node *np = device->of_node;
@@ -178,6 +242,20 @@ struct tegra_mipi_device *tegra_mipi_request(struct device *device)
178 dev->pads = args.args[0]; 242 dev->pads = args.args[0];
179 dev->device = device; 243 dev->device = device;
180 244
245 mutex_lock(&dev->mipi->lock);
246
247 if (dev->mipi->usage_count++ == 0) {
248 err = tegra_mipi_power_up(dev->mipi);
249 if (err < 0) {
250 dev_err(dev->mipi->dev,
251 "failed to power up MIPI bricks: %d\n",
252 err);
253 return ERR_PTR(err);
254 }
255 }
256
257 mutex_unlock(&dev->mipi->lock);
258
181 return dev; 259 return dev;
182 260
183put: 261put:
@@ -192,6 +270,25 @@ EXPORT_SYMBOL(tegra_mipi_request);
192 270
193void tegra_mipi_free(struct tegra_mipi_device *device) 271void tegra_mipi_free(struct tegra_mipi_device *device)
194{ 272{
273 int err;
274
275 mutex_lock(&device->mipi->lock);
276
277 if (--device->mipi->usage_count == 0) {
278 err = tegra_mipi_power_down(device->mipi);
279 if (err < 0) {
280 /*
281 * Not much that can be done here, so an error message
282 * will have to do.
283 */
284 dev_err(device->mipi->dev,
285 "failed to power down MIPI bricks: %d\n",
286 err);
287 }
288 }
289
290 mutex_unlock(&device->mipi->lock);
291
195 platform_device_put(device->pdev); 292 platform_device_put(device->pdev);
196 kfree(device); 293 kfree(device);
197} 294}
@@ -227,23 +324,11 @@ int tegra_mipi_calibrate(struct tegra_mipi_device *device)
227 324
228 mutex_lock(&device->mipi->lock); 325 mutex_lock(&device->mipi->lock);
229 326
230 value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0);
231 value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
232
233 if (soc->needs_vclamp_ref)
234 value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
235
236 tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
237
238 value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc->pad_drive_down_ref) | 327 value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(soc->pad_drive_down_ref) |
239 MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc->pad_drive_up_ref); 328 MIPI_CAL_BIAS_PAD_DRV_UP_REF(soc->pad_drive_up_ref);
240 tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG1); 329 tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG1);
241 330
242 value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2); 331 value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
243 value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
244 tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
245
246 value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
247 value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7); 332 value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7);
248 value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7); 333 value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7);
249 value |= MIPI_CAL_BIAS_PAD_VCLAMP(soc->pad_vclamp_level); 334 value |= MIPI_CAL_BIAS_PAD_VCLAMP(soc->pad_vclamp_level);
@@ -426,6 +511,7 @@ static int tegra_mipi_probe(struct platform_device *pdev)
426 return -ENOMEM; 511 return -ENOMEM;
427 512
428 mipi->soc = match->data; 513 mipi->soc = match->data;
514 mipi->dev = &pdev->dev;
429 515
430 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 516 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
431 mipi->regs = devm_ioremap_resource(&pdev->dev, res); 517 mipi->regs = devm_ioremap_resource(&pdev->dev, res);