0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 #include <linux/cpufreq.h>
0045 #include <linux/delay.h>
0046 #include <linux/interrupt.h>
0047 #include <linux/io.h>
0048 #include <linux/module.h>
0049 #include <linux/of_address.h>
0050 #include <linux/platform_device.h>
0051 #include <linux/semaphore.h>
0052
0053
0054 #define AVS_MAX_CMD_ARGS 4
0055
0056
0057
0058
0059
0060 #define AVS_PARAM_MULT(x) ((x) < AVS_MAX_CMD_ARGS ? (x) : 0)
0061
0062
0063 #define AVS_MBOX_COMMAND 0x00
0064 #define AVS_MBOX_STATUS 0x04
0065 #define AVS_MBOX_VOLTAGE0 0x08
0066 #define AVS_MBOX_TEMP0 0x0c
0067 #define AVS_MBOX_PV0 0x10
0068 #define AVS_MBOX_MV0 0x14
0069 #define AVS_MBOX_PARAM(x) (0x18 + AVS_PARAM_MULT(x) * sizeof(u32))
0070 #define AVS_MBOX_REVISION 0x28
0071 #define AVS_MBOX_PSTATE 0x2c
0072 #define AVS_MBOX_HEARTBEAT 0x30
0073 #define AVS_MBOX_MAGIC 0x34
0074 #define AVS_MBOX_SIGMA_HVT 0x38
0075 #define AVS_MBOX_SIGMA_SVT 0x3c
0076 #define AVS_MBOX_VOLTAGE1 0x40
0077 #define AVS_MBOX_TEMP1 0x44
0078 #define AVS_MBOX_PV1 0x48
0079 #define AVS_MBOX_MV1 0x4c
0080 #define AVS_MBOX_FREQUENCY 0x50
0081
0082
0083 #define AVS_CMD_AVAILABLE 0x00
0084 #define AVS_CMD_DISABLE 0x10
0085 #define AVS_CMD_ENABLE 0x11
0086 #define AVS_CMD_S2_ENTER 0x12
0087 #define AVS_CMD_S2_EXIT 0x13
0088 #define AVS_CMD_BBM_ENTER 0x14
0089 #define AVS_CMD_BBM_EXIT 0x15
0090 #define AVS_CMD_S3_ENTER 0x16
0091 #define AVS_CMD_S3_EXIT 0x17
0092 #define AVS_CMD_BALANCE 0x18
0093
0094 #define AVS_CMD_GET_PMAP 0x30
0095 #define AVS_CMD_SET_PMAP 0x31
0096 #define AVS_CMD_GET_PSTATE 0x40
0097 #define AVS_CMD_SET_PSTATE 0x41
0098
0099
0100 #define AVS_MODE_AVS 0x0
0101 #define AVS_MODE_DFS 0x1
0102 #define AVS_MODE_DVS 0x2
0103 #define AVS_MODE_DVFS 0x3
0104
0105
0106
0107
0108
0109 #define NDIV_INT_SHIFT 0
0110 #define NDIV_INT_MASK 0x3ff
0111 #define PDIV_SHIFT 10
0112 #define PDIV_MASK 0xf
0113 #define MDIV_P0_SHIFT 16
0114 #define MDIV_P0_MASK 0xff
0115
0116
0117
0118
0119 #define MDIV_P1_SHIFT 0
0120 #define MDIV_P1_MASK 0xff
0121 #define MDIV_P2_SHIFT 8
0122 #define MDIV_P2_MASK 0xff
0123 #define MDIV_P3_SHIFT 16
0124 #define MDIV_P3_MASK 0xff
0125 #define MDIV_P4_SHIFT 24
0126 #define MDIV_P4_MASK 0xff
0127
0128
0129 #define AVS_PSTATE_P0 0x0
0130 #define AVS_PSTATE_P1 0x1
0131 #define AVS_PSTATE_P2 0x2
0132 #define AVS_PSTATE_P3 0x3
0133 #define AVS_PSTATE_P4 0x4
0134 #define AVS_PSTATE_MAX AVS_PSTATE_P4
0135
0136
0137 #define AVS_CPU_L2_SET0 0x04
0138 #define AVS_CPU_L2_INT_MASK BIT(31)
0139
0140
0141 #define AVS_STATUS_CLEAR 0x00
0142
0143 #define AVS_STATUS_SUCCESS 0xf0
0144
0145 #define AVS_STATUS_FAILURE 0xff
0146
0147 #define AVS_STATUS_INVALID 0xf1
0148
0149 #define AVS_STATUS_NO_SUPP 0xf2
0150
0151 #define AVS_STATUS_NO_MAP 0xf3
0152
0153 #define AVS_STATUS_MAP_SET 0xf4
0154
0155 #define AVS_STATUS_MAX 0xff
0156
0157
0158 #define AVS_LOOP_LIMIT 10000
0159 #define AVS_TIMEOUT 300
0160 #define AVS_FIRMWARE_MAGIC 0xa11600d1
0161
0162 #define BRCM_AVS_CPUFREQ_PREFIX "brcmstb-avs"
0163 #define BRCM_AVS_CPUFREQ_NAME BRCM_AVS_CPUFREQ_PREFIX "-cpufreq"
0164 #define BRCM_AVS_CPU_DATA "brcm,avs-cpu-data-mem"
0165 #define BRCM_AVS_CPU_INTR "brcm,avs-cpu-l2-intr"
0166 #define BRCM_AVS_HOST_INTR "sw_intr"
0167
0168 struct pmap {
0169 unsigned int mode;
0170 unsigned int p1;
0171 unsigned int p2;
0172 unsigned int state;
0173 };
0174
0175 struct private_data {
0176 void __iomem *base;
0177 void __iomem *avs_intr_base;
0178 struct device *dev;
0179 struct completion done;
0180 struct semaphore sem;
0181 struct pmap pmap;
0182 int host_irq;
0183 };
0184
0185 static void __iomem *__map_region(const char *name)
0186 {
0187 struct device_node *np;
0188 void __iomem *ptr;
0189
0190 np = of_find_compatible_node(NULL, NULL, name);
0191 if (!np)
0192 return NULL;
0193
0194 ptr = of_iomap(np, 0);
0195 of_node_put(np);
0196
0197 return ptr;
0198 }
0199
0200 static unsigned long wait_for_avs_command(struct private_data *priv,
0201 unsigned long timeout)
0202 {
0203 unsigned long time_left = 0;
0204 u32 val;
0205
0206
0207 if (priv->host_irq >= 0)
0208 return wait_for_completion_timeout(&priv->done,
0209 msecs_to_jiffies(timeout));
0210
0211
0212 do {
0213 time_left = timeout;
0214 val = readl(priv->base + AVS_MBOX_STATUS);
0215 if (val)
0216 break;
0217
0218 usleep_range(1000, 2000);
0219 } while (--timeout);
0220
0221 return time_left;
0222 }
0223
0224 static int __issue_avs_command(struct private_data *priv, unsigned int cmd,
0225 unsigned int num_in, unsigned int num_out,
0226 u32 args[])
0227 {
0228 void __iomem *base = priv->base;
0229 unsigned long time_left;
0230 unsigned int i;
0231 int ret;
0232 u32 val;
0233
0234 ret = down_interruptible(&priv->sem);
0235 if (ret)
0236 return ret;
0237
0238
0239
0240
0241
0242
0243 for (i = 0, val = 1; val != 0 && i < AVS_LOOP_LIMIT; i++)
0244 val = readl(base + AVS_MBOX_COMMAND);
0245
0246
0247 if (i == AVS_LOOP_LIMIT) {
0248 ret = -EAGAIN;
0249 goto out;
0250 }
0251
0252
0253 writel(AVS_STATUS_CLEAR, base + AVS_MBOX_STATUS);
0254
0255
0256 for (i = 0; i < num_in; i++)
0257 writel(args[i], base + AVS_MBOX_PARAM(i));
0258
0259
0260 reinit_completion(&priv->done);
0261
0262
0263 writel(cmd, base + AVS_MBOX_COMMAND);
0264 writel(AVS_CPU_L2_INT_MASK, priv->avs_intr_base + AVS_CPU_L2_SET0);
0265
0266
0267 time_left = wait_for_avs_command(priv, AVS_TIMEOUT);
0268
0269
0270
0271
0272
0273
0274 val = readl(base + AVS_MBOX_STATUS);
0275 if (time_left == 0 || val == 0 || val > AVS_STATUS_MAX) {
0276 dev_err(priv->dev, "AVS command %#x didn't complete in time\n",
0277 cmd);
0278 dev_err(priv->dev, " Time left: %u ms, AVS status: %#x\n",
0279 jiffies_to_msecs(time_left), val);
0280 ret = -ETIMEDOUT;
0281 goto out;
0282 }
0283
0284
0285 for (i = 0; i < num_out; i++)
0286 args[i] = readl(base + AVS_MBOX_PARAM(i));
0287
0288
0289 writel(AVS_STATUS_CLEAR, base + AVS_MBOX_STATUS);
0290
0291
0292 switch (val) {
0293 case AVS_STATUS_INVALID:
0294 ret = -EINVAL;
0295 break;
0296 case AVS_STATUS_NO_SUPP:
0297 ret = -ENOTSUPP;
0298 break;
0299 case AVS_STATUS_NO_MAP:
0300 ret = -ENOENT;
0301 break;
0302 case AVS_STATUS_MAP_SET:
0303 ret = -EEXIST;
0304 break;
0305 case AVS_STATUS_FAILURE:
0306 ret = -EIO;
0307 break;
0308 }
0309
0310 out:
0311 up(&priv->sem);
0312
0313 return ret;
0314 }
0315
0316 static irqreturn_t irq_handler(int irq, void *data)
0317 {
0318 struct private_data *priv = data;
0319
0320
0321 complete(&priv->done);
0322
0323 return IRQ_HANDLED;
0324 }
0325
0326 static char *brcm_avs_mode_to_string(unsigned int mode)
0327 {
0328 switch (mode) {
0329 case AVS_MODE_AVS:
0330 return "AVS";
0331 case AVS_MODE_DFS:
0332 return "DFS";
0333 case AVS_MODE_DVS:
0334 return "DVS";
0335 case AVS_MODE_DVFS:
0336 return "DVFS";
0337 }
0338 return NULL;
0339 }
0340
0341 static void brcm_avs_parse_p1(u32 p1, unsigned int *mdiv_p0, unsigned int *pdiv,
0342 unsigned int *ndiv)
0343 {
0344 *mdiv_p0 = (p1 >> MDIV_P0_SHIFT) & MDIV_P0_MASK;
0345 *pdiv = (p1 >> PDIV_SHIFT) & PDIV_MASK;
0346 *ndiv = (p1 >> NDIV_INT_SHIFT) & NDIV_INT_MASK;
0347 }
0348
0349 static void brcm_avs_parse_p2(u32 p2, unsigned int *mdiv_p1,
0350 unsigned int *mdiv_p2, unsigned int *mdiv_p3,
0351 unsigned int *mdiv_p4)
0352 {
0353 *mdiv_p4 = (p2 >> MDIV_P4_SHIFT) & MDIV_P4_MASK;
0354 *mdiv_p3 = (p2 >> MDIV_P3_SHIFT) & MDIV_P3_MASK;
0355 *mdiv_p2 = (p2 >> MDIV_P2_SHIFT) & MDIV_P2_MASK;
0356 *mdiv_p1 = (p2 >> MDIV_P1_SHIFT) & MDIV_P1_MASK;
0357 }
0358
0359 static int brcm_avs_get_pmap(struct private_data *priv, struct pmap *pmap)
0360 {
0361 u32 args[AVS_MAX_CMD_ARGS];
0362 int ret;
0363
0364 ret = __issue_avs_command(priv, AVS_CMD_GET_PMAP, 0, 4, args);
0365 if (ret || !pmap)
0366 return ret;
0367
0368 pmap->mode = args[0];
0369 pmap->p1 = args[1];
0370 pmap->p2 = args[2];
0371 pmap->state = args[3];
0372
0373 return 0;
0374 }
0375
0376 static int brcm_avs_set_pmap(struct private_data *priv, struct pmap *pmap)
0377 {
0378 u32 args[AVS_MAX_CMD_ARGS];
0379
0380 args[0] = pmap->mode;
0381 args[1] = pmap->p1;
0382 args[2] = pmap->p2;
0383 args[3] = pmap->state;
0384
0385 return __issue_avs_command(priv, AVS_CMD_SET_PMAP, 4, 0, args);
0386 }
0387
0388 static int brcm_avs_get_pstate(struct private_data *priv, unsigned int *pstate)
0389 {
0390 u32 args[AVS_MAX_CMD_ARGS];
0391 int ret;
0392
0393 ret = __issue_avs_command(priv, AVS_CMD_GET_PSTATE, 0, 1, args);
0394 if (ret)
0395 return ret;
0396 *pstate = args[0];
0397
0398 return 0;
0399 }
0400
0401 static int brcm_avs_set_pstate(struct private_data *priv, unsigned int pstate)
0402 {
0403 u32 args[AVS_MAX_CMD_ARGS];
0404
0405 args[0] = pstate;
0406
0407 return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, 1, 0, args);
0408
0409 }
0410
0411 static u32 brcm_avs_get_voltage(void __iomem *base)
0412 {
0413 return readl(base + AVS_MBOX_VOLTAGE1);
0414 }
0415
0416 static u32 brcm_avs_get_frequency(void __iomem *base)
0417 {
0418 return readl(base + AVS_MBOX_FREQUENCY) * 1000;
0419 }
0420
0421
0422
0423
0424
0425 static struct cpufreq_frequency_table *
0426 brcm_avs_get_freq_table(struct device *dev, struct private_data *priv)
0427 {
0428 struct cpufreq_frequency_table *table;
0429 unsigned int pstate;
0430 int i, ret;
0431
0432
0433 ret = brcm_avs_get_pstate(priv, &pstate);
0434 if (ret)
0435 return ERR_PTR(ret);
0436
0437 table = devm_kcalloc(dev, AVS_PSTATE_MAX + 1, sizeof(*table),
0438 GFP_KERNEL);
0439 if (!table)
0440 return ERR_PTR(-ENOMEM);
0441
0442 for (i = AVS_PSTATE_P0; i <= AVS_PSTATE_MAX; i++) {
0443 ret = brcm_avs_set_pstate(priv, i);
0444 if (ret)
0445 return ERR_PTR(ret);
0446 table[i].frequency = brcm_avs_get_frequency(priv->base);
0447 table[i].driver_data = i;
0448 }
0449 table[i].frequency = CPUFREQ_TABLE_END;
0450
0451
0452 ret = brcm_avs_set_pstate(priv, pstate);
0453 if (ret)
0454 return ERR_PTR(ret);
0455
0456 return table;
0457 }
0458
0459
0460
0461
0462
0463
0464
0465 static bool brcm_avs_is_firmware_loaded(struct private_data *priv)
0466 {
0467 u32 magic;
0468 int rc;
0469
0470 rc = brcm_avs_get_pmap(priv, NULL);
0471 magic = readl(priv->base + AVS_MBOX_MAGIC);
0472
0473 return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) ||
0474 (rc != -EINVAL));
0475 }
0476
0477 static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
0478 {
0479 struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
0480 struct private_data *priv = policy->driver_data;
0481
0482 cpufreq_cpu_put(policy);
0483
0484 return brcm_avs_get_frequency(priv->base);
0485 }
0486
0487 static int brcm_avs_target_index(struct cpufreq_policy *policy,
0488 unsigned int index)
0489 {
0490 return brcm_avs_set_pstate(policy->driver_data,
0491 policy->freq_table[index].driver_data);
0492 }
0493
0494 static int brcm_avs_suspend(struct cpufreq_policy *policy)
0495 {
0496 struct private_data *priv = policy->driver_data;
0497 int ret;
0498
0499 ret = brcm_avs_get_pmap(priv, &priv->pmap);
0500 if (ret)
0501 return ret;
0502
0503
0504
0505
0506
0507
0508
0509 ret = brcm_avs_get_pstate(priv, &priv->pmap.state);
0510 if (ret)
0511 return ret;
0512
0513
0514 (void)__issue_avs_command(priv, AVS_CMD_S2_ENTER, 0, 0, NULL);
0515
0516 return 0;
0517 }
0518
0519 static int brcm_avs_resume(struct cpufreq_policy *policy)
0520 {
0521 struct private_data *priv = policy->driver_data;
0522 int ret;
0523
0524
0525 (void)__issue_avs_command(priv, AVS_CMD_S2_EXIT, 0, 0, NULL);
0526
0527 ret = brcm_avs_set_pmap(priv, &priv->pmap);
0528 if (ret == -EEXIST) {
0529 struct platform_device *pdev = cpufreq_get_driver_data();
0530 struct device *dev = &pdev->dev;
0531
0532 dev_warn(dev, "PMAP was already set\n");
0533 ret = 0;
0534 }
0535
0536 return ret;
0537 }
0538
0539
0540
0541
0542
0543
0544 static int brcm_avs_prepare_init(struct platform_device *pdev)
0545 {
0546 struct private_data *priv;
0547 struct device *dev;
0548 int ret;
0549
0550 dev = &pdev->dev;
0551 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0552 if (!priv)
0553 return -ENOMEM;
0554
0555 priv->dev = dev;
0556 sema_init(&priv->sem, 1);
0557 init_completion(&priv->done);
0558 platform_set_drvdata(pdev, priv);
0559
0560 priv->base = __map_region(BRCM_AVS_CPU_DATA);
0561 if (!priv->base) {
0562 dev_err(dev, "Couldn't find property %s in device tree.\n",
0563 BRCM_AVS_CPU_DATA);
0564 return -ENOENT;
0565 }
0566
0567 priv->avs_intr_base = __map_region(BRCM_AVS_CPU_INTR);
0568 if (!priv->avs_intr_base) {
0569 dev_err(dev, "Couldn't find property %s in device tree.\n",
0570 BRCM_AVS_CPU_INTR);
0571 ret = -ENOENT;
0572 goto unmap_base;
0573 }
0574
0575 priv->host_irq = platform_get_irq_byname(pdev, BRCM_AVS_HOST_INTR);
0576
0577 ret = devm_request_irq(dev, priv->host_irq, irq_handler,
0578 IRQF_TRIGGER_RISING,
0579 BRCM_AVS_HOST_INTR, priv);
0580 if (ret && priv->host_irq >= 0) {
0581 dev_err(dev, "IRQ request failed: %s (%d) -- %d\n",
0582 BRCM_AVS_HOST_INTR, priv->host_irq, ret);
0583 goto unmap_intr_base;
0584 }
0585
0586 if (brcm_avs_is_firmware_loaded(priv))
0587 return 0;
0588
0589 dev_err(dev, "AVS firmware is not loaded or doesn't support DVFS\n");
0590 ret = -ENODEV;
0591
0592 unmap_intr_base:
0593 iounmap(priv->avs_intr_base);
0594 unmap_base:
0595 iounmap(priv->base);
0596
0597 return ret;
0598 }
0599
0600 static void brcm_avs_prepare_uninit(struct platform_device *pdev)
0601 {
0602 struct private_data *priv;
0603
0604 priv = platform_get_drvdata(pdev);
0605
0606 iounmap(priv->avs_intr_base);
0607 iounmap(priv->base);
0608 }
0609
0610 static int brcm_avs_cpufreq_init(struct cpufreq_policy *policy)
0611 {
0612 struct cpufreq_frequency_table *freq_table;
0613 struct platform_device *pdev;
0614 struct private_data *priv;
0615 struct device *dev;
0616 int ret;
0617
0618 pdev = cpufreq_get_driver_data();
0619 priv = platform_get_drvdata(pdev);
0620 policy->driver_data = priv;
0621 dev = &pdev->dev;
0622
0623 freq_table = brcm_avs_get_freq_table(dev, priv);
0624 if (IS_ERR(freq_table)) {
0625 ret = PTR_ERR(freq_table);
0626 dev_err(dev, "Couldn't determine frequency table (%d).\n", ret);
0627 return ret;
0628 }
0629
0630 policy->freq_table = freq_table;
0631
0632
0633 cpumask_setall(policy->cpus);
0634
0635 ret = __issue_avs_command(priv, AVS_CMD_ENABLE, 0, 0, NULL);
0636 if (!ret) {
0637 unsigned int pstate;
0638
0639 ret = brcm_avs_get_pstate(priv, &pstate);
0640 if (!ret) {
0641 policy->cur = freq_table[pstate].frequency;
0642 dev_info(dev, "registered\n");
0643 return 0;
0644 }
0645 }
0646
0647 dev_err(dev, "couldn't initialize driver (%d)\n", ret);
0648
0649 return ret;
0650 }
0651
0652 static ssize_t show_brcm_avs_pstate(struct cpufreq_policy *policy, char *buf)
0653 {
0654 struct private_data *priv = policy->driver_data;
0655 unsigned int pstate;
0656
0657 if (brcm_avs_get_pstate(priv, &pstate))
0658 return sprintf(buf, "<unknown>\n");
0659
0660 return sprintf(buf, "%u\n", pstate);
0661 }
0662
0663 static ssize_t show_brcm_avs_mode(struct cpufreq_policy *policy, char *buf)
0664 {
0665 struct private_data *priv = policy->driver_data;
0666 struct pmap pmap;
0667
0668 if (brcm_avs_get_pmap(priv, &pmap))
0669 return sprintf(buf, "<unknown>\n");
0670
0671 return sprintf(buf, "%s %u\n", brcm_avs_mode_to_string(pmap.mode),
0672 pmap.mode);
0673 }
0674
0675 static ssize_t show_brcm_avs_pmap(struct cpufreq_policy *policy, char *buf)
0676 {
0677 unsigned int mdiv_p0, mdiv_p1, mdiv_p2, mdiv_p3, mdiv_p4;
0678 struct private_data *priv = policy->driver_data;
0679 unsigned int ndiv, pdiv;
0680 struct pmap pmap;
0681
0682 if (brcm_avs_get_pmap(priv, &pmap))
0683 return sprintf(buf, "<unknown>\n");
0684
0685 brcm_avs_parse_p1(pmap.p1, &mdiv_p0, &pdiv, &ndiv);
0686 brcm_avs_parse_p2(pmap.p2, &mdiv_p1, &mdiv_p2, &mdiv_p3, &mdiv_p4);
0687
0688 return sprintf(buf, "0x%08x 0x%08x %u %u %u %u %u %u %u %u %u\n",
0689 pmap.p1, pmap.p2, ndiv, pdiv, mdiv_p0, mdiv_p1, mdiv_p2,
0690 mdiv_p3, mdiv_p4, pmap.mode, pmap.state);
0691 }
0692
0693 static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf)
0694 {
0695 struct private_data *priv = policy->driver_data;
0696
0697 return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base));
0698 }
0699
0700 static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf)
0701 {
0702 struct private_data *priv = policy->driver_data;
0703
0704 return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base));
0705 }
0706
0707 cpufreq_freq_attr_ro(brcm_avs_pstate);
0708 cpufreq_freq_attr_ro(brcm_avs_mode);
0709 cpufreq_freq_attr_ro(brcm_avs_pmap);
0710 cpufreq_freq_attr_ro(brcm_avs_voltage);
0711 cpufreq_freq_attr_ro(brcm_avs_frequency);
0712
0713 static struct freq_attr *brcm_avs_cpufreq_attr[] = {
0714 &cpufreq_freq_attr_scaling_available_freqs,
0715 &brcm_avs_pstate,
0716 &brcm_avs_mode,
0717 &brcm_avs_pmap,
0718 &brcm_avs_voltage,
0719 &brcm_avs_frequency,
0720 NULL
0721 };
0722
0723 static struct cpufreq_driver brcm_avs_driver = {
0724 .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
0725 .verify = cpufreq_generic_frequency_table_verify,
0726 .target_index = brcm_avs_target_index,
0727 .get = brcm_avs_cpufreq_get,
0728 .suspend = brcm_avs_suspend,
0729 .resume = brcm_avs_resume,
0730 .init = brcm_avs_cpufreq_init,
0731 .attr = brcm_avs_cpufreq_attr,
0732 .name = BRCM_AVS_CPUFREQ_PREFIX,
0733 };
0734
0735 static int brcm_avs_cpufreq_probe(struct platform_device *pdev)
0736 {
0737 int ret;
0738
0739 ret = brcm_avs_prepare_init(pdev);
0740 if (ret)
0741 return ret;
0742
0743 brcm_avs_driver.driver_data = pdev;
0744
0745 ret = cpufreq_register_driver(&brcm_avs_driver);
0746 if (ret)
0747 brcm_avs_prepare_uninit(pdev);
0748
0749 return ret;
0750 }
0751
0752 static int brcm_avs_cpufreq_remove(struct platform_device *pdev)
0753 {
0754 int ret;
0755
0756 ret = cpufreq_unregister_driver(&brcm_avs_driver);
0757 WARN_ON(ret);
0758
0759 brcm_avs_prepare_uninit(pdev);
0760
0761 return 0;
0762 }
0763
0764 static const struct of_device_id brcm_avs_cpufreq_match[] = {
0765 { .compatible = BRCM_AVS_CPU_DATA },
0766 { }
0767 };
0768 MODULE_DEVICE_TABLE(of, brcm_avs_cpufreq_match);
0769
0770 static struct platform_driver brcm_avs_cpufreq_platdrv = {
0771 .driver = {
0772 .name = BRCM_AVS_CPUFREQ_NAME,
0773 .of_match_table = brcm_avs_cpufreq_match,
0774 },
0775 .probe = brcm_avs_cpufreq_probe,
0776 .remove = brcm_avs_cpufreq_remove,
0777 };
0778 module_platform_driver(brcm_avs_cpufreq_platdrv);
0779
0780 MODULE_AUTHOR("Markus Mayer <mmayer@broadcom.com>");
0781 MODULE_DESCRIPTION("CPUfreq driver for Broadcom STB AVS");
0782 MODULE_LICENSE("GPL");