Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
0004  *
0005  * Authors: Inha Song <ideal.song@samsung.com>
0006  *          Sylwester Nawrocki <s.nawrocki@samsung.com>
0007  *
0008  * Samsung Exynos SoC series Low Power Audio Subsystem driver.
0009  *
0010  * This module provides regmap for the Top SFR region and instantiates
0011  * devices for IP blocks like DMAC, I2S, UART.
0012  */
0013 
0014 #include <linux/clk.h>
0015 #include <linux/delay.h>
0016 #include <linux/io.h>
0017 #include <linux/module.h>
0018 #include <linux/of.h>
0019 #include <linux/of_platform.h>
0020 #include <linux/platform_device.h>
0021 #include <linux/pm_runtime.h>
0022 #include <linux/regmap.h>
0023 #include <linux/soc/samsung/exynos-regs-pmu.h>
0024 #include <linux/types.h>
0025 
0026 /* LPASS Top register definitions */
0027 #define SFR_LPASS_CORE_SW_RESET     0x08
0028 #define  LPASS_SB_SW_RESET      BIT(11)
0029 #define  LPASS_UART_SW_RESET        BIT(10)
0030 #define  LPASS_PCM_SW_RESET     BIT(9)
0031 #define  LPASS_I2S_SW_RESET     BIT(8)
0032 #define  LPASS_WDT1_SW_RESET        BIT(4)
0033 #define  LPASS_WDT0_SW_RESET        BIT(3)
0034 #define  LPASS_TIMER_SW_RESET       BIT(2)
0035 #define  LPASS_MEM_SW_RESET     BIT(1)
0036 #define  LPASS_DMA_SW_RESET     BIT(0)
0037 
0038 #define SFR_LPASS_INTR_CA5_MASK     0x48
0039 #define SFR_LPASS_INTR_CPU_MASK     0x58
0040 #define  LPASS_INTR_APM         BIT(9)
0041 #define  LPASS_INTR_MIF         BIT(8)
0042 #define  LPASS_INTR_TIMER       BIT(7)
0043 #define  LPASS_INTR_DMA         BIT(6)
0044 #define  LPASS_INTR_GPIO        BIT(5)
0045 #define  LPASS_INTR_I2S         BIT(4)
0046 #define  LPASS_INTR_PCM         BIT(3)
0047 #define  LPASS_INTR_SLIMBUS     BIT(2)
0048 #define  LPASS_INTR_UART        BIT(1)
0049 #define  LPASS_INTR_SFR         BIT(0)
0050 
0051 struct exynos_lpass {
0052     /* pointer to the LPASS TOP regmap */
0053     struct regmap *top;
0054     struct clk *sfr0_clk;
0055 };
0056 
0057 static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
0058 {
0059     unsigned int val = 0;
0060 
0061     regmap_read(lpass->top, SFR_LPASS_CORE_SW_RESET, &val);
0062 
0063     val &= ~mask;
0064     regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
0065 
0066     usleep_range(100, 150);
0067 
0068     val |= mask;
0069     regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
0070 }
0071 
0072 static void exynos_lpass_enable(struct exynos_lpass *lpass)
0073 {
0074     clk_prepare_enable(lpass->sfr0_clk);
0075 
0076     /* Unmask SFR, DMA and I2S interrupt */
0077     regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK,
0078              LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
0079 
0080     regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK,
0081              LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S |
0082              LPASS_INTR_UART);
0083 
0084     exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET);
0085     exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
0086     exynos_lpass_core_sw_reset(lpass, LPASS_MEM_SW_RESET);
0087     exynos_lpass_core_sw_reset(lpass, LPASS_UART_SW_RESET);
0088 }
0089 
0090 static void exynos_lpass_disable(struct exynos_lpass *lpass)
0091 {
0092     /* Mask any unmasked IP interrupt sources */
0093     regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK, 0);
0094     regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK, 0);
0095 
0096     clk_disable_unprepare(lpass->sfr0_clk);
0097 }
0098 
0099 static const struct regmap_config exynos_lpass_reg_conf = {
0100     .reg_bits   = 32,
0101     .reg_stride = 4,
0102     .val_bits   = 32,
0103     .max_register   = 0xfc,
0104     .fast_io    = true,
0105 };
0106 
0107 static int exynos_lpass_probe(struct platform_device *pdev)
0108 {
0109     struct device *dev = &pdev->dev;
0110     struct exynos_lpass *lpass;
0111     void __iomem *base_top;
0112     struct resource *res;
0113 
0114     lpass = devm_kzalloc(dev, sizeof(*lpass), GFP_KERNEL);
0115     if (!lpass)
0116         return -ENOMEM;
0117 
0118     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0119     base_top = devm_ioremap_resource(dev, res);
0120     if (IS_ERR(base_top))
0121         return PTR_ERR(base_top);
0122 
0123     lpass->sfr0_clk = devm_clk_get(dev, "sfr0_ctrl");
0124     if (IS_ERR(lpass->sfr0_clk))
0125         return PTR_ERR(lpass->sfr0_clk);
0126 
0127     lpass->top = regmap_init_mmio(dev, base_top,
0128                     &exynos_lpass_reg_conf);
0129     if (IS_ERR(lpass->top)) {
0130         dev_err(dev, "LPASS top regmap initialization failed\n");
0131         return PTR_ERR(lpass->top);
0132     }
0133 
0134     platform_set_drvdata(pdev, lpass);
0135     pm_runtime_set_active(dev);
0136     pm_runtime_enable(dev);
0137     exynos_lpass_enable(lpass);
0138 
0139     return devm_of_platform_populate(dev);
0140 }
0141 
0142 static int exynos_lpass_remove(struct platform_device *pdev)
0143 {
0144     struct exynos_lpass *lpass = platform_get_drvdata(pdev);
0145 
0146     exynos_lpass_disable(lpass);
0147     pm_runtime_disable(&pdev->dev);
0148     if (!pm_runtime_status_suspended(&pdev->dev))
0149         exynos_lpass_disable(lpass);
0150     regmap_exit(lpass->top);
0151 
0152     return 0;
0153 }
0154 
0155 static int __maybe_unused exynos_lpass_suspend(struct device *dev)
0156 {
0157     struct exynos_lpass *lpass = dev_get_drvdata(dev);
0158 
0159     exynos_lpass_disable(lpass);
0160 
0161     return 0;
0162 }
0163 
0164 static int __maybe_unused exynos_lpass_resume(struct device *dev)
0165 {
0166     struct exynos_lpass *lpass = dev_get_drvdata(dev);
0167 
0168     exynos_lpass_enable(lpass);
0169 
0170     return 0;
0171 }
0172 
0173 static const struct dev_pm_ops lpass_pm_ops = {
0174     SET_RUNTIME_PM_OPS(exynos_lpass_suspend, exynos_lpass_resume, NULL)
0175     SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0176                      pm_runtime_force_resume)
0177 };
0178 
0179 static const struct of_device_id exynos_lpass_of_match[] = {
0180     { .compatible = "samsung,exynos5433-lpass" },
0181     { },
0182 };
0183 MODULE_DEVICE_TABLE(of, exynos_lpass_of_match);
0184 
0185 static struct platform_driver exynos_lpass_driver = {
0186     .driver = {
0187         .name       = "exynos-lpass",
0188         .pm     = &lpass_pm_ops,
0189         .of_match_table = exynos_lpass_of_match,
0190     },
0191     .probe  = exynos_lpass_probe,
0192     .remove = exynos_lpass_remove,
0193 };
0194 module_platform_driver(exynos_lpass_driver);
0195 
0196 MODULE_DESCRIPTION("Samsung Low Power Audio Subsystem driver");
0197 MODULE_LICENSE("GPL v2");