blob: b16e37ee7f63502557586cd204b85a073aa974a7 [file] [log] [blame]
Harsh Shahbbe33742017-03-14 18:09:54 -07001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
14
15#include <linux/of.h>
16#include <linux/clk.h>
17#include "cam_soc_util.h"
18
19#undef CDBG
20#define CDBG(fmt, args...) pr_debug(fmt, ##args)
21
22int cam_soc_util_irq_enable(struct cam_hw_soc_info *soc_info)
23{
24 if (!soc_info) {
25 pr_err("Invalid arguments\n");
26 return -EINVAL;
27 }
28
29 if (!soc_info->irq_line) {
30 pr_err("No IRQ line available\n");
31 return -ENODEV;
32 }
33
34 enable_irq(soc_info->irq_line->start);
35
36 return 0;
37}
38
39int cam_soc_util_irq_disable(struct cam_hw_soc_info *soc_info)
40{
41 if (!soc_info) {
42 pr_err("Invalid arguments\n");
43 return -EINVAL;
44 }
45
46 if (!soc_info->irq_line) {
47 pr_err("No IRQ line available\n");
48 return -ENODEV;
49 }
50
51 disable_irq(soc_info->irq_line->start);
52
53 return 0;
54}
55
56int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name,
57 int32_t clk_rate)
58{
59 int rc = 0;
60 long clk_rate_round;
61
Harsh Shahc3ac9b92017-03-27 15:03:47 -070062 if (!clk || !clk_name)
Harsh Shahbbe33742017-03-14 18:09:54 -070063 return -EINVAL;
64
65 CDBG("enable %s, clk %pK rate %d\n",
66 clk_name, clk, clk_rate);
67 if (clk_rate > 0) {
68 clk_rate_round = clk_round_rate(clk, clk_rate);
69 CDBG("new_rate %ld\n", clk_rate_round);
70 if (clk_rate_round < 0) {
71 pr_err("%s: round failed for clock %s rc = %ld\n",
72 __func__, clk_name, clk_rate_round);
73 return clk_rate_round;
74 }
75 rc = clk_set_rate(clk, clk_rate_round);
76 if (rc) {
77 pr_err("set_rate failed on %s\n", clk_name);
78 return rc;
79 }
80 } else if (clk_rate == INIT_RATE) {
81 clk_rate_round = clk_get_rate(clk);
82 CDBG("init new_rate %ld\n", clk_rate_round);
83 if (clk_rate_round == 0) {
84 clk_rate_round = clk_round_rate(clk, 0);
85 if (clk_rate_round <= 0) {
86 pr_err("round rate failed on %s\n", clk_name);
87 return clk_rate_round;
88 }
89 }
90 rc = clk_set_rate(clk, clk_rate_round);
91 if (rc) {
92 pr_err("set_rate failed on %s\n", clk_name);
93 return rc;
94 }
95 }
96 rc = clk_prepare_enable(clk);
97 if (rc) {
98 pr_err("enable failed for %s\n", clk_name);
99 return rc;
100 }
101
102 return rc;
103}
104
105int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name)
106{
107 if (!clk || !clk_name)
108 return -EINVAL;
109
110 CDBG("disable %s\n", clk_name);
111 clk_disable_unprepare(clk);
112
113 return 0;
114}
115
116/**
117 * cam_soc_util_clk_enable_default()
118 *
119 * @brief: This function enables the default clocks present
120 * in soc_info
121 *
122 * @soc_info: device soc struct to be populated
123 *
124 * @return: success or failure
125 */
126static int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info)
127{
128 int i, rc = 0;
129
130 if (soc_info->num_clk == 0)
131 return rc;
132
133 for (i = 0; i < soc_info->num_clk; i++) {
134 rc = cam_soc_util_clk_enable(soc_info->clk[i],
135 soc_info->clk_name[i], soc_info->clk_rate[i]);
136 if (rc)
137 goto clk_disable;
138 }
139
140 return rc;
141
142clk_disable:
143 for (i--; i >= 0; i--) {
144 cam_soc_util_clk_disable(soc_info->clk[i],
145 soc_info->clk_name[i]);
146 }
147
148 return rc;
149}
150
151/**
152 * cam_soc_util_clk_disable_default()
153 *
154 * @brief: This function disables the default clocks present
155 * in soc_info
156 *
157 * @soc_info: device soc struct to be populated
158 *
159 * @return: success or failure
160 */
161static void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info)
162{
163 int i;
164
165 if (soc_info->num_clk == 0)
166 return;
167
168 for (i = soc_info->num_clk - 1; i >= 0; i--) {
169 CDBG("disable %s\n", soc_info->clk_name[i]);
170 cam_soc_util_clk_disable(soc_info->clk[i],
171 soc_info->clk_name[i]);
172 }
173}
174
175/**
176 * cam_soc_util_get_dt_clk_info()
177 *
178 * @brief: Parse the DT and populate the Clock properties
179 *
180 * @soc_info: device soc struct to be populated
181 * @src_clk_str name of src clock that has rate control
182 *
183 * @return: success or failure
184 */
185static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info)
186{
187 struct device_node *of_node = NULL;
188 int count;
189 int i, rc;
190 struct platform_device *pdev = NULL;
191 const char *src_clk_str = NULL;
192
193 if (!soc_info || !soc_info->pdev)
194 return -EINVAL;
195
196 pdev = soc_info->pdev;
197
198 of_node = pdev->dev.of_node;
199
200 count = of_property_count_strings(of_node, "clock-names");
201
202 CDBG("count = %d\n", count);
203 if (count > CAM_SOC_MAX_CLK) {
204 pr_err("invalid count of clocks, count=%d", count);
205 rc = -EINVAL;
206 return rc;
207 }
208 if (count <= 0) {
209 CDBG("No clock-names found\n");
210 count = 0;
211 soc_info->num_clk = count;
212 return 0;
213 }
214 soc_info->num_clk = count;
215
216 for (i = 0; i < count; i++) {
217 rc = of_property_read_string_index(of_node, "clock-names",
218 i, &(soc_info->clk_name[i]));
219 CDBG("clock-names[%d] = %s\n", i, soc_info->clk_name[i]);
220 if (rc) {
221 pr_err("i= %d count= %d reading clock-names failed\n",
222 i, count);
223 return rc;
224 }
225 }
226
227 rc = of_property_read_u32_array(of_node, "clock-rates",
228 soc_info->clk_rate, count);
229 if (rc) {
230 pr_err("reading clock-rates failed");
231 return rc;
232 }
233
Harsh Shahc3ac9b92017-03-27 15:03:47 -0700234 rc = of_property_read_string_index(of_node, "src-clock-name", 0,
235 &src_clk_str);
Harsh Shahbbe33742017-03-14 18:09:54 -0700236 if (rc) {
237 CDBG("No src_clk_str found\n");
238 soc_info->src_clk_idx = -1;
239 rc = 0;
240 /* Bottom loop is dependent on src_clk_str. So return here */
241 return rc;
242 }
243
244 for (i = 0; i < soc_info->num_clk; i++) {
245 soc_info->clk_rate[i] = (soc_info->clk_rate[i] == 0) ?
246 (long)-1 : soc_info->clk_rate[i];
247 if (src_clk_str &&
248 (strcmp(soc_info->clk_name[i], src_clk_str) == 0)) {
249 soc_info->src_clk_idx = i;
250 }
251 CDBG("clk_rate[%d] = %d\n", i, soc_info->clk_rate[i]);
252 }
253
254 return rc;
255}
256
257int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info)
258{
259 struct device_node *of_node = NULL;
260 int count = 0, i = 0, rc = 0;
261 struct platform_device *pdev = NULL;
262
263 if (!soc_info || !soc_info->pdev)
264 return -EINVAL;
265
266 pdev = soc_info->pdev;
267
268 of_node = pdev->dev.of_node;
269
270 rc = of_property_read_u32(of_node, "cell-index", &pdev->id);
271 if (rc) {
272 pr_err("device %s failed to read cell-index\n", pdev->name);
273 return rc;
274 }
275
276 count = of_property_count_strings(of_node, "regulator-names");
277 if (count <= 0) {
278 pr_err("no regulators found\n");
279 count = 0;
280 }
281 soc_info->num_rgltr = count;
282
283 for (i = 0; i < soc_info->num_rgltr; i++) {
284 rc = of_property_read_string_index(of_node,
285 "regulator-names", i, &soc_info->rgltr_name[i]);
286 CDBG("rgltr_name[%d] = %s\n", i, soc_info->rgltr_name[i]);
287 if (rc) {
288 pr_err("no regulator resource at cnt=%d\n", i);
289 rc = -ENODEV;
290 return rc;
291 }
292 }
293
294 count = of_property_count_strings(of_node, "reg-names");
295 if (count <= 0) {
296 pr_err("no reg-names found\n");
297 count = 0;
298 }
299 soc_info->num_mem_block = count;
300
301 for (i = 0; i < soc_info->num_mem_block; i++) {
302 rc = of_property_read_string_index(of_node, "reg-names", i,
303 &soc_info->mem_block_name[i]);
304 if (rc) {
305 pr_err("failed to read reg-names at %d\n", i);
306 return rc;
307 }
308 soc_info->mem_block[i] =
309 platform_get_resource_byname(pdev, IORESOURCE_MEM,
310 soc_info->mem_block_name[i]);
311
312 if (!soc_info->mem_block[i]) {
313 pr_err("no mem resource by name %s\n",
314 soc_info->mem_block_name[i]);
315 rc = -ENODEV;
316 return rc;
317 }
318 }
319
320 rc = of_property_read_u32_array(of_node, "reg-cam-base",
321 soc_info->mem_block_cam_base, soc_info->num_mem_block);
322 if (rc) {
323 pr_err("Error reading register offsets\n");
324 return rc;
325 }
326
327 rc = of_property_read_string_index(of_node, "interrupt-names", 0,
328 &soc_info->irq_name);
329 if (rc) {
330 pr_warn("No interrupt line present\n");
331 } else {
332 soc_info->irq_line = platform_get_resource_byname(pdev,
333 IORESOURCE_IRQ, soc_info->irq_name);
334 if (!soc_info->irq_line) {
335 pr_err("no irq resource\n");
336 rc = -ENODEV;
337 return rc;
338 }
339 }
340
341 rc = cam_soc_util_get_dt_clk_info(soc_info);
342
343 return rc;
344}
345
346/**
347 * cam_soc_util_get_regulator()
348 *
349 * @brief: Get regulator resource named vdd
350 *
351 * @pdev: Platform device associated with regulator
352 * @reg: Return pointer to be filled with regulator on success
353 * @rgltr_name: Name of regulator to get
354 *
355 * @return: 0 for Success, negative value for failure
356 */
357static int cam_soc_util_get_regulator(struct platform_device *pdev,
358 struct regulator **reg, const char *rgltr_name)
359{
360 int rc = 0;
361 *reg = regulator_get(&pdev->dev, rgltr_name);
362 if (IS_ERR_OR_NULL(*reg)) {
363 rc = PTR_ERR(*reg);
364 rc = rc ? rc : -EINVAL;
365 pr_err("Regulator %s get failed %d\n", rgltr_name, rc);
366 *reg = NULL;
367 }
368 return rc;
369}
370
371int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info,
372 irq_handler_t handler, void *irq_data)
373{
374 int i = 0, rc = 0;
375 struct platform_device *pdev = NULL;
376
377 if (!soc_info || !soc_info->pdev)
378 return -EINVAL;
379
380 pdev = soc_info->pdev;
381
382 for (i = 0; i < soc_info->num_mem_block; i++) {
383 soc_info->reg_map[i].mem_base = ioremap(
384 soc_info->mem_block[i]->start,
385 resource_size(soc_info->mem_block[i]));
386 if (!soc_info->reg_map[i].mem_base) {
387 pr_err("i= %d base NULL\n", i);
388 rc = -ENOMEM;
389 goto unmap_base;
390 }
391 soc_info->reg_map[i].mem_cam_base =
392 soc_info->mem_block_cam_base[i];
393 soc_info->reg_map[i].size =
394 resource_size(soc_info->mem_block[i]);
395 soc_info->num_reg_map++;
396 }
397
398 for (i = 0; i < soc_info->num_rgltr; i++) {
399 rc = cam_soc_util_get_regulator(pdev, &soc_info->rgltr[i],
400 soc_info->rgltr_name[i]);
401 if (rc)
402 goto put_regulator;
403 }
404
405 if (soc_info->irq_line) {
406 rc = devm_request_irq(&pdev->dev, soc_info->irq_line->start,
407 handler, IRQF_TRIGGER_RISING,
408 soc_info->irq_name, irq_data);
409 if (rc < 0) {
410 pr_err("irq request fail\n");
411 rc = -EBUSY;
412 goto put_regulator;
413 }
414 disable_irq(soc_info->irq_line->start);
Pavan Kumar Chilamkurthi84614012017-04-17 22:37:41 -0700415 soc_info->irq_data = irq_data;
Harsh Shahbbe33742017-03-14 18:09:54 -0700416 }
417
418 /* Get Clock */
419 for (i = 0; i < soc_info->num_clk; i++) {
420 soc_info->clk[i] = clk_get(&soc_info->pdev->dev,
421 soc_info->clk_name[i]);
422 if (!soc_info->clk[i]) {
423 pr_err("get failed for %s\n", soc_info->clk_name[i]);
424 rc = -ENOENT;
425 goto put_clk;
426 }
427 }
428
429 return rc;
430
431put_clk:
432 if (i == -1)
433 i = soc_info->num_clk;
434 for (i = i - 1; i >= 0; i--) {
435 if (soc_info->clk[i]) {
436 clk_put(soc_info->clk[i]);
437 soc_info->clk[i] = NULL;
438 }
439 }
440
441 if (soc_info->irq_line) {
442 disable_irq(soc_info->irq_line->start);
Pavan Kumar Chilamkurthi84614012017-04-17 22:37:41 -0700443 devm_free_irq(&soc_info->pdev->dev,
444 soc_info->irq_line->start, irq_data);
Harsh Shahbbe33742017-03-14 18:09:54 -0700445 }
446
447put_regulator:
448 if (i == -1)
449 i = soc_info->num_rgltr;
450 for (i = i - 1; i >= 0; i--) {
451 if (soc_info->rgltr[i]) {
452 regulator_disable(soc_info->rgltr[i]);
453 regulator_put(soc_info->rgltr[i]);
454 soc_info->rgltr[i] = NULL;
455 }
456 }
457
458unmap_base:
459 if (i == -1)
460 i = soc_info->num_reg_map;
461 for (i = i - 1; i >= 0; i--) {
462 iounmap(soc_info->reg_map[i].mem_base);
463 soc_info->reg_map[i].mem_base = NULL;
464 soc_info->reg_map[i].size = 0;
465 }
466
467 return rc;
468}
469
470int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info)
471{
472 int i;
473 struct platform_device *pdev = NULL;
474
475 if (!soc_info || !soc_info->pdev)
476 return -EINVAL;
477
478 pdev = soc_info->pdev;
479
480 for (i = soc_info->num_clk - 1; i >= 0; i--) {
481 clk_put(soc_info->clk[i]);
482 soc_info->clk[i] = NULL;
483 }
484
485 for (i = soc_info->num_rgltr - 1; i >= 0; i--) {
486 if (soc_info->rgltr[i]) {
487 regulator_put(soc_info->rgltr[i]);
488 soc_info->rgltr[i] = NULL;
489 }
490 }
491
492 for (i = soc_info->num_reg_map - 1; i >= 0; i--) {
493 iounmap(soc_info->reg_map[i].mem_base);
494 soc_info->reg_map[i].mem_base = NULL;
495 soc_info->reg_map[i].size = 0;
496 }
497
498 if (soc_info->irq_line) {
499 disable_irq(soc_info->irq_line->start);
Pavan Kumar Chilamkurthi84614012017-04-17 22:37:41 -0700500 devm_free_irq(&soc_info->pdev->dev,
501 soc_info->irq_line->start, soc_info->irq_data);
Harsh Shahbbe33742017-03-14 18:09:54 -0700502 }
503
504 return 0;
505}
506
507int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info,
508 bool enable_clocks, bool enable_irq)
509{
510 int i, rc = 0;
511
512 if (!soc_info)
513 return -EINVAL;
514
515 for (i = 0; i < soc_info->num_rgltr; i++) {
516 rc = regulator_enable(soc_info->rgltr[i]);
517 if (rc) {
518 pr_err("Regulator enable %s failed\n",
519 soc_info->rgltr_name[i]);
520 goto disable_regulator;
521 }
522 }
523
524 if (enable_clocks) {
525 rc = cam_soc_util_clk_enable_default(soc_info);
526 if (rc)
527 goto disable_regulator;
528 }
529
530 if (enable_irq) {
531 rc = cam_soc_util_irq_enable(soc_info);
532 if (rc)
533 goto disable_clk;
534 }
535
536 return rc;
537
538disable_clk:
539 if (enable_clocks)
540 cam_soc_util_clk_disable_default(soc_info);
541
542disable_regulator:
543 if (i == -1)
544 i = soc_info->num_rgltr;
545 for (i = i - 1; i >= 0; i--) {
546 if (soc_info->rgltr[i])
547 regulator_disable(soc_info->rgltr[i]);
548 }
549
550 return rc;
551}
552
553int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info,
554 bool disable_clocks, bool disble_irq)
555{
556 int i, rc = 0;
557
558 if (!soc_info)
559 return -EINVAL;
560
561 if (disable_clocks)
562 cam_soc_util_clk_disable_default(soc_info);
563
564 for (i = soc_info->num_rgltr - 1; i >= 0; i--) {
565 rc |= regulator_disable(soc_info->rgltr[i]);
566 if (rc) {
567 pr_err("Regulator disble %s failed\n",
568 soc_info->rgltr_name[i]);
569 continue;
570 }
571 }
572
573 if (disble_irq)
574 rc |= cam_soc_util_irq_disable(soc_info);
575
576 return rc;
577}
578
579int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info,
580 uint32_t base_index, uint32_t offset, int size)
581{
582 void __iomem *base_addr = NULL;
583
584 CDBG("base_idx %u size=%d\n", base_index, size);
585
586 if (!soc_info || base_index >= soc_info->num_reg_map ||
587 size <= 0 || (offset + size) >=
588 CAM_SOC_GET_REG_MAP_SIZE(soc_info, base_index))
589 return -EINVAL;
590
591 base_addr = CAM_SOC_GET_REG_MAP_START(soc_info, base_index);
592
593 /*
594 * All error checking already done above,
595 * hence ignoring the return value below.
596 */
597 cam_io_dump(base_addr, offset, size);
598
599 return 0;
600}
601