blob: 090612460cef19ff7447780ff21db740e704763a [file] [log] [blame]
Tony Lindgren0eecc632017-10-10 14:23:43 -07001/*
2 * ti-sysc.c - Texas Instruments sysc interconnect target driver
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/io.h>
15#include <linux/clk.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/pm_runtime.h>
19#include <linux/of_address.h>
20#include <linux/of_platform.h>
Tony Lindgren70a65242017-12-15 09:41:09 -080021#include <linux/platform_data/ti-sysc.h>
22
23#include <dt-bindings/bus/ti-sysc.h>
Tony Lindgren0eecc632017-10-10 14:23:43 -070024
25enum sysc_registers {
26 SYSC_REVISION,
27 SYSC_SYSCONFIG,
28 SYSC_SYSSTATUS,
29 SYSC_MAX_REGS,
30};
31
32static const char * const reg_names[] = { "rev", "sysc", "syss", };
33
34enum sysc_clocks {
35 SYSC_FCK,
36 SYSC_ICK,
37 SYSC_MAX_CLOCKS,
38};
39
40static const char * const clock_names[] = { "fck", "ick", };
41
42/**
43 * struct sysc - TI sysc interconnect target module registers and capabilities
44 * @dev: struct device pointer
45 * @module_pa: physical address of the interconnect target module
46 * @module_size: size of the interconnect target module
47 * @module_va: virtual address of the interconnect target module
48 * @offsets: register offsets from module base
49 * @clocks: clocks used by the interconnect target module
50 * @legacy_mode: configured for legacy mode if set
Tony Lindgren70a65242017-12-15 09:41:09 -080051 * @cap: interconnect target module capabilities
52 * @cfg: interconnect target module configuration
Tony Lindgren566a9b052017-12-15 09:41:19 -080053 * @name: name if available
54 * @revision: interconnect target module revision
Tony Lindgren0eecc632017-10-10 14:23:43 -070055 */
56struct sysc {
57 struct device *dev;
58 u64 module_pa;
59 u32 module_size;
60 void __iomem *module_va;
61 int offsets[SYSC_MAX_REGS];
62 struct clk *clocks[SYSC_MAX_CLOCKS];
63 const char *legacy_mode;
Tony Lindgren70a65242017-12-15 09:41:09 -080064 const struct sysc_capabilities *cap;
65 struct sysc_config cfg;
Tony Lindgren566a9b052017-12-15 09:41:19 -080066 const char *name;
67 u32 revision;
Tony Lindgren0eecc632017-10-10 14:23:43 -070068};
69
Tony Lindgren566a9b052017-12-15 09:41:19 -080070static u32 sysc_read(struct sysc *ddata, int offset)
71{
72 if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
73 u32 val;
74
75 val = readw_relaxed(ddata->module_va + offset);
76 val |= (readw_relaxed(ddata->module_va + offset + 4) << 16);
77
78 return val;
79 }
80
81 return readl_relaxed(ddata->module_va + offset);
82}
83
Tony Lindgren0eecc632017-10-10 14:23:43 -070084static u32 sysc_read_revision(struct sysc *ddata)
85{
Tony Lindgren566a9b052017-12-15 09:41:19 -080086 int offset = ddata->offsets[SYSC_REVISION];
87
88 if (offset < 0)
89 return 0;
90
91 return sysc_read(ddata, offset);
Tony Lindgren0eecc632017-10-10 14:23:43 -070092}
93
94static int sysc_get_one_clock(struct sysc *ddata,
95 enum sysc_clocks index)
96{
97 const char *name;
98 int error;
99
100 switch (index) {
101 case SYSC_FCK:
102 break;
103 case SYSC_ICK:
104 break;
105 default:
106 return -EINVAL;
107 }
108 name = clock_names[index];
109
110 ddata->clocks[index] = devm_clk_get(ddata->dev, name);
111 if (IS_ERR(ddata->clocks[index])) {
112 if (PTR_ERR(ddata->clocks[index]) == -ENOENT)
113 return 0;
114
115 dev_err(ddata->dev, "clock get error for %s: %li\n",
116 name, PTR_ERR(ddata->clocks[index]));
117
118 return PTR_ERR(ddata->clocks[index]);
119 }
120
121 error = clk_prepare(ddata->clocks[index]);
122 if (error) {
123 dev_err(ddata->dev, "clock prepare error for %s: %i\n",
124 name, error);
125
126 return error;
127 }
128
129 return 0;
130}
131
132static int sysc_get_clocks(struct sysc *ddata)
133{
134 int i, error;
135
136 if (ddata->legacy_mode)
137 return 0;
138
139 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
140 error = sysc_get_one_clock(ddata, i);
141 if (error && error != -ENOENT)
142 return error;
143 }
144
145 return 0;
146}
147
148/**
149 * sysc_parse_and_check_child_range - parses module IO region from ranges
150 * @ddata: device driver data
151 *
152 * In general we only need rev, syss, and sysc registers and not the whole
153 * module range. But we do want the offsets for these registers from the
154 * module base. This allows us to check them against the legacy hwmod
155 * platform data. Let's also check the ranges are configured properly.
156 */
157static int sysc_parse_and_check_child_range(struct sysc *ddata)
158{
159 struct device_node *np = ddata->dev->of_node;
160 const __be32 *ranges;
161 u32 nr_addr, nr_size;
162 int len, error;
163
164 ranges = of_get_property(np, "ranges", &len);
165 if (!ranges) {
166 dev_err(ddata->dev, "missing ranges for %pOF\n", np);
167
168 return -ENOENT;
169 }
170
171 len /= sizeof(*ranges);
172
173 if (len < 3) {
174 dev_err(ddata->dev, "incomplete ranges for %pOF\n", np);
175
176 return -EINVAL;
177 }
178
179 error = of_property_read_u32(np, "#address-cells", &nr_addr);
180 if (error)
181 return -ENOENT;
182
183 error = of_property_read_u32(np, "#size-cells", &nr_size);
184 if (error)
185 return -ENOENT;
186
187 if (nr_addr != 1 || nr_size != 1) {
188 dev_err(ddata->dev, "invalid ranges for %pOF\n", np);
189
190 return -EINVAL;
191 }
192
193 ranges++;
194 ddata->module_pa = of_translate_address(np, ranges++);
195 ddata->module_size = be32_to_cpup(ranges);
196
197 dev_dbg(ddata->dev, "interconnect target 0x%llx size 0x%x for %pOF\n",
198 ddata->module_pa, ddata->module_size, np);
199
200 return 0;
201}
202
203/**
204 * sysc_check_one_child - check child configuration
205 * @ddata: device driver data
206 * @np: child device node
207 *
208 * Let's avoid messy situations where we have new interconnect target
209 * node but children have "ti,hwmods". These belong to the interconnect
210 * target node and are managed by this driver.
211 */
212static int sysc_check_one_child(struct sysc *ddata,
213 struct device_node *np)
214{
215 const char *name;
216
217 name = of_get_property(np, "ti,hwmods", NULL);
218 if (name)
219 dev_warn(ddata->dev, "really a child ti,hwmods property?");
220
221 return 0;
222}
223
224static int sysc_check_children(struct sysc *ddata)
225{
226 struct device_node *child;
227 int error;
228
229 for_each_child_of_node(ddata->dev->of_node, child) {
230 error = sysc_check_one_child(ddata, child);
231 if (error)
232 return error;
233 }
234
235 return 0;
236}
237
Tony Lindgrena7199e22017-12-15 09:41:14 -0800238/*
239 * So far only I2C uses 16-bit read access with clockactivity with revision
240 * in two registers with stride of 4. We can detect this based on the rev
241 * register size to configure things far enough to be able to properly read
242 * the revision register.
243 */
244static void sysc_check_quirk_16bit(struct sysc *ddata, struct resource *res)
245{
246 if (resource_size(res) == 8) {
247 dev_dbg(ddata->dev,
248 "enabling 16-bit and clockactivity quirks\n");
249 ddata->cfg.quirks |= SYSC_QUIRK_16BIT | SYSC_QUIRK_USE_CLOCKACT;
250 }
251}
252
Tony Lindgren0eecc632017-10-10 14:23:43 -0700253/**
254 * sysc_parse_one - parses the interconnect target module registers
255 * @ddata: device driver data
256 * @reg: register to parse
257 */
258static int sysc_parse_one(struct sysc *ddata, enum sysc_registers reg)
259{
260 struct resource *res;
261 const char *name;
262
263 switch (reg) {
264 case SYSC_REVISION:
265 case SYSC_SYSCONFIG:
266 case SYSC_SYSSTATUS:
267 name = reg_names[reg];
268 break;
269 default:
270 return -EINVAL;
271 }
272
273 res = platform_get_resource_byname(to_platform_device(ddata->dev),
274 IORESOURCE_MEM, name);
275 if (!res) {
276 dev_dbg(ddata->dev, "has no %s register\n", name);
277 ddata->offsets[reg] = -ENODEV;
278
279 return 0;
280 }
281
282 ddata->offsets[reg] = res->start - ddata->module_pa;
Tony Lindgrena7199e22017-12-15 09:41:14 -0800283 if (reg == SYSC_REVISION)
284 sysc_check_quirk_16bit(ddata, res);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700285
286 return 0;
287}
288
289static int sysc_parse_registers(struct sysc *ddata)
290{
291 int i, error;
292
293 for (i = 0; i < SYSC_MAX_REGS; i++) {
294 error = sysc_parse_one(ddata, i);
295 if (error)
296 return error;
297 }
298
299 return 0;
300}
301
302/**
303 * sysc_check_registers - check for misconfigured register overlaps
304 * @ddata: device driver data
305 */
306static int sysc_check_registers(struct sysc *ddata)
307{
308 int i, j, nr_regs = 0, nr_matches = 0;
309
310 for (i = 0; i < SYSC_MAX_REGS; i++) {
311 if (ddata->offsets[i] < 0)
312 continue;
313
314 if (ddata->offsets[i] > (ddata->module_size - 4)) {
315 dev_err(ddata->dev, "register outside module range");
316
317 return -EINVAL;
318 }
319
320 for (j = 0; j < SYSC_MAX_REGS; j++) {
321 if (ddata->offsets[j] < 0)
322 continue;
323
324 if (ddata->offsets[i] == ddata->offsets[j])
325 nr_matches++;
326 }
327 nr_regs++;
328 }
329
330 if (nr_regs < 1) {
331 dev_err(ddata->dev, "missing registers\n");
332
333 return -EINVAL;
334 }
335
336 if (nr_matches > nr_regs) {
337 dev_err(ddata->dev, "overlapping registers: (%i/%i)",
338 nr_regs, nr_matches);
339
340 return -EINVAL;
341 }
342
343 return 0;
344}
345
346/**
347 * syc_ioremap - ioremap register space for the interconnect target module
348 * @ddata: deviec driver data
349 *
350 * Note that the interconnect target module registers can be anywhere
351 * within the first child device address space. For example, SGX has
352 * them at offset 0x1fc00 in the 32MB module address space. We just
353 * what we need around the interconnect target module registers.
354 */
355static int sysc_ioremap(struct sysc *ddata)
356{
357 u32 size = 0;
358
359 if (ddata->offsets[SYSC_SYSSTATUS] >= 0)
360 size = ddata->offsets[SYSC_SYSSTATUS];
361 else if (ddata->offsets[SYSC_SYSCONFIG] >= 0)
362 size = ddata->offsets[SYSC_SYSCONFIG];
363 else if (ddata->offsets[SYSC_REVISION] >= 0)
364 size = ddata->offsets[SYSC_REVISION];
365 else
366 return -EINVAL;
367
368 size &= 0xfff00;
369 size += SZ_256;
370
371 ddata->module_va = devm_ioremap(ddata->dev,
372 ddata->module_pa,
373 size);
374 if (!ddata->module_va)
375 return -EIO;
376
377 return 0;
378}
379
380/**
381 * sysc_map_and_check_registers - ioremap and check device registers
382 * @ddata: device driver data
383 */
384static int sysc_map_and_check_registers(struct sysc *ddata)
385{
386 int error;
387
388 error = sysc_parse_and_check_child_range(ddata);
389 if (error)
390 return error;
391
392 error = sysc_check_children(ddata);
393 if (error)
394 return error;
395
396 error = sysc_parse_registers(ddata);
397 if (error)
398 return error;
399
400 error = sysc_ioremap(ddata);
401 if (error)
402 return error;
403
404 error = sysc_check_registers(ddata);
405 if (error)
406 return error;
407
408 return 0;
409}
410
411/**
412 * sysc_show_rev - read and show interconnect target module revision
413 * @bufp: buffer to print the information to
414 * @ddata: device driver data
415 */
416static int sysc_show_rev(char *bufp, struct sysc *ddata)
417{
Tony Lindgren566a9b052017-12-15 09:41:19 -0800418 int len;
Tony Lindgren0eecc632017-10-10 14:23:43 -0700419
420 if (ddata->offsets[SYSC_REVISION] < 0)
421 return sprintf(bufp, ":NA");
422
Tony Lindgren566a9b052017-12-15 09:41:19 -0800423 len = sprintf(bufp, ":%08x", ddata->revision);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700424
425 return len;
426}
427
428static int sysc_show_reg(struct sysc *ddata,
429 char *bufp, enum sysc_registers reg)
430{
431 if (ddata->offsets[reg] < 0)
432 return sprintf(bufp, ":NA");
433
434 return sprintf(bufp, ":%x", ddata->offsets[reg]);
435}
436
437/**
438 * sysc_show_registers - show information about interconnect target module
439 * @ddata: device driver data
440 */
441static void sysc_show_registers(struct sysc *ddata)
442{
443 char buf[128];
444 char *bufp = buf;
445 int i;
446
447 for (i = 0; i < SYSC_MAX_REGS; i++)
448 bufp += sysc_show_reg(ddata, bufp, i);
449
450 bufp += sysc_show_rev(bufp, ddata);
451
452 dev_dbg(ddata->dev, "%llx:%x%s\n",
453 ddata->module_pa, ddata->module_size,
454 buf);
455}
456
Arnd Bergmanna4a5d492017-10-13 11:25:32 +0200457static int __maybe_unused sysc_runtime_suspend(struct device *dev)
Tony Lindgren0eecc632017-10-10 14:23:43 -0700458{
459 struct sysc *ddata;
460 int i;
461
462 ddata = dev_get_drvdata(dev);
463
464 if (ddata->legacy_mode)
465 return 0;
466
467 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
468 if (IS_ERR_OR_NULL(ddata->clocks[i]))
469 continue;
470 clk_disable(ddata->clocks[i]);
471 }
472
473 return 0;
474}
475
Arnd Bergmanna4a5d492017-10-13 11:25:32 +0200476static int __maybe_unused sysc_runtime_resume(struct device *dev)
Tony Lindgren0eecc632017-10-10 14:23:43 -0700477{
478 struct sysc *ddata;
479 int i, error;
480
481 ddata = dev_get_drvdata(dev);
482
483 if (ddata->legacy_mode)
484 return 0;
485
486 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
487 if (IS_ERR_OR_NULL(ddata->clocks[i]))
488 continue;
489 error = clk_enable(ddata->clocks[i]);
490 if (error)
491 return error;
492 }
493
494 return 0;
495}
496
497static const struct dev_pm_ops sysc_pm_ops = {
498 SET_RUNTIME_PM_OPS(sysc_runtime_suspend,
499 sysc_runtime_resume,
500 NULL)
501};
502
Tony Lindgren566a9b052017-12-15 09:41:19 -0800503/* At this point the module is configured enough to read the revision */
504static int sysc_init_module(struct sysc *ddata)
505{
506 int error;
507
508 error = pm_runtime_get_sync(ddata->dev);
509 if (error < 0) {
510 pm_runtime_put_noidle(ddata->dev);
511
512 return 0;
513 }
514 ddata->revision = sysc_read_revision(ddata);
515 pm_runtime_put_sync(ddata->dev);
516
517 return 0;
518}
519
520/* Device tree configured quirks */
521struct sysc_dts_quirk {
522 const char *name;
523 u32 mask;
524};
525
526static const struct sysc_dts_quirk sysc_dts_quirks[] = {
527 { .name = "ti,no-idle-on-init",
528 .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, },
529 { .name = "ti,no-reset-on-init",
530 .mask = SYSC_QUIRK_NO_RESET_ON_INIT, },
531};
532
533static int sysc_init_dts_quirks(struct sysc *ddata)
534{
535 struct device_node *np = ddata->dev->of_node;
536 const struct property *prop;
537 int i, len, error;
538 u32 val;
539
540 ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
541
542 for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
543 prop = of_get_property(np, sysc_dts_quirks[i].name, &len);
544 if (!prop)
545 break;
546
547 ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
548 }
549
550 error = of_property_read_u32(np, "ti,sysc-delay-us", &val);
551 if (!error) {
552 if (val > 255) {
553 dev_warn(ddata->dev, "bad ti,sysc-delay-us: %i\n",
554 val);
555 }
556
557 ddata->cfg.srst_udelay = (u8)val;
558 }
559
560 return 0;
561}
562
Tony Lindgren0eecc632017-10-10 14:23:43 -0700563static void sysc_unprepare(struct sysc *ddata)
564{
565 int i;
566
567 for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
568 if (!IS_ERR_OR_NULL(ddata->clocks[i]))
569 clk_unprepare(ddata->clocks[i]);
570 }
571}
572
Tony Lindgren70a65242017-12-15 09:41:09 -0800573/*
574 * Common sysc register bits found on omap2, also known as type1
575 */
576static const struct sysc_regbits sysc_regbits_omap2 = {
577 .dmadisable_shift = -ENODEV,
578 .midle_shift = 12,
579 .sidle_shift = 3,
580 .clkact_shift = 8,
581 .emufree_shift = 5,
582 .enwkup_shift = 2,
583 .srst_shift = 1,
584 .autoidle_shift = 0,
585};
586
587static const struct sysc_capabilities sysc_omap2 = {
588 .type = TI_SYSC_OMAP2,
589 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE |
590 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET |
591 SYSC_OMAP2_AUTOIDLE,
592 .regbits = &sysc_regbits_omap2,
593};
594
595/* All omap2 and 3 timers, and timers 1, 2 & 10 on omap 4 and 5 */
596static const struct sysc_capabilities sysc_omap2_timer = {
597 .type = TI_SYSC_OMAP2_TIMER,
598 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE |
599 SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET |
600 SYSC_OMAP2_AUTOIDLE,
601 .regbits = &sysc_regbits_omap2,
602 .mod_quirks = SYSC_QUIRK_USE_CLOCKACT,
603};
604
605/*
606 * SHAM2 (SHA1/MD5) sysc found on omap3, a variant of sysc_regbits_omap2
607 * with different sidle position
608 */
609static const struct sysc_regbits sysc_regbits_omap3_sham = {
610 .dmadisable_shift = -ENODEV,
611 .midle_shift = -ENODEV,
612 .sidle_shift = 4,
613 .clkact_shift = -ENODEV,
614 .enwkup_shift = -ENODEV,
615 .srst_shift = 1,
616 .autoidle_shift = 0,
617 .emufree_shift = -ENODEV,
618};
619
620static const struct sysc_capabilities sysc_omap3_sham = {
621 .type = TI_SYSC_OMAP3_SHAM,
622 .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE,
623 .regbits = &sysc_regbits_omap3_sham,
624};
625
626/*
627 * AES register bits found on omap3 and later, a variant of
628 * sysc_regbits_omap2 with different sidle position
629 */
630static const struct sysc_regbits sysc_regbits_omap3_aes = {
631 .dmadisable_shift = -ENODEV,
632 .midle_shift = -ENODEV,
633 .sidle_shift = 6,
634 .clkact_shift = -ENODEV,
635 .enwkup_shift = -ENODEV,
636 .srst_shift = 1,
637 .autoidle_shift = 0,
638 .emufree_shift = -ENODEV,
639};
640
641static const struct sysc_capabilities sysc_omap3_aes = {
642 .type = TI_SYSC_OMAP3_AES,
643 .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE,
644 .regbits = &sysc_regbits_omap3_aes,
645};
646
647/*
648 * Common sysc register bits found on omap4, also known as type2
649 */
650static const struct sysc_regbits sysc_regbits_omap4 = {
651 .dmadisable_shift = 16,
652 .midle_shift = 4,
653 .sidle_shift = 2,
654 .clkact_shift = -ENODEV,
655 .enwkup_shift = -ENODEV,
656 .emufree_shift = 1,
657 .srst_shift = 0,
658 .autoidle_shift = -ENODEV,
659};
660
661static const struct sysc_capabilities sysc_omap4 = {
662 .type = TI_SYSC_OMAP4,
663 .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU |
664 SYSC_OMAP4_SOFTRESET,
665 .regbits = &sysc_regbits_omap4,
666};
667
668static const struct sysc_capabilities sysc_omap4_timer = {
669 .type = TI_SYSC_OMAP4_TIMER,
670 .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU |
671 SYSC_OMAP4_SOFTRESET,
672 .regbits = &sysc_regbits_omap4,
673};
674
675/*
676 * Common sysc register bits found on omap4, also known as type3
677 */
678static const struct sysc_regbits sysc_regbits_omap4_simple = {
679 .dmadisable_shift = -ENODEV,
680 .midle_shift = 2,
681 .sidle_shift = 0,
682 .clkact_shift = -ENODEV,
683 .enwkup_shift = -ENODEV,
684 .srst_shift = -ENODEV,
685 .emufree_shift = -ENODEV,
686 .autoidle_shift = -ENODEV,
687};
688
689static const struct sysc_capabilities sysc_omap4_simple = {
690 .type = TI_SYSC_OMAP4_SIMPLE,
691 .regbits = &sysc_regbits_omap4_simple,
692};
693
694/*
695 * SmartReflex sysc found on omap34xx
696 */
697static const struct sysc_regbits sysc_regbits_omap34xx_sr = {
698 .dmadisable_shift = -ENODEV,
699 .midle_shift = -ENODEV,
700 .sidle_shift = -ENODEV,
701 .clkact_shift = 20,
702 .enwkup_shift = -ENODEV,
703 .srst_shift = -ENODEV,
704 .emufree_shift = -ENODEV,
705 .autoidle_shift = -ENODEV,
706};
707
708static const struct sysc_capabilities sysc_34xx_sr = {
709 .type = TI_SYSC_OMAP34XX_SR,
710 .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY,
711 .regbits = &sysc_regbits_omap34xx_sr,
712 .mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED,
713};
714
715/*
716 * SmartReflex sysc found on omap36xx and later
717 */
718static const struct sysc_regbits sysc_regbits_omap36xx_sr = {
719 .dmadisable_shift = -ENODEV,
720 .midle_shift = -ENODEV,
721 .sidle_shift = 24,
722 .clkact_shift = -ENODEV,
723 .enwkup_shift = 26,
724 .srst_shift = -ENODEV,
725 .emufree_shift = -ENODEV,
726 .autoidle_shift = -ENODEV,
727};
728
729static const struct sysc_capabilities sysc_36xx_sr = {
730 .type = TI_SYSC_OMAP36XX_SR,
731 .sysc_mask = SYSC_OMAP2_ENAWAKEUP,
732 .regbits = &sysc_regbits_omap36xx_sr,
733 .mod_quirks = SYSC_QUIRK_UNCACHED,
734};
735
736static const struct sysc_capabilities sysc_omap4_sr = {
737 .type = TI_SYSC_OMAP4_SR,
738 .regbits = &sysc_regbits_omap36xx_sr,
739};
740
741/*
742 * McASP register bits found on omap4 and later
743 */
744static const struct sysc_regbits sysc_regbits_omap4_mcasp = {
745 .dmadisable_shift = -ENODEV,
746 .midle_shift = -ENODEV,
747 .sidle_shift = 0,
748 .clkact_shift = -ENODEV,
749 .enwkup_shift = -ENODEV,
750 .srst_shift = -ENODEV,
751 .emufree_shift = -ENODEV,
752 .autoidle_shift = -ENODEV,
753};
754
755static const struct sysc_capabilities sysc_omap4_mcasp = {
756 .type = TI_SYSC_OMAP4_MCASP,
757 .regbits = &sysc_regbits_omap4_mcasp,
758};
759
760/*
761 * FS USB host found on omap4 and later
762 */
763static const struct sysc_regbits sysc_regbits_omap4_usb_host_fs = {
764 .dmadisable_shift = -ENODEV,
765 .midle_shift = -ENODEV,
766 .sidle_shift = 24,
767 .clkact_shift = -ENODEV,
768 .enwkup_shift = 26,
769 .srst_shift = -ENODEV,
770 .emufree_shift = -ENODEV,
771 .autoidle_shift = -ENODEV,
772};
773
774static const struct sysc_capabilities sysc_omap4_usb_host_fs = {
775 .type = TI_SYSC_OMAP4_USB_HOST_FS,
776 .sysc_mask = SYSC_OMAP2_ENAWAKEUP,
777 .regbits = &sysc_regbits_omap4_usb_host_fs,
778};
779
780static int sysc_init_match(struct sysc *ddata)
781{
782 const struct sysc_capabilities *cap;
783
784 cap = of_device_get_match_data(ddata->dev);
785 if (!cap)
786 return -EINVAL;
787
788 ddata->cap = cap;
789 if (ddata->cap)
790 ddata->cfg.quirks |= ddata->cap->mod_quirks;
791
792 return 0;
793}
794
Tony Lindgren0eecc632017-10-10 14:23:43 -0700795static int sysc_probe(struct platform_device *pdev)
796{
Tony Lindgren0eecc632017-10-10 14:23:43 -0700797 struct sysc *ddata;
798 int error;
799
800 ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
801 if (!ddata)
802 return -ENOMEM;
803
804 ddata->dev = &pdev->dev;
Tony Lindgren566a9b052017-12-15 09:41:19 -0800805 platform_set_drvdata(pdev, ddata);
Tony Lindgren0eecc632017-10-10 14:23:43 -0700806
Tony Lindgren70a65242017-12-15 09:41:09 -0800807 error = sysc_init_match(ddata);
808 if (error)
809 return error;
810
Tony Lindgren566a9b052017-12-15 09:41:19 -0800811 error = sysc_init_dts_quirks(ddata);
812 if (error)
813 goto unprepare;
814
Tony Lindgren0eecc632017-10-10 14:23:43 -0700815 error = sysc_get_clocks(ddata);
816 if (error)
817 return error;
818
819 error = sysc_map_and_check_registers(ddata);
820 if (error)
821 goto unprepare;
822
Tony Lindgren0eecc632017-10-10 14:23:43 -0700823 pm_runtime_enable(ddata->dev);
Tony Lindgren566a9b052017-12-15 09:41:19 -0800824
825 error = sysc_init_module(ddata);
826 if (error)
827 goto unprepare;
828
Tony Lindgren0eecc632017-10-10 14:23:43 -0700829 error = pm_runtime_get_sync(ddata->dev);
830 if (error < 0) {
831 pm_runtime_put_noidle(ddata->dev);
832 pm_runtime_disable(ddata->dev);
833 goto unprepare;
834 }
835
836 pm_runtime_use_autosuspend(ddata->dev);
837
838 sysc_show_registers(ddata);
839
840 error = of_platform_populate(ddata->dev->of_node,
841 NULL, NULL, ddata->dev);
842 if (error)
843 goto err;
844
845 pm_runtime_mark_last_busy(ddata->dev);
846 pm_runtime_put_autosuspend(ddata->dev);
847
848 return 0;
849
850err:
851 pm_runtime_dont_use_autosuspend(&pdev->dev);
852 pm_runtime_put_sync(&pdev->dev);
853 pm_runtime_disable(&pdev->dev);
854unprepare:
855 sysc_unprepare(ddata);
856
857 return error;
858}
859
Tony Lindgren684be5a2017-10-13 10:48:40 -0700860static int sysc_remove(struct platform_device *pdev)
861{
862 struct sysc *ddata = platform_get_drvdata(pdev);
863 int error;
864
865 error = pm_runtime_get_sync(ddata->dev);
866 if (error < 0) {
867 pm_runtime_put_noidle(ddata->dev);
868 pm_runtime_disable(ddata->dev);
869 goto unprepare;
870 }
871
872 of_platform_depopulate(&pdev->dev);
873
874 pm_runtime_dont_use_autosuspend(&pdev->dev);
875 pm_runtime_put_sync(&pdev->dev);
876 pm_runtime_disable(&pdev->dev);
877
878unprepare:
879 sysc_unprepare(ddata);
880
881 return 0;
882}
883
Tony Lindgren0eecc632017-10-10 14:23:43 -0700884static const struct of_device_id sysc_match[] = {
Tony Lindgren70a65242017-12-15 09:41:09 -0800885 { .compatible = "ti,sysc-omap2", .data = &sysc_omap2, },
886 { .compatible = "ti,sysc-omap2-timer", .data = &sysc_omap2_timer, },
887 { .compatible = "ti,sysc-omap4", .data = &sysc_omap4, },
888 { .compatible = "ti,sysc-omap4-timer", .data = &sysc_omap4_timer, },
889 { .compatible = "ti,sysc-omap4-simple", .data = &sysc_omap4_simple, },
890 { .compatible = "ti,sysc-omap3430-sr", .data = &sysc_34xx_sr, },
891 { .compatible = "ti,sysc-omap3630-sr", .data = &sysc_36xx_sr, },
892 { .compatible = "ti,sysc-omap4-sr", .data = &sysc_omap4_sr, },
893 { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, },
894 { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, },
895 { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, },
896 { .compatible = "ti,sysc-usb-host-fs",
897 .data = &sysc_omap4_usb_host_fs, },
Tony Lindgren0eecc632017-10-10 14:23:43 -0700898 { },
899};
900MODULE_DEVICE_TABLE(of, sysc_match);
901
902static struct platform_driver sysc_driver = {
903 .probe = sysc_probe,
Tony Lindgren684be5a2017-10-13 10:48:40 -0700904 .remove = sysc_remove,
Tony Lindgren0eecc632017-10-10 14:23:43 -0700905 .driver = {
906 .name = "ti-sysc",
907 .of_match_table = sysc_match,
908 .pm = &sysc_pm_ops,
909 },
910};
911module_platform_driver(sysc_driver);
912
913MODULE_DESCRIPTION("TI sysc interconnect target driver");
914MODULE_LICENSE("GPL v2");