| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 3 | + * DB8500 PRCM Unit driver |
|---|
| 4 | + * |
|---|
| 2 | 5 | * Copyright (C) STMicroelectronics 2009 |
|---|
| 3 | 6 | * Copyright (C) ST-Ericsson SA 2010 |
|---|
| 4 | 7 | * |
|---|
| 5 | | - * License Terms: GNU General Public License v2 |
|---|
| 6 | 8 | * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com> |
|---|
| 7 | 9 | * Author: Sundar Iyer <sundar.iyer@stericsson.com> |
|---|
| 8 | 10 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> |
|---|
| 9 | 11 | * |
|---|
| 10 | 12 | * U8500 PRCM Unit interface driver |
|---|
| 11 | | - * |
|---|
| 12 | 13 | */ |
|---|
| 13 | | -#include <linux/module.h> |
|---|
| 14 | +#include <linux/init.h> |
|---|
| 15 | +#include <linux/export.h> |
|---|
| 14 | 16 | #include <linux/kernel.h> |
|---|
| 15 | 17 | #include <linux/delay.h> |
|---|
| 16 | 18 | #include <linux/errno.h> |
|---|
| .. | .. |
|---|
| 25 | 27 | #include <linux/bitops.h> |
|---|
| 26 | 28 | #include <linux/fs.h> |
|---|
| 27 | 29 | #include <linux/of.h> |
|---|
| 30 | +#include <linux/of_address.h> |
|---|
| 28 | 31 | #include <linux/of_irq.h> |
|---|
| 29 | 32 | #include <linux/platform_device.h> |
|---|
| 30 | 33 | #include <linux/uaccess.h> |
|---|
| .. | .. |
|---|
| 34 | 37 | #include <linux/regulator/db8500-prcmu.h> |
|---|
| 35 | 38 | #include <linux/regulator/machine.h> |
|---|
| 36 | 39 | #include <linux/platform_data/ux500_wdt.h> |
|---|
| 37 | | -#include <linux/platform_data/db8500_thermal.h> |
|---|
| 38 | 40 | #include "dbx500-prcmu-regs.h" |
|---|
| 39 | 41 | |
|---|
| 40 | 42 | /* Index of different voltages to be used when accessing AVSData */ |
|---|
| .. | .. |
|---|
| 540 | 542 | } |
|---|
| 541 | 543 | }; |
|---|
| 542 | 544 | |
|---|
| 543 | | - |
|---|
| 544 | | -/* |
|---|
| 545 | | -* Used by MCDE to setup all necessary PRCMU registers |
|---|
| 546 | | -*/ |
|---|
| 547 | | -#define PRCMU_RESET_DSIPLL 0x00004000 |
|---|
| 548 | | -#define PRCMU_UNCLAMP_DSIPLL 0x00400800 |
|---|
| 549 | | - |
|---|
| 550 | | -#define PRCMU_CLK_PLL_DIV_SHIFT 0 |
|---|
| 551 | | -#define PRCMU_CLK_PLL_SW_SHIFT 5 |
|---|
| 552 | | -#define PRCMU_CLK_38 (1 << 9) |
|---|
| 553 | | -#define PRCMU_CLK_38_SRC (1 << 10) |
|---|
| 554 | | -#define PRCMU_CLK_38_DIV (1 << 11) |
|---|
| 555 | | - |
|---|
| 556 | | -/* PLLDIV=12, PLLSW=4 (PLLDDR) */ |
|---|
| 557 | | -#define PRCMU_DSI_CLOCK_SETTING 0x0000008C |
|---|
| 558 | | - |
|---|
| 559 | | -/* DPI 50000000 Hz */ |
|---|
| 560 | | -#define PRCMU_DPI_CLOCK_SETTING ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \ |
|---|
| 561 | | - (16 << PRCMU_CLK_PLL_DIV_SHIFT)) |
|---|
| 562 | | -#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000E00 |
|---|
| 563 | | - |
|---|
| 564 | | -/* D=101, N=1, R=4, SELDIV2=0 */ |
|---|
| 565 | | -#define PRCMU_PLLDSI_FREQ_SETTING 0x00040165 |
|---|
| 566 | | - |
|---|
| 567 | | -#define PRCMU_ENABLE_PLLDSI 0x00000001 |
|---|
| 568 | | -#define PRCMU_DISABLE_PLLDSI 0x00000000 |
|---|
| 569 | | -#define PRCMU_RELEASE_RESET_DSS 0x0000400C |
|---|
| 570 | | -#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000202 |
|---|
| 571 | | -/* ESC clk, div0=1, div1=1, div2=3 */ |
|---|
| 572 | | -#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x07030101 |
|---|
| 573 | | -#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00030101 |
|---|
| 574 | | -#define PRCMU_DSI_RESET_SW 0x00000007 |
|---|
| 575 | | - |
|---|
| 576 | | -#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3 |
|---|
| 577 | | - |
|---|
| 578 | | -int db8500_prcmu_enable_dsipll(void) |
|---|
| 579 | | -{ |
|---|
| 580 | | - int i; |
|---|
| 581 | | - |
|---|
| 582 | | - /* Clear DSIPLL_RESETN */ |
|---|
| 583 | | - writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR); |
|---|
| 584 | | - /* Unclamp DSIPLL in/out */ |
|---|
| 585 | | - writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR); |
|---|
| 586 | | - |
|---|
| 587 | | - /* Set DSI PLL FREQ */ |
|---|
| 588 | | - writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ); |
|---|
| 589 | | - writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL); |
|---|
| 590 | | - /* Enable Escape clocks */ |
|---|
| 591 | | - writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV); |
|---|
| 592 | | - |
|---|
| 593 | | - /* Start DSI PLL */ |
|---|
| 594 | | - writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE); |
|---|
| 595 | | - /* Reset DSI PLL */ |
|---|
| 596 | | - writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET); |
|---|
| 597 | | - for (i = 0; i < 10; i++) { |
|---|
| 598 | | - if ((readl(PRCM_PLLDSI_LOCKP) & PRCMU_PLLDSI_LOCKP_LOCKED) |
|---|
| 599 | | - == PRCMU_PLLDSI_LOCKP_LOCKED) |
|---|
| 600 | | - break; |
|---|
| 601 | | - udelay(100); |
|---|
| 602 | | - } |
|---|
| 603 | | - /* Set DSIPLL_RESETN */ |
|---|
| 604 | | - writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET); |
|---|
| 605 | | - return 0; |
|---|
| 606 | | -} |
|---|
| 607 | | - |
|---|
| 608 | | -int db8500_prcmu_disable_dsipll(void) |
|---|
| 609 | | -{ |
|---|
| 610 | | - /* Disable dsi pll */ |
|---|
| 611 | | - writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE); |
|---|
| 612 | | - /* Disable escapeclock */ |
|---|
| 613 | | - writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV); |
|---|
| 614 | | - return 0; |
|---|
| 615 | | -} |
|---|
| 616 | | - |
|---|
| 617 | | -int db8500_prcmu_set_display_clocks(void) |
|---|
| 618 | | -{ |
|---|
| 619 | | - unsigned long flags; |
|---|
| 620 | | - |
|---|
| 621 | | - spin_lock_irqsave(&clk_mgt_lock, flags); |
|---|
| 622 | | - |
|---|
| 623 | | - /* Grab the HW semaphore. */ |
|---|
| 624 | | - while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0) |
|---|
| 625 | | - cpu_relax(); |
|---|
| 626 | | - |
|---|
| 627 | | - writel(PRCMU_DSI_CLOCK_SETTING, prcmu_base + PRCM_HDMICLK_MGT); |
|---|
| 628 | | - writel(PRCMU_DSI_LP_CLOCK_SETTING, prcmu_base + PRCM_TVCLK_MGT); |
|---|
| 629 | | - writel(PRCMU_DPI_CLOCK_SETTING, prcmu_base + PRCM_LCDCLK_MGT); |
|---|
| 630 | | - |
|---|
| 631 | | - /* Release the HW semaphore. */ |
|---|
| 632 | | - writel(0, PRCM_SEM); |
|---|
| 633 | | - |
|---|
| 634 | | - spin_unlock_irqrestore(&clk_mgt_lock, flags); |
|---|
| 635 | | - |
|---|
| 636 | | - return 0; |
|---|
| 637 | | -} |
|---|
| 638 | | - |
|---|
| 639 | 545 | u32 db8500_prcmu_read(unsigned int reg) |
|---|
| 640 | 546 | { |
|---|
| 641 | 547 | return readl(prcmu_base + reg); |
|---|
| .. | .. |
|---|
| 665 | 571 | struct prcmu_fw_version *prcmu_get_fw_version(void) |
|---|
| 666 | 572 | { |
|---|
| 667 | 573 | return fw_info.valid ? &fw_info.version : NULL; |
|---|
| 574 | +} |
|---|
| 575 | + |
|---|
| 576 | +static bool prcmu_is_ulppll_disabled(void) |
|---|
| 577 | +{ |
|---|
| 578 | + struct prcmu_fw_version *ver; |
|---|
| 579 | + |
|---|
| 580 | + ver = prcmu_get_fw_version(); |
|---|
| 581 | + return ver && ver->project == PRCMU_FW_PROJECT_U8420_SYSCLK; |
|---|
| 668 | 582 | } |
|---|
| 669 | 583 | |
|---|
| 670 | 584 | bool prcmu_has_arm_maxopp(void) |
|---|
| .. | .. |
|---|
| 1307 | 1221 | |
|---|
| 1308 | 1222 | static int request_timclk(bool enable) |
|---|
| 1309 | 1223 | { |
|---|
| 1310 | | - u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK); |
|---|
| 1224 | + u32 val; |
|---|
| 1225 | + |
|---|
| 1226 | + /* |
|---|
| 1227 | + * On the U8420_CLKSEL firmware, the ULP (Ultra Low Power) |
|---|
| 1228 | + * PLL is disabled so we cannot use doze mode, this will |
|---|
| 1229 | + * stop the clock on this firmware. |
|---|
| 1230 | + */ |
|---|
| 1231 | + if (prcmu_is_ulppll_disabled()) |
|---|
| 1232 | + val = 0; |
|---|
| 1233 | + else |
|---|
| 1234 | + val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK); |
|---|
| 1311 | 1235 | |
|---|
| 1312 | 1236 | if (!enable) |
|---|
| 1313 | | - val |= PRCM_TCR_STOP_TIMERS; |
|---|
| 1237 | + val |= PRCM_TCR_STOP_TIMERS | |
|---|
| 1238 | + PRCM_TCR_DOZE_MODE | |
|---|
| 1239 | + PRCM_TCR_TENSEL_MASK; |
|---|
| 1240 | + |
|---|
| 1314 | 1241 | writel(val, PRCM_TCR); |
|---|
| 1315 | 1242 | |
|---|
| 1316 | 1243 | return 0; |
|---|
| .. | .. |
|---|
| 1588 | 1515 | switch (divsel) { |
|---|
| 1589 | 1516 | case PRCM_DSI_PLLOUT_SEL_PHI_4: |
|---|
| 1590 | 1517 | div *= 2; |
|---|
| 1518 | + fallthrough; |
|---|
| 1591 | 1519 | case PRCM_DSI_PLLOUT_SEL_PHI_2: |
|---|
| 1592 | 1520 | div *= 2; |
|---|
| 1521 | + fallthrough; |
|---|
| 1593 | 1522 | case PRCM_DSI_PLLOUT_SEL_PHI: |
|---|
| 1594 | 1523 | return pll_rate(PRCM_PLLDSI_FREQ, clock_rate(PRCMU_HDMICLK), |
|---|
| 1595 | 1524 | PLL_RAW) / div; |
|---|
| .. | .. |
|---|
| 1612 | 1541 | if (clock < PRCMU_NUM_REG_CLOCKS) |
|---|
| 1613 | 1542 | return clock_rate(clock); |
|---|
| 1614 | 1543 | else if (clock == PRCMU_TIMCLK) |
|---|
| 1615 | | - return ROOT_CLOCK_RATE / 16; |
|---|
| 1544 | + return prcmu_is_ulppll_disabled() ? |
|---|
| 1545 | + 32768 : ROOT_CLOCK_RATE / 16; |
|---|
| 1616 | 1546 | else if (clock == PRCMU_SYSCLK) |
|---|
| 1617 | 1547 | return ROOT_CLOCK_RATE; |
|---|
| 1618 | 1548 | else if (clock == PRCMU_PLLSOC0) |
|---|
| .. | .. |
|---|
| 1691 | 1621 | return rounded_rate; |
|---|
| 1692 | 1622 | } |
|---|
| 1693 | 1623 | |
|---|
| 1694 | | -static const unsigned long armss_freqs[] = { |
|---|
| 1695 | | - 200000000, |
|---|
| 1696 | | - 400000000, |
|---|
| 1697 | | - 800000000, |
|---|
| 1624 | +static const unsigned long db8500_armss_freqs[] = { |
|---|
| 1625 | + 199680000, |
|---|
| 1626 | + 399360000, |
|---|
| 1627 | + 798720000, |
|---|
| 1698 | 1628 | 998400000 |
|---|
| 1629 | +}; |
|---|
| 1630 | + |
|---|
| 1631 | +/* The DB8520 has slightly higher ARMSS max frequency */ |
|---|
| 1632 | +static const unsigned long db8520_armss_freqs[] = { |
|---|
| 1633 | + 199680000, |
|---|
| 1634 | + 399360000, |
|---|
| 1635 | + 798720000, |
|---|
| 1636 | + 1152000000 |
|---|
| 1699 | 1637 | }; |
|---|
| 1700 | 1638 | |
|---|
| 1701 | 1639 | static long round_armss_rate(unsigned long rate) |
|---|
| 1702 | 1640 | { |
|---|
| 1703 | 1641 | unsigned long freq = 0; |
|---|
| 1642 | + const unsigned long *freqs; |
|---|
| 1643 | + int nfreqs; |
|---|
| 1704 | 1644 | int i; |
|---|
| 1705 | 1645 | |
|---|
| 1646 | + if (fw_info.version.project == PRCMU_FW_PROJECT_U8520) { |
|---|
| 1647 | + freqs = db8520_armss_freqs; |
|---|
| 1648 | + nfreqs = ARRAY_SIZE(db8520_armss_freqs); |
|---|
| 1649 | + } else { |
|---|
| 1650 | + freqs = db8500_armss_freqs; |
|---|
| 1651 | + nfreqs = ARRAY_SIZE(db8500_armss_freqs); |
|---|
| 1652 | + } |
|---|
| 1653 | + |
|---|
| 1706 | 1654 | /* Find the corresponding arm opp from the cpufreq table. */ |
|---|
| 1707 | | - for (i = 0; i < ARRAY_SIZE(armss_freqs); i++) { |
|---|
| 1708 | | - freq = armss_freqs[i]; |
|---|
| 1655 | + for (i = 0; i < nfreqs; i++) { |
|---|
| 1656 | + freq = freqs[i]; |
|---|
| 1709 | 1657 | if (rate <= freq) |
|---|
| 1710 | 1658 | break; |
|---|
| 1711 | 1659 | } |
|---|
| .. | .. |
|---|
| 1850 | 1798 | { |
|---|
| 1851 | 1799 | unsigned long freq; |
|---|
| 1852 | 1800 | u8 opps[] = { ARM_EXTCLK, ARM_50_OPP, ARM_100_OPP, ARM_MAX_OPP }; |
|---|
| 1801 | + const unsigned long *freqs; |
|---|
| 1802 | + int nfreqs; |
|---|
| 1853 | 1803 | int i; |
|---|
| 1854 | 1804 | |
|---|
| 1805 | + if (fw_info.version.project == PRCMU_FW_PROJECT_U8520) { |
|---|
| 1806 | + freqs = db8520_armss_freqs; |
|---|
| 1807 | + nfreqs = ARRAY_SIZE(db8520_armss_freqs); |
|---|
| 1808 | + } else { |
|---|
| 1809 | + freqs = db8500_armss_freqs; |
|---|
| 1810 | + nfreqs = ARRAY_SIZE(db8500_armss_freqs); |
|---|
| 1811 | + } |
|---|
| 1812 | + |
|---|
| 1855 | 1813 | /* Find the corresponding arm opp from the cpufreq table. */ |
|---|
| 1856 | | - for (i = 0; i < ARRAY_SIZE(armss_freqs); i++) { |
|---|
| 1857 | | - freq = armss_freqs[i]; |
|---|
| 1814 | + for (i = 0; i < nfreqs; i++) { |
|---|
| 1815 | + freq = freqs[i]; |
|---|
| 1858 | 1816 | if (rate == freq) |
|---|
| 1859 | 1817 | break; |
|---|
| 1860 | 1818 | } |
|---|
| .. | .. |
|---|
| 2316 | 2274 | * |
|---|
| 2317 | 2275 | * Saves the reset reason code and then sets the APE_SOFTRST register which |
|---|
| 2318 | 2276 | * fires interrupt to fw |
|---|
| 2277 | + * |
|---|
| 2278 | + * @reset_code: The reason for system reset |
|---|
| 2319 | 2279 | */ |
|---|
| 2320 | 2280 | void db8500_prcmu_system_reset(u16 reset_code) |
|---|
| 2321 | 2281 | { |
|---|
| .. | .. |
|---|
| 2613 | 2573 | return "U8520 MBL"; |
|---|
| 2614 | 2574 | case PRCMU_FW_PROJECT_U8420: |
|---|
| 2615 | 2575 | return "U8420"; |
|---|
| 2576 | + case PRCMU_FW_PROJECT_U8420_SYSCLK: |
|---|
| 2577 | + return "U8420-sysclk"; |
|---|
| 2616 | 2578 | case PRCMU_FW_PROJECT_U9540: |
|---|
| 2617 | 2579 | return "U9540"; |
|---|
| 2618 | 2580 | case PRCMU_FW_PROJECT_A9420: |
|---|
| .. | .. |
|---|
| 2660 | 2622 | return 0; |
|---|
| 2661 | 2623 | } |
|---|
| 2662 | 2624 | |
|---|
| 2663 | | -static void dbx500_fw_version_init(struct platform_device *pdev, |
|---|
| 2664 | | - u32 version_offset) |
|---|
| 2625 | +static void dbx500_fw_version_init(struct device_node *np) |
|---|
| 2665 | 2626 | { |
|---|
| 2666 | | - struct resource *res; |
|---|
| 2667 | 2627 | void __iomem *tcpm_base; |
|---|
| 2668 | 2628 | u32 version; |
|---|
| 2669 | 2629 | |
|---|
| 2670 | | - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
|---|
| 2671 | | - "prcmu-tcpm"); |
|---|
| 2672 | | - if (!res) { |
|---|
| 2673 | | - dev_err(&pdev->dev, |
|---|
| 2674 | | - "Error: no prcmu tcpm memory region provided\n"); |
|---|
| 2675 | | - return; |
|---|
| 2676 | | - } |
|---|
| 2677 | | - tcpm_base = ioremap(res->start, resource_size(res)); |
|---|
| 2630 | + tcpm_base = of_iomap(np, 1); |
|---|
| 2678 | 2631 | if (!tcpm_base) { |
|---|
| 2679 | | - dev_err(&pdev->dev, "no prcmu tcpm mem region provided\n"); |
|---|
| 2632 | + pr_err("no prcmu tcpm mem region provided\n"); |
|---|
| 2680 | 2633 | return; |
|---|
| 2681 | 2634 | } |
|---|
| 2682 | 2635 | |
|---|
| 2683 | | - version = readl(tcpm_base + version_offset); |
|---|
| 2636 | + version = readl(tcpm_base + DB8500_PRCMU_FW_VERSION_OFFSET); |
|---|
| 2684 | 2637 | fw_info.version.project = (version & 0xFF); |
|---|
| 2685 | 2638 | fw_info.version.api_version = (version >> 8) & 0xFF; |
|---|
| 2686 | 2639 | fw_info.version.func_version = (version >> 16) & 0xFF; |
|---|
| .. | .. |
|---|
| 2698 | 2651 | iounmap(tcpm_base); |
|---|
| 2699 | 2652 | } |
|---|
| 2700 | 2653 | |
|---|
| 2701 | | -void __init db8500_prcmu_early_init(u32 phy_base, u32 size) |
|---|
| 2654 | +void __init db8500_prcmu_early_init(void) |
|---|
| 2702 | 2655 | { |
|---|
| 2703 | 2656 | /* |
|---|
| 2704 | 2657 | * This is a temporary remap to bring up the clocks. It is |
|---|
| .. | .. |
|---|
| 2707 | 2660 | * clock driver can probe independently. An early initcall will |
|---|
| 2708 | 2661 | * still be needed, but it can be diverted into drivers/clk/ux500. |
|---|
| 2709 | 2662 | */ |
|---|
| 2710 | | - prcmu_base = ioremap(phy_base, size); |
|---|
| 2711 | | - if (!prcmu_base) |
|---|
| 2663 | + struct device_node *np; |
|---|
| 2664 | + |
|---|
| 2665 | + np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu"); |
|---|
| 2666 | + prcmu_base = of_iomap(np, 0); |
|---|
| 2667 | + if (!prcmu_base) { |
|---|
| 2668 | + of_node_put(np); |
|---|
| 2712 | 2669 | pr_err("%s: ioremap() of prcmu registers failed!\n", __func__); |
|---|
| 2670 | + return; |
|---|
| 2671 | + } |
|---|
| 2672 | + dbx500_fw_version_init(np); |
|---|
| 2673 | + of_node_put(np); |
|---|
| 2713 | 2674 | |
|---|
| 2714 | 2675 | spin_lock_init(&mb0_transfer.lock); |
|---|
| 2715 | 2676 | spin_lock_init(&mb0_transfer.dbb_irqs_lock); |
|---|
| .. | .. |
|---|
| 2980 | 2941 | .timeout = 600, /* 10 minutes */ |
|---|
| 2981 | 2942 | .has_28_bits_resolution = true, |
|---|
| 2982 | 2943 | }; |
|---|
| 2983 | | -/* |
|---|
| 2984 | | - * Thermal Sensor |
|---|
| 2985 | | - */ |
|---|
| 2986 | | - |
|---|
| 2987 | | -static struct resource db8500_thsens_resources[] = { |
|---|
| 2988 | | - { |
|---|
| 2989 | | - .name = "IRQ_HOTMON_LOW", |
|---|
| 2990 | | - .start = IRQ_PRCMU_HOTMON_LOW, |
|---|
| 2991 | | - .end = IRQ_PRCMU_HOTMON_LOW, |
|---|
| 2992 | | - .flags = IORESOURCE_IRQ, |
|---|
| 2993 | | - }, |
|---|
| 2994 | | - { |
|---|
| 2995 | | - .name = "IRQ_HOTMON_HIGH", |
|---|
| 2996 | | - .start = IRQ_PRCMU_HOTMON_HIGH, |
|---|
| 2997 | | - .end = IRQ_PRCMU_HOTMON_HIGH, |
|---|
| 2998 | | - .flags = IORESOURCE_IRQ, |
|---|
| 2999 | | - }, |
|---|
| 3000 | | -}; |
|---|
| 3001 | | - |
|---|
| 3002 | | -static struct db8500_thsens_platform_data db8500_thsens_data = { |
|---|
| 3003 | | - .trip_points[0] = { |
|---|
| 3004 | | - .temp = 70000, |
|---|
| 3005 | | - .type = THERMAL_TRIP_ACTIVE, |
|---|
| 3006 | | - .cdev_name = { |
|---|
| 3007 | | - [0] = "thermal-cpufreq-0", |
|---|
| 3008 | | - }, |
|---|
| 3009 | | - }, |
|---|
| 3010 | | - .trip_points[1] = { |
|---|
| 3011 | | - .temp = 75000, |
|---|
| 3012 | | - .type = THERMAL_TRIP_ACTIVE, |
|---|
| 3013 | | - .cdev_name = { |
|---|
| 3014 | | - [0] = "thermal-cpufreq-0", |
|---|
| 3015 | | - }, |
|---|
| 3016 | | - }, |
|---|
| 3017 | | - .trip_points[2] = { |
|---|
| 3018 | | - .temp = 80000, |
|---|
| 3019 | | - .type = THERMAL_TRIP_ACTIVE, |
|---|
| 3020 | | - .cdev_name = { |
|---|
| 3021 | | - [0] = "thermal-cpufreq-0", |
|---|
| 3022 | | - }, |
|---|
| 3023 | | - }, |
|---|
| 3024 | | - .trip_points[3] = { |
|---|
| 3025 | | - .temp = 85000, |
|---|
| 3026 | | - .type = THERMAL_TRIP_CRITICAL, |
|---|
| 3027 | | - }, |
|---|
| 3028 | | - .num_trips = 4, |
|---|
| 3029 | | -}; |
|---|
| 3030 | 2944 | |
|---|
| 3031 | 2945 | static const struct mfd_cell common_prcmu_devs[] = { |
|---|
| 3032 | 2946 | { |
|---|
| .. | .. |
|---|
| 3038 | 2952 | }; |
|---|
| 3039 | 2953 | |
|---|
| 3040 | 2954 | static const struct mfd_cell db8500_prcmu_devs[] = { |
|---|
| 3041 | | - { |
|---|
| 3042 | | - .name = "db8500-prcmu-regulators", |
|---|
| 3043 | | - .of_compatible = "stericsson,db8500-prcmu-regulator", |
|---|
| 3044 | | - .platform_data = &db8500_regulators, |
|---|
| 3045 | | - .pdata_size = sizeof(db8500_regulators), |
|---|
| 3046 | | - }, |
|---|
| 3047 | | - { |
|---|
| 3048 | | - .name = "cpuidle-dbx500", |
|---|
| 3049 | | - .of_compatible = "stericsson,cpuidle-dbx500", |
|---|
| 3050 | | - }, |
|---|
| 3051 | | - { |
|---|
| 3052 | | - .name = "db8500-thermal", |
|---|
| 3053 | | - .num_resources = ARRAY_SIZE(db8500_thsens_resources), |
|---|
| 3054 | | - .resources = db8500_thsens_resources, |
|---|
| 3055 | | - .platform_data = &db8500_thsens_data, |
|---|
| 3056 | | - .pdata_size = sizeof(db8500_thsens_data), |
|---|
| 3057 | | - }, |
|---|
| 2955 | + OF_MFD_CELL("db8500-prcmu-regulators", NULL, |
|---|
| 2956 | + &db8500_regulators, sizeof(db8500_regulators), 0, |
|---|
| 2957 | + "stericsson,db8500-prcmu-regulator"), |
|---|
| 2958 | + OF_MFD_CELL("cpuidle-dbx500", |
|---|
| 2959 | + NULL, NULL, 0, 0, "stericsson,cpuidle-dbx500"), |
|---|
| 2960 | + OF_MFD_CELL("db8500-thermal", |
|---|
| 2961 | + NULL, NULL, 0, 0, "stericsson,db8500-thermal"), |
|---|
| 3058 | 2962 | }; |
|---|
| 3059 | 2963 | |
|---|
| 3060 | 2964 | static int db8500_prcmu_register_ab8500(struct device *parent) |
|---|
| 3061 | 2965 | { |
|---|
| 3062 | 2966 | struct device_node *np; |
|---|
| 3063 | | - struct resource ab8500_resource; |
|---|
| 2967 | + struct resource ab850x_resource; |
|---|
| 3064 | 2968 | const struct mfd_cell ab8500_cell = { |
|---|
| 3065 | 2969 | .name = "ab8500-core", |
|---|
| 3066 | 2970 | .of_compatible = "stericsson,ab8500", |
|---|
| 3067 | 2971 | .id = AB8500_VERSION_AB8500, |
|---|
| 3068 | | - .resources = &ab8500_resource, |
|---|
| 2972 | + .resources = &ab850x_resource, |
|---|
| 3069 | 2973 | .num_resources = 1, |
|---|
| 3070 | 2974 | }; |
|---|
| 2975 | + const struct mfd_cell ab8505_cell = { |
|---|
| 2976 | + .name = "ab8505-core", |
|---|
| 2977 | + .of_compatible = "stericsson,ab8505", |
|---|
| 2978 | + .id = AB8500_VERSION_AB8505, |
|---|
| 2979 | + .resources = &ab850x_resource, |
|---|
| 2980 | + .num_resources = 1, |
|---|
| 2981 | + }; |
|---|
| 2982 | + const struct mfd_cell *ab850x_cell; |
|---|
| 3071 | 2983 | |
|---|
| 3072 | 2984 | if (!parent->of_node) |
|---|
| 3073 | 2985 | return -ENODEV; |
|---|
| 3074 | 2986 | |
|---|
| 3075 | 2987 | /* Look up the device node, sneak the IRQ out of it */ |
|---|
| 3076 | 2988 | for_each_child_of_node(parent->of_node, np) { |
|---|
| 3077 | | - if (of_device_is_compatible(np, ab8500_cell.of_compatible)) |
|---|
| 2989 | + if (of_device_is_compatible(np, ab8500_cell.of_compatible)) { |
|---|
| 2990 | + ab850x_cell = &ab8500_cell; |
|---|
| 3078 | 2991 | break; |
|---|
| 2992 | + } |
|---|
| 2993 | + if (of_device_is_compatible(np, ab8505_cell.of_compatible)) { |
|---|
| 2994 | + ab850x_cell = &ab8505_cell; |
|---|
| 2995 | + break; |
|---|
| 2996 | + } |
|---|
| 3079 | 2997 | } |
|---|
| 3080 | 2998 | if (!np) { |
|---|
| 3081 | | - dev_info(parent, "could not find AB8500 node in the device tree\n"); |
|---|
| 2999 | + dev_info(parent, "could not find AB850X node in the device tree\n"); |
|---|
| 3082 | 3000 | return -ENODEV; |
|---|
| 3083 | 3001 | } |
|---|
| 3084 | | - of_irq_to_resource_table(np, &ab8500_resource, 1); |
|---|
| 3002 | + of_irq_to_resource_table(np, &ab850x_resource, 1); |
|---|
| 3085 | 3003 | |
|---|
| 3086 | | - return mfd_add_devices(parent, 0, &ab8500_cell, 1, NULL, 0, NULL); |
|---|
| 3004 | + return mfd_add_devices(parent, 0, ab850x_cell, 1, NULL, 0, NULL); |
|---|
| 3087 | 3005 | } |
|---|
| 3088 | 3006 | |
|---|
| 3089 | | -/** |
|---|
| 3090 | | - * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic |
|---|
| 3091 | | - * |
|---|
| 3092 | | - */ |
|---|
| 3093 | 3007 | static int db8500_prcmu_probe(struct platform_device *pdev) |
|---|
| 3094 | 3008 | { |
|---|
| 3095 | 3009 | struct device_node *np = pdev->dev.of_node; |
|---|
| .. | .. |
|---|
| 3108 | 3022 | return -ENOMEM; |
|---|
| 3109 | 3023 | } |
|---|
| 3110 | 3024 | init_prcm_registers(); |
|---|
| 3111 | | - dbx500_fw_version_init(pdev, DB8500_PRCMU_FW_VERSION_OFFSET); |
|---|
| 3112 | 3025 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm"); |
|---|
| 3113 | 3026 | if (!res) { |
|---|
| 3114 | 3027 | dev_err(&pdev->dev, "no prcmu tcdm region provided\n"); |
|---|
| .. | .. |
|---|
| 3126 | 3039 | writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR); |
|---|
| 3127 | 3040 | |
|---|
| 3128 | 3041 | irq = platform_get_irq(pdev, 0); |
|---|
| 3129 | | - if (irq <= 0) { |
|---|
| 3130 | | - dev_err(&pdev->dev, "no prcmu irq provided\n"); |
|---|
| 3042 | + if (irq <= 0) |
|---|
| 3131 | 3043 | return irq; |
|---|
| 3132 | | - } |
|---|
| 3133 | 3044 | |
|---|
| 3134 | 3045 | err = request_threaded_irq(irq, prcmu_irq_handler, |
|---|
| 3135 | 3046 | prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL); |
|---|
| .. | .. |
|---|
| 3188 | 3099 | { |
|---|
| 3189 | 3100 | return platform_driver_register(&db8500_prcmu_driver); |
|---|
| 3190 | 3101 | } |
|---|
| 3191 | | - |
|---|
| 3192 | 3102 | core_initcall(db8500_prcmu_init); |
|---|
| 3193 | | - |
|---|
| 3194 | | -MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com>"); |
|---|
| 3195 | | -MODULE_DESCRIPTION("DB8500 PRCM Unit driver"); |
|---|
| 3196 | | -MODULE_LICENSE("GPL v2"); |
|---|