Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/devfreq/event/exynos-ppmu.c
26428 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* exynos_ppmu.c - Exynos PPMU (Platform Performance Monitoring Unit) support
4
*
5
* Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
6
* Author : Chanwoo Choi <[email protected]>
7
*
8
* This driver is based on drivers/devfreq/exynos/exynos_ppmu.c
9
*/
10
11
#include <linux/clk.h>
12
#include <linux/io.h>
13
#include <linux/kernel.h>
14
#include <linux/module.h>
15
#include <linux/of.h>
16
#include <linux/platform_device.h>
17
#include <linux/property.h>
18
#include <linux/regmap.h>
19
#include <linux/suspend.h>
20
#include <linux/devfreq-event.h>
21
22
#include "exynos-ppmu.h"
23
24
enum exynos_ppmu_type {
25
EXYNOS_TYPE_PPMU,
26
EXYNOS_TYPE_PPMU_V2,
27
};
28
29
struct exynos_ppmu_data {
30
struct clk *clk;
31
};
32
33
struct exynos_ppmu {
34
struct devfreq_event_dev **edev;
35
struct devfreq_event_desc *desc;
36
unsigned int num_events;
37
38
struct device *dev;
39
struct regmap *regmap;
40
41
struct exynos_ppmu_data ppmu;
42
enum exynos_ppmu_type ppmu_type;
43
};
44
45
#define PPMU_EVENT(name) \
46
{ "ppmu-event0-"#name, PPMU_PMNCNT0 }, \
47
{ "ppmu-event1-"#name, PPMU_PMNCNT1 }, \
48
{ "ppmu-event2-"#name, PPMU_PMNCNT2 }, \
49
{ "ppmu-event3-"#name, PPMU_PMNCNT3 }
50
51
static struct __exynos_ppmu_events {
52
char *name;
53
int id;
54
} ppmu_events[] = {
55
/* For Exynos3250, Exynos4 and Exynos5260 */
56
PPMU_EVENT(g3d),
57
PPMU_EVENT(fsys),
58
59
/* For Exynos4 SoCs and Exynos3250 */
60
PPMU_EVENT(dmc0),
61
PPMU_EVENT(dmc1),
62
PPMU_EVENT(cpu),
63
PPMU_EVENT(rightbus),
64
PPMU_EVENT(leftbus),
65
PPMU_EVENT(lcd0),
66
PPMU_EVENT(camif),
67
68
/* Only for Exynos3250 and Exynos5260 */
69
PPMU_EVENT(mfc),
70
71
/* Only for Exynos4 SoCs */
72
PPMU_EVENT(mfc-left),
73
PPMU_EVENT(mfc-right),
74
75
/* Only for Exynos5260 SoCs */
76
PPMU_EVENT(drex0-s0),
77
PPMU_EVENT(drex0-s1),
78
PPMU_EVENT(drex1-s0),
79
PPMU_EVENT(drex1-s1),
80
PPMU_EVENT(eagle),
81
PPMU_EVENT(kfc),
82
PPMU_EVENT(isp),
83
PPMU_EVENT(fimc),
84
PPMU_EVENT(gscl),
85
PPMU_EVENT(mscl),
86
PPMU_EVENT(fimd0x),
87
PPMU_EVENT(fimd1x),
88
89
/* Only for Exynos5433 SoCs */
90
PPMU_EVENT(d0-cpu),
91
PPMU_EVENT(d0-general),
92
PPMU_EVENT(d0-rt),
93
PPMU_EVENT(d1-cpu),
94
PPMU_EVENT(d1-general),
95
PPMU_EVENT(d1-rt),
96
97
/* For Exynos5422 SoC, deprecated (backwards compatible) */
98
PPMU_EVENT(dmc0_0),
99
PPMU_EVENT(dmc0_1),
100
PPMU_EVENT(dmc1_0),
101
PPMU_EVENT(dmc1_1),
102
/* For Exynos5422 SoC */
103
PPMU_EVENT(dmc0-0),
104
PPMU_EVENT(dmc0-1),
105
PPMU_EVENT(dmc1-0),
106
PPMU_EVENT(dmc1-1),
107
};
108
109
static int __exynos_ppmu_find_ppmu_id(const char *edev_name)
110
{
111
int i;
112
113
for (i = 0; i < ARRAY_SIZE(ppmu_events); i++)
114
if (!strcmp(edev_name, ppmu_events[i].name))
115
return ppmu_events[i].id;
116
117
return -EINVAL;
118
}
119
120
static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
121
{
122
return __exynos_ppmu_find_ppmu_id(edev->desc->name);
123
}
124
125
/*
126
* The devfreq-event ops structure for PPMU v1.1
127
*/
128
static int exynos_ppmu_disable(struct devfreq_event_dev *edev)
129
{
130
struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
131
int ret;
132
u32 pmnc;
133
134
/* Disable all counters */
135
ret = regmap_write(info->regmap, PPMU_CNTENC,
136
PPMU_CCNT_MASK |
137
PPMU_PMCNT0_MASK |
138
PPMU_PMCNT1_MASK |
139
PPMU_PMCNT2_MASK |
140
PPMU_PMCNT3_MASK);
141
if (ret < 0)
142
return ret;
143
144
/* Disable PPMU */
145
ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
146
if (ret < 0)
147
return ret;
148
149
pmnc &= ~PPMU_PMNC_ENABLE_MASK;
150
ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
151
if (ret < 0)
152
return ret;
153
154
return 0;
155
}
156
157
static int exynos_ppmu_set_event(struct devfreq_event_dev *edev)
158
{
159
struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
160
int id = exynos_ppmu_find_ppmu_id(edev);
161
int ret;
162
u32 pmnc, cntens;
163
164
if (id < 0)
165
return id;
166
167
/* Enable specific counter */
168
ret = regmap_read(info->regmap, PPMU_CNTENS, &cntens);
169
if (ret < 0)
170
return ret;
171
172
cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
173
ret = regmap_write(info->regmap, PPMU_CNTENS, cntens);
174
if (ret < 0)
175
return ret;
176
177
/* Set the event of proper data type monitoring */
178
ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id),
179
edev->desc->event_type);
180
if (ret < 0)
181
return ret;
182
183
/* Reset cycle counter/performance counter and enable PPMU */
184
ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
185
if (ret < 0)
186
return ret;
187
188
pmnc &= ~(PPMU_PMNC_ENABLE_MASK
189
| PPMU_PMNC_COUNTER_RESET_MASK
190
| PPMU_PMNC_CC_RESET_MASK);
191
pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT);
192
pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
193
pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
194
ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
195
if (ret < 0)
196
return ret;
197
198
return 0;
199
}
200
201
static int exynos_ppmu_get_event(struct devfreq_event_dev *edev,
202
struct devfreq_event_data *edata)
203
{
204
struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
205
int id = exynos_ppmu_find_ppmu_id(edev);
206
unsigned int total_count, load_count;
207
unsigned int pmcnt3_high, pmcnt3_low;
208
unsigned int pmnc, cntenc;
209
int ret;
210
211
if (id < 0)
212
return -EINVAL;
213
214
/* Disable PPMU */
215
ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
216
if (ret < 0)
217
return ret;
218
219
pmnc &= ~PPMU_PMNC_ENABLE_MASK;
220
ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
221
if (ret < 0)
222
return ret;
223
224
/* Read cycle count */
225
ret = regmap_read(info->regmap, PPMU_CCNT, &total_count);
226
if (ret < 0)
227
return ret;
228
edata->total_count = total_count;
229
230
/* Read performance count */
231
switch (id) {
232
case PPMU_PMNCNT0:
233
case PPMU_PMNCNT1:
234
case PPMU_PMNCNT2:
235
ret = regmap_read(info->regmap, PPMU_PMNCT(id), &load_count);
236
if (ret < 0)
237
return ret;
238
edata->load_count = load_count;
239
break;
240
case PPMU_PMNCNT3:
241
ret = regmap_read(info->regmap, PPMU_PMCNT3_HIGH, &pmcnt3_high);
242
if (ret < 0)
243
return ret;
244
245
ret = regmap_read(info->regmap, PPMU_PMCNT3_LOW, &pmcnt3_low);
246
if (ret < 0)
247
return ret;
248
249
edata->load_count = ((pmcnt3_high << 8) | pmcnt3_low);
250
break;
251
default:
252
return -EINVAL;
253
}
254
255
/* Disable specific counter */
256
ret = regmap_read(info->regmap, PPMU_CNTENC, &cntenc);
257
if (ret < 0)
258
return ret;
259
260
cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
261
ret = regmap_write(info->regmap, PPMU_CNTENC, cntenc);
262
if (ret < 0)
263
return ret;
264
265
dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name,
266
edata->load_count, edata->total_count);
267
268
return 0;
269
}
270
271
static const struct devfreq_event_ops exynos_ppmu_ops = {
272
.disable = exynos_ppmu_disable,
273
.set_event = exynos_ppmu_set_event,
274
.get_event = exynos_ppmu_get_event,
275
};
276
277
/*
278
* The devfreq-event ops structure for PPMU v2.0
279
*/
280
static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev)
281
{
282
struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
283
int ret;
284
u32 pmnc, clear;
285
286
/* Disable all counters */
287
clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK
288
| PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK);
289
ret = regmap_write(info->regmap, PPMU_V2_FLAG, clear);
290
if (ret < 0)
291
return ret;
292
293
ret = regmap_write(info->regmap, PPMU_V2_INTENC, clear);
294
if (ret < 0)
295
return ret;
296
297
ret = regmap_write(info->regmap, PPMU_V2_CNTENC, clear);
298
if (ret < 0)
299
return ret;
300
301
ret = regmap_write(info->regmap, PPMU_V2_CNT_RESET, clear);
302
if (ret < 0)
303
return ret;
304
305
ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG0, 0x0);
306
if (ret < 0)
307
return ret;
308
309
ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG1, 0x0);
310
if (ret < 0)
311
return ret;
312
313
ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG2, 0x0);
314
if (ret < 0)
315
return ret;
316
317
ret = regmap_write(info->regmap, PPMU_V2_CIG_RESULT, 0x0);
318
if (ret < 0)
319
return ret;
320
321
ret = regmap_write(info->regmap, PPMU_V2_CNT_AUTO, 0x0);
322
if (ret < 0)
323
return ret;
324
325
ret = regmap_write(info->regmap, PPMU_V2_CH_EV0_TYPE, 0x0);
326
if (ret < 0)
327
return ret;
328
329
ret = regmap_write(info->regmap, PPMU_V2_CH_EV1_TYPE, 0x0);
330
if (ret < 0)
331
return ret;
332
333
ret = regmap_write(info->regmap, PPMU_V2_CH_EV2_TYPE, 0x0);
334
if (ret < 0)
335
return ret;
336
337
ret = regmap_write(info->regmap, PPMU_V2_CH_EV3_TYPE, 0x0);
338
if (ret < 0)
339
return ret;
340
341
ret = regmap_write(info->regmap, PPMU_V2_SM_ID_V, 0x0);
342
if (ret < 0)
343
return ret;
344
345
ret = regmap_write(info->regmap, PPMU_V2_SM_ID_A, 0x0);
346
if (ret < 0)
347
return ret;
348
349
ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_V, 0x0);
350
if (ret < 0)
351
return ret;
352
353
ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_A, 0x0);
354
if (ret < 0)
355
return ret;
356
357
ret = regmap_write(info->regmap, PPMU_V2_INTERRUPT_RESET, 0x0);
358
if (ret < 0)
359
return ret;
360
361
/* Disable PPMU */
362
ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
363
if (ret < 0)
364
return ret;
365
366
pmnc &= ~PPMU_PMNC_ENABLE_MASK;
367
ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
368
if (ret < 0)
369
return ret;
370
371
return 0;
372
}
373
374
static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev)
375
{
376
struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
377
unsigned int pmnc, cntens;
378
int id = exynos_ppmu_find_ppmu_id(edev);
379
int ret;
380
381
/* Enable all counters */
382
ret = regmap_read(info->regmap, PPMU_V2_CNTENS, &cntens);
383
if (ret < 0)
384
return ret;
385
386
cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
387
ret = regmap_write(info->regmap, PPMU_V2_CNTENS, cntens);
388
if (ret < 0)
389
return ret;
390
391
/* Set the event of proper data type monitoring */
392
ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
393
edev->desc->event_type);
394
if (ret < 0)
395
return ret;
396
397
/* Reset cycle counter/performance counter and enable PPMU */
398
ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
399
if (ret < 0)
400
return ret;
401
402
pmnc &= ~(PPMU_PMNC_ENABLE_MASK
403
| PPMU_PMNC_COUNTER_RESET_MASK
404
| PPMU_PMNC_CC_RESET_MASK
405
| PPMU_PMNC_CC_DIVIDER_MASK
406
| PPMU_V2_PMNC_START_MODE_MASK);
407
pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT);
408
pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
409
pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
410
pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT);
411
412
ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
413
if (ret < 0)
414
return ret;
415
416
return 0;
417
}
418
419
static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev,
420
struct devfreq_event_data *edata)
421
{
422
struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
423
int id = exynos_ppmu_find_ppmu_id(edev);
424
int ret;
425
unsigned int pmnc, cntenc;
426
unsigned int pmcnt_high, pmcnt_low;
427
unsigned int total_count, count;
428
unsigned long load_count = 0;
429
430
/* Disable PPMU */
431
ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
432
if (ret < 0)
433
return ret;
434
435
pmnc &= ~PPMU_PMNC_ENABLE_MASK;
436
ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
437
if (ret < 0)
438
return ret;
439
440
/* Read cycle count and performance count */
441
ret = regmap_read(info->regmap, PPMU_V2_CCNT, &total_count);
442
if (ret < 0)
443
return ret;
444
edata->total_count = total_count;
445
446
switch (id) {
447
case PPMU_PMNCNT0:
448
case PPMU_PMNCNT1:
449
case PPMU_PMNCNT2:
450
ret = regmap_read(info->regmap, PPMU_V2_PMNCT(id), &count);
451
if (ret < 0)
452
return ret;
453
load_count = count;
454
break;
455
case PPMU_PMNCNT3:
456
ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_HIGH,
457
&pmcnt_high);
458
if (ret < 0)
459
return ret;
460
461
ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_LOW, &pmcnt_low);
462
if (ret < 0)
463
return ret;
464
465
load_count = ((u64)((pmcnt_high & 0xff)) << 32)+ (u64)pmcnt_low;
466
break;
467
}
468
edata->load_count = load_count;
469
470
/* Disable all counters */
471
ret = regmap_read(info->regmap, PPMU_V2_CNTENC, &cntenc);
472
if (ret < 0)
473
return 0;
474
475
cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
476
ret = regmap_write(info->regmap, PPMU_V2_CNTENC, cntenc);
477
if (ret < 0)
478
return ret;
479
480
dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name,
481
edata->load_count, edata->total_count);
482
return 0;
483
}
484
485
static const struct devfreq_event_ops exynos_ppmu_v2_ops = {
486
.disable = exynos_ppmu_v2_disable,
487
.set_event = exynos_ppmu_v2_set_event,
488
.get_event = exynos_ppmu_v2_get_event,
489
};
490
491
static const struct of_device_id exynos_ppmu_id_match[] = {
492
{
493
.compatible = "samsung,exynos-ppmu",
494
.data = (void *)EXYNOS_TYPE_PPMU,
495
}, {
496
.compatible = "samsung,exynos-ppmu-v2",
497
.data = (void *)EXYNOS_TYPE_PPMU_V2,
498
},
499
{ /* sentinel */ },
500
};
501
MODULE_DEVICE_TABLE(of, exynos_ppmu_id_match);
502
503
static int of_get_devfreq_events(struct device_node *np,
504
struct exynos_ppmu *info)
505
{
506
struct devfreq_event_desc *desc;
507
struct device *dev = info->dev;
508
struct device_node *events_np, *node;
509
int i, j, count;
510
int ret;
511
512
events_np = of_get_child_by_name(np, "events");
513
if (!events_np) {
514
dev_err(dev,
515
"failed to get child node of devfreq-event devices\n");
516
return -EINVAL;
517
}
518
519
count = of_get_child_count(events_np);
520
desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
521
if (!desc) {
522
of_node_put(events_np);
523
return -ENOMEM;
524
}
525
info->num_events = count;
526
527
info->ppmu_type = (enum exynos_ppmu_type)device_get_match_data(dev);
528
529
j = 0;
530
for_each_child_of_node(events_np, node) {
531
for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) {
532
if (!ppmu_events[i].name)
533
continue;
534
535
if (of_node_name_eq(node, ppmu_events[i].name))
536
break;
537
}
538
539
if (i == ARRAY_SIZE(ppmu_events)) {
540
dev_warn(dev,
541
"don't know how to configure events : %pOFn\n",
542
node);
543
continue;
544
}
545
546
switch (info->ppmu_type) {
547
case EXYNOS_TYPE_PPMU:
548
desc[j].ops = &exynos_ppmu_ops;
549
break;
550
case EXYNOS_TYPE_PPMU_V2:
551
desc[j].ops = &exynos_ppmu_v2_ops;
552
break;
553
}
554
555
desc[j].driver_data = info;
556
557
of_property_read_string(node, "event-name", &desc[j].name);
558
ret = of_property_read_u32(node, "event-data-type",
559
&desc[j].event_type);
560
if (ret) {
561
/* Set the event of proper data type counting.
562
* Check if the data type has been defined in DT,
563
* use default if not.
564
*/
565
if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) {
566
/* Not all registers take the same value for
567
* read+write data count.
568
*/
569
switch (ppmu_events[i].id) {
570
case PPMU_PMNCNT0:
571
case PPMU_PMNCNT1:
572
case PPMU_PMNCNT2:
573
desc[j].event_type = PPMU_V2_RO_DATA_CNT
574
| PPMU_V2_WO_DATA_CNT;
575
break;
576
case PPMU_PMNCNT3:
577
desc[j].event_type =
578
PPMU_V2_EVT3_RW_DATA_CNT;
579
break;
580
}
581
} else {
582
desc[j].event_type = PPMU_RO_DATA_CNT |
583
PPMU_WO_DATA_CNT;
584
}
585
}
586
587
j++;
588
}
589
info->desc = desc;
590
591
of_node_put(events_np);
592
593
return 0;
594
}
595
596
static struct regmap_config exynos_ppmu_regmap_config = {
597
.reg_bits = 32,
598
.val_bits = 32,
599
.reg_stride = 4,
600
};
601
602
static int exynos_ppmu_parse_dt(struct platform_device *pdev,
603
struct exynos_ppmu *info)
604
{
605
struct device *dev = info->dev;
606
struct device_node *np = dev->of_node;
607
struct resource *res;
608
void __iomem *base;
609
int ret = 0;
610
611
if (!np) {
612
dev_err(dev, "failed to find devicetree node\n");
613
return -EINVAL;
614
}
615
616
/* Maps the memory mapped IO to control PPMU register */
617
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
618
if (IS_ERR(base))
619
return PTR_ERR(base);
620
621
exynos_ppmu_regmap_config.max_register = resource_size(res) - 4;
622
info->regmap = devm_regmap_init_mmio(dev, base,
623
&exynos_ppmu_regmap_config);
624
if (IS_ERR(info->regmap)) {
625
dev_err(dev, "failed to initialize regmap\n");
626
return PTR_ERR(info->regmap);
627
}
628
629
info->ppmu.clk = devm_clk_get(dev, "ppmu");
630
if (IS_ERR(info->ppmu.clk)) {
631
info->ppmu.clk = NULL;
632
dev_warn(dev, "cannot get PPMU clock\n");
633
}
634
635
ret = of_get_devfreq_events(np, info);
636
if (ret < 0) {
637
dev_err(dev, "failed to parse exynos ppmu dt node\n");
638
return ret;
639
}
640
641
return 0;
642
}
643
644
static int exynos_ppmu_probe(struct platform_device *pdev)
645
{
646
struct exynos_ppmu *info;
647
struct devfreq_event_dev **edev;
648
struct devfreq_event_desc *desc;
649
int i, ret = 0, size;
650
651
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
652
if (!info)
653
return -ENOMEM;
654
655
info->dev = &pdev->dev;
656
657
/* Parse dt data to get resource */
658
ret = exynos_ppmu_parse_dt(pdev, info);
659
if (ret < 0) {
660
dev_err(&pdev->dev,
661
"failed to parse devicetree for resource\n");
662
return ret;
663
}
664
desc = info->desc;
665
666
size = sizeof(struct devfreq_event_dev *) * info->num_events;
667
info->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
668
if (!info->edev)
669
return -ENOMEM;
670
671
edev = info->edev;
672
platform_set_drvdata(pdev, info);
673
674
for (i = 0; i < info->num_events; i++) {
675
edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]);
676
if (IS_ERR(edev[i])) {
677
dev_err(&pdev->dev,
678
"failed to add devfreq-event device\n");
679
return PTR_ERR(edev[i]);
680
}
681
682
pr_info("exynos-ppmu: new PPMU device registered %s (%s)\n",
683
dev_name(&pdev->dev), desc[i].name);
684
}
685
686
ret = clk_prepare_enable(info->ppmu.clk);
687
if (ret) {
688
dev_err(&pdev->dev, "failed to prepare ppmu clock\n");
689
return ret;
690
}
691
692
return 0;
693
}
694
695
static void exynos_ppmu_remove(struct platform_device *pdev)
696
{
697
struct exynos_ppmu *info = platform_get_drvdata(pdev);
698
699
clk_disable_unprepare(info->ppmu.clk);
700
}
701
702
static struct platform_driver exynos_ppmu_driver = {
703
.probe = exynos_ppmu_probe,
704
.remove = exynos_ppmu_remove,
705
.driver = {
706
.name = "exynos-ppmu",
707
.of_match_table = exynos_ppmu_id_match,
708
},
709
};
710
module_platform_driver(exynos_ppmu_driver);
711
712
MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver");
713
MODULE_AUTHOR("Chanwoo Choi <[email protected]>");
714
MODULE_LICENSE("GPL");
715
716