root/drivers/mfd/exynos-lpass.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. exynos_lpass_core_sw_reset
  2. exynos_lpass_enable
  3. exynos_lpass_disable
  4. exynos_lpass_probe
  5. exynos_lpass_remove
  6. exynos_lpass_suspend
  7. exynos_lpass_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
   4  *
   5  * Authors: Inha Song <ideal.song@samsung.com>
   6  *          Sylwester Nawrocki <s.nawrocki@samsung.com>
   7  *
   8  * Samsung Exynos SoC series Low Power Audio Subsystem driver.
   9  *
  10  * This module provides regmap for the Top SFR region and instantiates
  11  * devices for IP blocks like DMAC, I2S, UART.
  12  */
  13 
  14 #include <linux/clk.h>
  15 #include <linux/delay.h>
  16 #include <linux/io.h>
  17 #include <linux/module.h>
  18 #include <linux/mfd/syscon.h>
  19 #include <linux/of.h>
  20 #include <linux/of_platform.h>
  21 #include <linux/platform_device.h>
  22 #include <linux/pm_runtime.h>
  23 #include <linux/regmap.h>
  24 #include <linux/soc/samsung/exynos-regs-pmu.h>
  25 #include <linux/types.h>
  26 
  27 /* LPASS Top register definitions */
  28 #define SFR_LPASS_CORE_SW_RESET         0x08
  29 #define  LPASS_SB_SW_RESET              BIT(11)
  30 #define  LPASS_UART_SW_RESET            BIT(10)
  31 #define  LPASS_PCM_SW_RESET             BIT(9)
  32 #define  LPASS_I2S_SW_RESET             BIT(8)
  33 #define  LPASS_WDT1_SW_RESET            BIT(4)
  34 #define  LPASS_WDT0_SW_RESET            BIT(3)
  35 #define  LPASS_TIMER_SW_RESET           BIT(2)
  36 #define  LPASS_MEM_SW_RESET             BIT(1)
  37 #define  LPASS_DMA_SW_RESET             BIT(0)
  38 
  39 #define SFR_LPASS_INTR_CA5_MASK         0x48
  40 #define SFR_LPASS_INTR_CPU_MASK         0x58
  41 #define  LPASS_INTR_APM                 BIT(9)
  42 #define  LPASS_INTR_MIF                 BIT(8)
  43 #define  LPASS_INTR_TIMER               BIT(7)
  44 #define  LPASS_INTR_DMA                 BIT(6)
  45 #define  LPASS_INTR_GPIO                BIT(5)
  46 #define  LPASS_INTR_I2S                 BIT(4)
  47 #define  LPASS_INTR_PCM                 BIT(3)
  48 #define  LPASS_INTR_SLIMBUS             BIT(2)
  49 #define  LPASS_INTR_UART                BIT(1)
  50 #define  LPASS_INTR_SFR                 BIT(0)
  51 
  52 struct exynos_lpass {
  53         /* pointer to the LPASS TOP regmap */
  54         struct regmap *top;
  55         struct clk *sfr0_clk;
  56 };
  57 
  58 static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
  59 {
  60         unsigned int val = 0;
  61 
  62         regmap_read(lpass->top, SFR_LPASS_CORE_SW_RESET, &val);
  63 
  64         val &= ~mask;
  65         regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
  66 
  67         usleep_range(100, 150);
  68 
  69         val |= mask;
  70         regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
  71 }
  72 
  73 static void exynos_lpass_enable(struct exynos_lpass *lpass)
  74 {
  75         clk_prepare_enable(lpass->sfr0_clk);
  76 
  77         /* Unmask SFR, DMA and I2S interrupt */
  78         regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK,
  79                      LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
  80 
  81         regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK,
  82                      LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S |
  83                      LPASS_INTR_UART);
  84 
  85         exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET);
  86         exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
  87         exynos_lpass_core_sw_reset(lpass, LPASS_MEM_SW_RESET);
  88         exynos_lpass_core_sw_reset(lpass, LPASS_UART_SW_RESET);
  89 }
  90 
  91 static void exynos_lpass_disable(struct exynos_lpass *lpass)
  92 {
  93         /* Mask any unmasked IP interrupt sources */
  94         regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK, 0);
  95         regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK, 0);
  96 
  97         clk_disable_unprepare(lpass->sfr0_clk);
  98 }
  99 
 100 static const struct regmap_config exynos_lpass_reg_conf = {
 101         .reg_bits       = 32,
 102         .reg_stride     = 4,
 103         .val_bits       = 32,
 104         .max_register   = 0xfc,
 105         .fast_io        = true,
 106 };
 107 
 108 static int exynos_lpass_probe(struct platform_device *pdev)
 109 {
 110         struct device *dev = &pdev->dev;
 111         struct exynos_lpass *lpass;
 112         void __iomem *base_top;
 113         struct resource *res;
 114 
 115         lpass = devm_kzalloc(dev, sizeof(*lpass), GFP_KERNEL);
 116         if (!lpass)
 117                 return -ENOMEM;
 118 
 119         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 120         base_top = devm_ioremap_resource(dev, res);
 121         if (IS_ERR(base_top))
 122                 return PTR_ERR(base_top);
 123 
 124         lpass->sfr0_clk = devm_clk_get(dev, "sfr0_ctrl");
 125         if (IS_ERR(lpass->sfr0_clk))
 126                 return PTR_ERR(lpass->sfr0_clk);
 127 
 128         lpass->top = regmap_init_mmio(dev, base_top,
 129                                         &exynos_lpass_reg_conf);
 130         if (IS_ERR(lpass->top)) {
 131                 dev_err(dev, "LPASS top regmap initialization failed\n");
 132                 return PTR_ERR(lpass->top);
 133         }
 134 
 135         platform_set_drvdata(pdev, lpass);
 136         pm_runtime_set_active(dev);
 137         pm_runtime_enable(dev);
 138         exynos_lpass_enable(lpass);
 139 
 140         return devm_of_platform_populate(dev);
 141 }
 142 
 143 static int exynos_lpass_remove(struct platform_device *pdev)
 144 {
 145         struct exynos_lpass *lpass = platform_get_drvdata(pdev);
 146 
 147         exynos_lpass_disable(lpass);
 148         pm_runtime_disable(&pdev->dev);
 149         if (!pm_runtime_status_suspended(&pdev->dev))
 150                 exynos_lpass_disable(lpass);
 151         regmap_exit(lpass->top);
 152 
 153         return 0;
 154 }
 155 
 156 static int __maybe_unused exynos_lpass_suspend(struct device *dev)
 157 {
 158         struct exynos_lpass *lpass = dev_get_drvdata(dev);
 159 
 160         exynos_lpass_disable(lpass);
 161 
 162         return 0;
 163 }
 164 
 165 static int __maybe_unused exynos_lpass_resume(struct device *dev)
 166 {
 167         struct exynos_lpass *lpass = dev_get_drvdata(dev);
 168 
 169         exynos_lpass_enable(lpass);
 170 
 171         return 0;
 172 }
 173 
 174 static const struct dev_pm_ops lpass_pm_ops = {
 175         SET_RUNTIME_PM_OPS(exynos_lpass_suspend, exynos_lpass_resume, NULL)
 176         SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
 177                                      pm_runtime_force_resume)
 178 };
 179 
 180 static const struct of_device_id exynos_lpass_of_match[] = {
 181         { .compatible = "samsung,exynos5433-lpass" },
 182         { },
 183 };
 184 MODULE_DEVICE_TABLE(of, exynos_lpass_of_match);
 185 
 186 static struct platform_driver exynos_lpass_driver = {
 187         .driver = {
 188                 .name           = "exynos-lpass",
 189                 .pm             = &lpass_pm_ops,
 190                 .of_match_table = exynos_lpass_of_match,
 191         },
 192         .probe  = exynos_lpass_probe,
 193         .remove = exynos_lpass_remove,
 194 };
 195 module_platform_driver(exynos_lpass_driver);
 196 
 197 MODULE_DESCRIPTION("Samsung Low Power Audio Subsystem driver");
 198 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */