aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/db8500-prcmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/db8500-prcmu.c')
-rw-r--r--drivers/mfd/db8500-prcmu.c122
1 files changed, 79 insertions, 43 deletions
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 67d8b25d183e..eba03d2329dd 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -38,9 +38,6 @@
38#include <mach/db8500-regs.h> 38#include <mach/db8500-regs.h>
39#include "dbx500-prcmu-regs.h" 39#include "dbx500-prcmu-regs.h"
40 40
41/* Offset for the firmware version within the TCPM */
42#define PRCMU_FW_VERSION_OFFSET 0xA4
43
44/* Index of different voltages to be used when accessing AVSData */ 41/* Index of different voltages to be used when accessing AVSData */
45#define PRCM_AVS_BASE 0x2FC 42#define PRCM_AVS_BASE 0x2FC
46#define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0) 43#define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0)
@@ -2704,21 +2701,43 @@ static struct irq_chip prcmu_irq_chip = {
2704 .irq_unmask = prcmu_irq_unmask, 2701 .irq_unmask = prcmu_irq_unmask,
2705}; 2702};
2706 2703
2707static char *fw_project_name(u8 project) 2704static __init char *fw_project_name(u32 project)
2708{ 2705{
2709 switch (project) { 2706 switch (project) {
2710 case PRCMU_FW_PROJECT_U8500: 2707 case PRCMU_FW_PROJECT_U8500:
2711 return "U8500"; 2708 return "U8500";
2712 case PRCMU_FW_PROJECT_U8500_C2: 2709 case PRCMU_FW_PROJECT_U8400:
2713 return "U8500 C2"; 2710 return "U8400";
2714 case PRCMU_FW_PROJECT_U9500: 2711 case PRCMU_FW_PROJECT_U9500:
2715 return "U9500"; 2712 return "U9500";
2716 case PRCMU_FW_PROJECT_U9500_C2: 2713 case PRCMU_FW_PROJECT_U8500_MBB:
2717 return "U9500 C2"; 2714 return "U8500 MBB";
2715 case PRCMU_FW_PROJECT_U8500_C1:
2716 return "U8500 C1";
2717 case PRCMU_FW_PROJECT_U8500_C2:
2718 return "U8500 C2";
2719 case PRCMU_FW_PROJECT_U8500_C3:
2720 return "U8500 C3";
2721 case PRCMU_FW_PROJECT_U8500_C4:
2722 return "U8500 C4";
2723 case PRCMU_FW_PROJECT_U9500_MBL:
2724 return "U9500 MBL";
2725 case PRCMU_FW_PROJECT_U8500_MBL:
2726 return "U8500 MBL";
2727 case PRCMU_FW_PROJECT_U8500_MBL2:
2728 return "U8500 MBL2";
2718 case PRCMU_FW_PROJECT_U8520: 2729 case PRCMU_FW_PROJECT_U8520:
2719 return "U8520"; 2730 return "U8520 MBL";
2720 case PRCMU_FW_PROJECT_U8420: 2731 case PRCMU_FW_PROJECT_U8420:
2721 return "U8420"; 2732 return "U8420";
2733 case PRCMU_FW_PROJECT_U9540:
2734 return "U9540";
2735 case PRCMU_FW_PROJECT_A9420:
2736 return "A9420";
2737 case PRCMU_FW_PROJECT_L8540:
2738 return "L8540";
2739 case PRCMU_FW_PROJECT_L8580:
2740 return "L8580";
2722 default: 2741 default:
2723 return "Unknown"; 2742 return "Unknown";
2724 } 2743 }
@@ -2759,37 +2778,44 @@ static int db8500_irq_init(struct device_node *np)
2759 return 0; 2778 return 0;
2760} 2779}
2761 2780
2762void __init db8500_prcmu_early_init(void) 2781static void dbx500_fw_version_init(struct platform_device *pdev,
2782 u32 version_offset)
2763{ 2783{
2764 if (cpu_is_u8500v2() || cpu_is_u9540()) { 2784 struct resource *res;
2765 void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); 2785 void __iomem *tcpm_base;
2766
2767 if (tcpm_base != NULL) {
2768 u32 version;
2769 version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
2770 fw_info.version.project = version & 0xFF;
2771 fw_info.version.api_version = (version >> 8) & 0xFF;
2772 fw_info.version.func_version = (version >> 16) & 0xFF;
2773 fw_info.version.errata = (version >> 24) & 0xFF;
2774 fw_info.valid = true;
2775 pr_info("PRCMU firmware: %s, version %d.%d.%d\n",
2776 fw_project_name(fw_info.version.project),
2777 (version >> 8) & 0xFF, (version >> 16) & 0xFF,
2778 (version >> 24) & 0xFF);
2779 iounmap(tcpm_base);
2780 }
2781 2786
2782 if (cpu_is_u9540()) 2787 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
2783 tcdm_base = ioremap_nocache(U8500_PRCMU_TCDM_BASE, 2788 "prcmu-tcpm");
2784 SZ_4K + SZ_8K) + SZ_8K; 2789 if (!res) {
2785 else 2790 dev_err(&pdev->dev,
2786 tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); 2791 "Error: no prcmu tcpm memory region provided\n");
2787 } else { 2792 return;
2788 pr_err("prcmu: Unsupported chip version\n"); 2793 }
2789 BUG(); 2794 tcpm_base = ioremap(res->start, resource_size(res));
2795 if (tcpm_base != NULL) {
2796 u32 version;
2797
2798 version = readl(tcpm_base + version_offset);
2799 fw_info.version.project = (version & 0xFF);
2800 fw_info.version.api_version = (version >> 8) & 0xFF;
2801 fw_info.version.func_version = (version >> 16) & 0xFF;
2802 fw_info.version.errata = (version >> 24) & 0xFF;
2803 strncpy(fw_info.version.project_name,
2804 fw_project_name(fw_info.version.project),
2805 PRCMU_FW_PROJECT_NAME_LEN);
2806 fw_info.valid = true;
2807 pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n",
2808 fw_info.version.project_name,
2809 fw_info.version.project,
2810 fw_info.version.api_version,
2811 fw_info.version.func_version,
2812 fw_info.version.errata);
2813 iounmap(tcpm_base);
2790 } 2814 }
2791 tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE); 2815}
2792 2816
2817void __init db8500_prcmu_early_init(void)
2818{
2793 spin_lock_init(&mb0_transfer.lock); 2819 spin_lock_init(&mb0_transfer.lock);
2794 spin_lock_init(&mb0_transfer.dbb_irqs_lock); 2820 spin_lock_init(&mb0_transfer.dbb_irqs_lock);
2795 mutex_init(&mb0_transfer.ac_wake_lock); 2821 mutex_init(&mb0_transfer.ac_wake_lock);
@@ -3099,20 +3125,30 @@ static void db8500_prcmu_update_cpufreq(void)
3099 */ 3125 */
3100static int db8500_prcmu_probe(struct platform_device *pdev) 3126static int db8500_prcmu_probe(struct platform_device *pdev)
3101{ 3127{
3102 struct ab8500_platform_data *ab8500_platdata = pdev->dev.platform_data;
3103 struct device_node *np = pdev->dev.of_node; 3128 struct device_node *np = pdev->dev.of_node;
3129 struct prcmu_pdata *pdata = dev_get_platdata(&pdev->dev);
3104 int irq = 0, err = 0, i; 3130 int irq = 0, err = 0, i;
3131 struct resource *res;
3105 3132
3106 init_prcm_registers(); 3133 init_prcm_registers();
3107 3134
3135 dbx500_fw_version_init(pdev, pdata->version_offset);
3136 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
3137 if (!res) {
3138 dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
3139 return -ENOENT;
3140 }
3141 tcdm_base = devm_ioremap(&pdev->dev, res->start,
3142 resource_size(res));
3143
3108 /* Clean up the mailbox interrupts after pre-kernel code. */ 3144 /* Clean up the mailbox interrupts after pre-kernel code. */
3109 writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR); 3145 writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
3110 3146
3111 if (np) 3147 irq = platform_get_irq(pdev, 0);
3112 irq = platform_get_irq(pdev, 0); 3148 if (irq <= 0) {
3113 3149 dev_err(&pdev->dev, "no prcmu irq provided\n");
3114 if (!np || irq <= 0) 3150 return -ENOENT;
3115 irq = IRQ_DB8500_PRCMU1; 3151 }
3116 3152
3117 err = request_threaded_irq(irq, prcmu_irq_handler, 3153 err = request_threaded_irq(irq, prcmu_irq_handler,
3118 prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL); 3154 prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
@@ -3126,7 +3162,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
3126 3162
3127 for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) { 3163 for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) {
3128 if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) { 3164 if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) {
3129 db8500_prcmu_devs[i].platform_data = ab8500_platdata; 3165 db8500_prcmu_devs[i].platform_data = pdata->ab_platdata;
3130 db8500_prcmu_devs[i].pdata_size = sizeof(struct ab8500_platform_data); 3166 db8500_prcmu_devs[i].pdata_size = sizeof(struct ab8500_platform_data);
3131 } 3167 }
3132 } 3168 }