18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel Sunrisepoint LPSS core support. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015, Intel Corporation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 88c2ecf20Sopenharmony_ci * Mika Westerberg <mika.westerberg@linux.intel.com> 98c2ecf20Sopenharmony_ci * Heikki Krogerus <heikki.krogerus@linux.intel.com> 108c2ecf20Sopenharmony_ci * Jarkko Nikula <jarkko.nikula@linux.intel.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/clk.h> 148c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 158c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 168c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 178c2ecf20Sopenharmony_ci#include <linux/idr.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <linux/ioport.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/mfd/core.h> 238c2ecf20Sopenharmony_ci#include <linux/pm_qos.h> 248c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 258c2ecf20Sopenharmony_ci#include <linux/property.h> 268c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 278c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include <linux/dma/idma64.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "intel-lpss.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define LPSS_DEV_OFFSET 0x000 348c2ecf20Sopenharmony_ci#define LPSS_DEV_SIZE 0x200 358c2ecf20Sopenharmony_ci#define LPSS_PRIV_OFFSET 0x200 368c2ecf20Sopenharmony_ci#define LPSS_PRIV_SIZE 0x100 378c2ecf20Sopenharmony_ci#define LPSS_PRIV_REG_COUNT (LPSS_PRIV_SIZE / 4) 388c2ecf20Sopenharmony_ci#define LPSS_IDMA64_OFFSET 0x800 398c2ecf20Sopenharmony_ci#define LPSS_IDMA64_SIZE 0x800 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Offsets from lpss->priv */ 428c2ecf20Sopenharmony_ci#define LPSS_PRIV_RESETS 0x04 438c2ecf20Sopenharmony_ci#define LPSS_PRIV_RESETS_IDMA BIT(2) 448c2ecf20Sopenharmony_ci#define LPSS_PRIV_RESETS_FUNC 0x3 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define LPSS_PRIV_ACTIVELTR 0x10 478c2ecf20Sopenharmony_ci#define LPSS_PRIV_IDLELTR 0x14 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define LPSS_PRIV_LTR_REQ BIT(15) 508c2ecf20Sopenharmony_ci#define LPSS_PRIV_LTR_SCALE_MASK GENMASK(11, 10) 518c2ecf20Sopenharmony_ci#define LPSS_PRIV_LTR_SCALE_1US (2 << 10) 528c2ecf20Sopenharmony_ci#define LPSS_PRIV_LTR_SCALE_32US (3 << 10) 538c2ecf20Sopenharmony_ci#define LPSS_PRIV_LTR_VALUE_MASK GENMASK(9, 0) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define LPSS_PRIV_SSP_REG 0x20 568c2ecf20Sopenharmony_ci#define LPSS_PRIV_SSP_REG_DIS_DMA_FIN BIT(0) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define LPSS_PRIV_REMAP_ADDR 0x40 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define LPSS_PRIV_CAPS 0xfc 618c2ecf20Sopenharmony_ci#define LPSS_PRIV_CAPS_NO_IDMA BIT(8) 628c2ecf20Sopenharmony_ci#define LPSS_PRIV_CAPS_TYPE_MASK GENMASK(7, 4) 638c2ecf20Sopenharmony_ci#define LPSS_PRIV_CAPS_TYPE_SHIFT 4 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* This matches the type field in CAPS register */ 668c2ecf20Sopenharmony_cienum intel_lpss_dev_type { 678c2ecf20Sopenharmony_ci LPSS_DEV_I2C = 0, 688c2ecf20Sopenharmony_ci LPSS_DEV_UART, 698c2ecf20Sopenharmony_ci LPSS_DEV_SPI, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct intel_lpss { 738c2ecf20Sopenharmony_ci const struct intel_lpss_platform_info *info; 748c2ecf20Sopenharmony_ci enum intel_lpss_dev_type type; 758c2ecf20Sopenharmony_ci struct clk *clk; 768c2ecf20Sopenharmony_ci struct clk_lookup *clock; 778c2ecf20Sopenharmony_ci struct mfd_cell *cell; 788c2ecf20Sopenharmony_ci struct device *dev; 798c2ecf20Sopenharmony_ci void __iomem *priv; 808c2ecf20Sopenharmony_ci u32 priv_ctx[LPSS_PRIV_REG_COUNT]; 818c2ecf20Sopenharmony_ci int devid; 828c2ecf20Sopenharmony_ci u32 caps; 838c2ecf20Sopenharmony_ci u32 active_ltr; 848c2ecf20Sopenharmony_ci u32 idle_ltr; 858c2ecf20Sopenharmony_ci struct dentry *debugfs; 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const struct resource intel_lpss_dev_resources[] = { 898c2ecf20Sopenharmony_ci DEFINE_RES_MEM_NAMED(LPSS_DEV_OFFSET, LPSS_DEV_SIZE, "lpss_dev"), 908c2ecf20Sopenharmony_ci DEFINE_RES_MEM_NAMED(LPSS_PRIV_OFFSET, LPSS_PRIV_SIZE, "lpss_priv"), 918c2ecf20Sopenharmony_ci DEFINE_RES_IRQ(0), 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic const struct resource intel_lpss_idma64_resources[] = { 958c2ecf20Sopenharmony_ci DEFINE_RES_MEM(LPSS_IDMA64_OFFSET, LPSS_IDMA64_SIZE), 968c2ecf20Sopenharmony_ci DEFINE_RES_IRQ(0), 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * Cells needs to be ordered so that the iDMA is created first. This is 1018c2ecf20Sopenharmony_ci * because we need to be sure the DMA is available when the host controller 1028c2ecf20Sopenharmony_ci * driver is probed. 1038c2ecf20Sopenharmony_ci */ 1048c2ecf20Sopenharmony_cistatic const struct mfd_cell intel_lpss_idma64_cell = { 1058c2ecf20Sopenharmony_ci .name = LPSS_IDMA64_DRIVER_NAME, 1068c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(intel_lpss_idma64_resources), 1078c2ecf20Sopenharmony_ci .resources = intel_lpss_idma64_resources, 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic const struct mfd_cell intel_lpss_i2c_cell = { 1118c2ecf20Sopenharmony_ci .name = "i2c_designware", 1128c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), 1138c2ecf20Sopenharmony_ci .resources = intel_lpss_dev_resources, 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic const struct mfd_cell intel_lpss_uart_cell = { 1178c2ecf20Sopenharmony_ci .name = "dw-apb-uart", 1188c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), 1198c2ecf20Sopenharmony_ci .resources = intel_lpss_dev_resources, 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic const struct mfd_cell intel_lpss_spi_cell = { 1238c2ecf20Sopenharmony_ci .name = "pxa2xx-spi", 1248c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), 1258c2ecf20Sopenharmony_ci .resources = intel_lpss_dev_resources, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic DEFINE_IDA(intel_lpss_devid_ida); 1298c2ecf20Sopenharmony_cistatic struct dentry *intel_lpss_debugfs; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void intel_lpss_cache_ltr(struct intel_lpss *lpss) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci lpss->active_ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); 1348c2ecf20Sopenharmony_ci lpss->idle_ltr = readl(lpss->priv + LPSS_PRIV_IDLELTR); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int intel_lpss_debugfs_add(struct intel_lpss *lpss) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct dentry *dir; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci dir = debugfs_create_dir(dev_name(lpss->dev), intel_lpss_debugfs); 1428c2ecf20Sopenharmony_ci if (IS_ERR(dir)) 1438c2ecf20Sopenharmony_ci return PTR_ERR(dir); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* Cache the values into lpss structure */ 1468c2ecf20Sopenharmony_ci intel_lpss_cache_ltr(lpss); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci debugfs_create_x32("capabilities", S_IRUGO, dir, &lpss->caps); 1498c2ecf20Sopenharmony_ci debugfs_create_x32("active_ltr", S_IRUGO, dir, &lpss->active_ltr); 1508c2ecf20Sopenharmony_ci debugfs_create_x32("idle_ltr", S_IRUGO, dir, &lpss->idle_ltr); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci lpss->debugfs = dir; 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void intel_lpss_debugfs_remove(struct intel_lpss *lpss) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci debugfs_remove_recursive(lpss->debugfs); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void intel_lpss_ltr_set(struct device *dev, s32 val) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct intel_lpss *lpss = dev_get_drvdata(dev); 1648c2ecf20Sopenharmony_ci u32 ltr; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * Program latency tolerance (LTR) accordingly what has been asked 1688c2ecf20Sopenharmony_ci * by the PM QoS layer or disable it in case we were passed 1698c2ecf20Sopenharmony_ci * negative value or PM_QOS_LATENCY_ANY. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (val == PM_QOS_LATENCY_ANY || val < 0) { 1748c2ecf20Sopenharmony_ci ltr &= ~LPSS_PRIV_LTR_REQ; 1758c2ecf20Sopenharmony_ci } else { 1768c2ecf20Sopenharmony_ci ltr |= LPSS_PRIV_LTR_REQ; 1778c2ecf20Sopenharmony_ci ltr &= ~LPSS_PRIV_LTR_SCALE_MASK; 1788c2ecf20Sopenharmony_ci ltr &= ~LPSS_PRIV_LTR_VALUE_MASK; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (val > LPSS_PRIV_LTR_VALUE_MASK) 1818c2ecf20Sopenharmony_ci ltr |= LPSS_PRIV_LTR_SCALE_32US | val >> 5; 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci ltr |= LPSS_PRIV_LTR_SCALE_1US | val; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (ltr == lpss->active_ltr) 1878c2ecf20Sopenharmony_ci return; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci writel(ltr, lpss->priv + LPSS_PRIV_ACTIVELTR); 1908c2ecf20Sopenharmony_ci writel(ltr, lpss->priv + LPSS_PRIV_IDLELTR); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Cache the values into lpss structure */ 1938c2ecf20Sopenharmony_ci intel_lpss_cache_ltr(lpss); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void intel_lpss_ltr_expose(struct intel_lpss *lpss) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci lpss->dev->power.set_latency_tolerance = intel_lpss_ltr_set; 1998c2ecf20Sopenharmony_ci dev_pm_qos_expose_latency_tolerance(lpss->dev); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void intel_lpss_ltr_hide(struct intel_lpss *lpss) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci dev_pm_qos_hide_latency_tolerance(lpss->dev); 2058c2ecf20Sopenharmony_ci lpss->dev->power.set_latency_tolerance = NULL; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int intel_lpss_assign_devs(struct intel_lpss *lpss) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci const struct mfd_cell *cell; 2118c2ecf20Sopenharmony_ci unsigned int type; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK; 2148c2ecf20Sopenharmony_ci type >>= LPSS_PRIV_CAPS_TYPE_SHIFT; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci switch (type) { 2178c2ecf20Sopenharmony_ci case LPSS_DEV_I2C: 2188c2ecf20Sopenharmony_ci cell = &intel_lpss_i2c_cell; 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci case LPSS_DEV_UART: 2218c2ecf20Sopenharmony_ci cell = &intel_lpss_uart_cell; 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci case LPSS_DEV_SPI: 2248c2ecf20Sopenharmony_ci cell = &intel_lpss_spi_cell; 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci default: 2278c2ecf20Sopenharmony_ci return -ENODEV; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci lpss->cell = devm_kmemdup(lpss->dev, cell, sizeof(*cell), GFP_KERNEL); 2318c2ecf20Sopenharmony_ci if (!lpss->cell) 2328c2ecf20Sopenharmony_ci return -ENOMEM; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci lpss->type = type; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic bool intel_lpss_has_idma(const struct intel_lpss *lpss) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return (lpss->caps & LPSS_PRIV_CAPS_NO_IDMA) == 0; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void intel_lpss_set_remap_addr(const struct intel_lpss *lpss) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci resource_size_t addr = lpss->info->mem->start; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci lo_hi_writeq(addr, lpss->priv + LPSS_PRIV_REMAP_ADDR); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic void intel_lpss_deassert_reset(const struct intel_lpss *lpss) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci u32 value = LPSS_PRIV_RESETS_FUNC | LPSS_PRIV_RESETS_IDMA; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Bring out the device from reset */ 2568c2ecf20Sopenharmony_ci writel(value, lpss->priv + LPSS_PRIV_RESETS); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void intel_lpss_init_dev(const struct intel_lpss *lpss) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Set the device in reset state */ 2648c2ecf20Sopenharmony_ci writel(0, lpss->priv + LPSS_PRIV_RESETS); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci intel_lpss_deassert_reset(lpss); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci intel_lpss_set_remap_addr(lpss); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (!intel_lpss_has_idma(lpss)) 2718c2ecf20Sopenharmony_ci return; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Make sure that SPI multiblock DMA transfers are re-enabled */ 2748c2ecf20Sopenharmony_ci if (lpss->type == LPSS_DEV_SPI) 2758c2ecf20Sopenharmony_ci writel(value, lpss->priv + LPSS_PRIV_SSP_REG); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void intel_lpss_unregister_clock_tree(struct clk *clk) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct clk *parent; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci while (clk) { 2838c2ecf20Sopenharmony_ci parent = clk_get_parent(clk); 2848c2ecf20Sopenharmony_ci clk_unregister(clk); 2858c2ecf20Sopenharmony_ci clk = parent; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int intel_lpss_register_clock_divider(struct intel_lpss *lpss, 2908c2ecf20Sopenharmony_ci const char *devname, 2918c2ecf20Sopenharmony_ci struct clk **clk) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci char name[32]; 2948c2ecf20Sopenharmony_ci struct clk *tmp = *clk; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%s-enable", devname); 2978c2ecf20Sopenharmony_ci tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), 0, 2988c2ecf20Sopenharmony_ci lpss->priv, 0, 0, NULL); 2998c2ecf20Sopenharmony_ci if (IS_ERR(tmp)) 3008c2ecf20Sopenharmony_ci return PTR_ERR(tmp); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%s-div", devname); 3038c2ecf20Sopenharmony_ci tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp), 3048c2ecf20Sopenharmony_ci 0, lpss->priv, 1, 15, 16, 15, 0, 3058c2ecf20Sopenharmony_ci NULL); 3068c2ecf20Sopenharmony_ci if (IS_ERR(tmp)) 3078c2ecf20Sopenharmony_ci return PTR_ERR(tmp); 3088c2ecf20Sopenharmony_ci *clk = tmp; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%s-update", devname); 3118c2ecf20Sopenharmony_ci tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), 3128c2ecf20Sopenharmony_ci CLK_SET_RATE_PARENT, lpss->priv, 31, 0, NULL); 3138c2ecf20Sopenharmony_ci if (IS_ERR(tmp)) 3148c2ecf20Sopenharmony_ci return PTR_ERR(tmp); 3158c2ecf20Sopenharmony_ci *clk = tmp; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int intel_lpss_register_clock(struct intel_lpss *lpss) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci const struct mfd_cell *cell = lpss->cell; 3238c2ecf20Sopenharmony_ci struct clk *clk; 3248c2ecf20Sopenharmony_ci char devname[24]; 3258c2ecf20Sopenharmony_ci int ret; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!lpss->info->clk_rate) 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Root clock */ 3318c2ecf20Sopenharmony_ci clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL, 0, 3328c2ecf20Sopenharmony_ci lpss->info->clk_rate); 3338c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 3348c2ecf20Sopenharmony_ci return PTR_ERR(clk); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci snprintf(devname, sizeof(devname), "%s.%d", cell->name, lpss->devid); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* 3398c2ecf20Sopenharmony_ci * Support for clock divider only if it has some preset value. 3408c2ecf20Sopenharmony_ci * Otherwise we assume that the divider is not used. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci if (lpss->type != LPSS_DEV_I2C) { 3438c2ecf20Sopenharmony_ci ret = intel_lpss_register_clock_divider(lpss, devname, &clk); 3448c2ecf20Sopenharmony_ci if (ret) 3458c2ecf20Sopenharmony_ci goto err_clk_register; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ret = -ENOMEM; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* Clock for the host controller */ 3518c2ecf20Sopenharmony_ci lpss->clock = clkdev_create(clk, lpss->info->clk_con_id, "%s", devname); 3528c2ecf20Sopenharmony_ci if (!lpss->clock) 3538c2ecf20Sopenharmony_ci goto err_clk_register; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci lpss->clk = clk; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cierr_clk_register: 3608c2ecf20Sopenharmony_ci intel_lpss_unregister_clock_tree(clk); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic void intel_lpss_unregister_clock(struct intel_lpss *lpss) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(lpss->clk)) 3688c2ecf20Sopenharmony_ci return; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci clkdev_drop(lpss->clock); 3718c2ecf20Sopenharmony_ci intel_lpss_unregister_clock_tree(lpss->clk); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ciint intel_lpss_probe(struct device *dev, 3758c2ecf20Sopenharmony_ci const struct intel_lpss_platform_info *info) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct intel_lpss *lpss; 3788c2ecf20Sopenharmony_ci int ret; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (!info || !info->mem || info->irq <= 0) 3818c2ecf20Sopenharmony_ci return -EINVAL; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci lpss = devm_kzalloc(dev, sizeof(*lpss), GFP_KERNEL); 3848c2ecf20Sopenharmony_ci if (!lpss) 3858c2ecf20Sopenharmony_ci return -ENOMEM; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci lpss->priv = devm_ioremap_uc(dev, info->mem->start + LPSS_PRIV_OFFSET, 3888c2ecf20Sopenharmony_ci LPSS_PRIV_SIZE); 3898c2ecf20Sopenharmony_ci if (!lpss->priv) 3908c2ecf20Sopenharmony_ci return -ENOMEM; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci lpss->info = info; 3938c2ecf20Sopenharmony_ci lpss->dev = dev; 3948c2ecf20Sopenharmony_ci lpss->caps = readl(lpss->priv + LPSS_PRIV_CAPS); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci dev_set_drvdata(dev, lpss); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ret = intel_lpss_assign_devs(lpss); 3998c2ecf20Sopenharmony_ci if (ret) 4008c2ecf20Sopenharmony_ci return ret; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci lpss->cell->properties = info->properties; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci intel_lpss_init_dev(lpss); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL); 4078c2ecf20Sopenharmony_ci if (lpss->devid < 0) 4088c2ecf20Sopenharmony_ci return lpss->devid; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci ret = intel_lpss_register_clock(lpss); 4118c2ecf20Sopenharmony_ci if (ret) 4128c2ecf20Sopenharmony_ci goto err_clk_register; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci intel_lpss_ltr_expose(lpss); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ret = intel_lpss_debugfs_add(lpss); 4178c2ecf20Sopenharmony_ci if (ret) 4188c2ecf20Sopenharmony_ci dev_warn(dev, "Failed to create debugfs entries\n"); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (intel_lpss_has_idma(lpss)) { 4218c2ecf20Sopenharmony_ci ret = mfd_add_devices(dev, lpss->devid, &intel_lpss_idma64_cell, 4228c2ecf20Sopenharmony_ci 1, info->mem, info->irq, NULL); 4238c2ecf20Sopenharmony_ci if (ret) 4248c2ecf20Sopenharmony_ci dev_warn(dev, "Failed to add %s, fallback to PIO\n", 4258c2ecf20Sopenharmony_ci LPSS_IDMA64_DRIVER_NAME); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci ret = mfd_add_devices(dev, lpss->devid, lpss->cell, 4298c2ecf20Sopenharmony_ci 1, info->mem, info->irq, NULL); 4308c2ecf20Sopenharmony_ci if (ret) 4318c2ecf20Sopenharmony_ci goto err_remove_ltr; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cierr_remove_ltr: 4388c2ecf20Sopenharmony_ci intel_lpss_debugfs_remove(lpss); 4398c2ecf20Sopenharmony_ci intel_lpss_ltr_hide(lpss); 4408c2ecf20Sopenharmony_ci intel_lpss_unregister_clock(lpss); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cierr_clk_register: 4438c2ecf20Sopenharmony_ci ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return ret; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_probe); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_civoid intel_lpss_remove(struct device *dev) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct intel_lpss *lpss = dev_get_drvdata(dev); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci mfd_remove_devices(dev); 4548c2ecf20Sopenharmony_ci intel_lpss_debugfs_remove(lpss); 4558c2ecf20Sopenharmony_ci intel_lpss_ltr_hide(lpss); 4568c2ecf20Sopenharmony_ci intel_lpss_unregister_clock(lpss); 4578c2ecf20Sopenharmony_ci ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_remove); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int resume_lpss_device(struct device *dev, void *data) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) 4648c2ecf20Sopenharmony_ci pm_runtime_resume(dev); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ciint intel_lpss_prepare(struct device *dev) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci /* 4728c2ecf20Sopenharmony_ci * Resume both child devices before entering system sleep. This 4738c2ecf20Sopenharmony_ci * ensures that they are in proper state before they get suspended. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci device_for_each_child_reverse(dev, NULL, resume_lpss_device); 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_prepare); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ciint intel_lpss_suspend(struct device *dev) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct intel_lpss *lpss = dev_get_drvdata(dev); 4838c2ecf20Sopenharmony_ci unsigned int i; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Save device context */ 4868c2ecf20Sopenharmony_ci for (i = 0; i < LPSS_PRIV_REG_COUNT; i++) 4878c2ecf20Sopenharmony_ci lpss->priv_ctx[i] = readl(lpss->priv + i * 4); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* 4908c2ecf20Sopenharmony_ci * If the device type is not UART, then put the controller into 4918c2ecf20Sopenharmony_ci * reset. UART cannot be put into reset since S3/S0ix fail when 4928c2ecf20Sopenharmony_ci * no_console_suspend flag is enabled. 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_ci if (lpss->type != LPSS_DEV_UART) 4958c2ecf20Sopenharmony_ci writel(0, lpss->priv + LPSS_PRIV_RESETS); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_suspend); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ciint intel_lpss_resume(struct device *dev) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct intel_lpss *lpss = dev_get_drvdata(dev); 5048c2ecf20Sopenharmony_ci unsigned int i; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci intel_lpss_deassert_reset(lpss); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Restore device context */ 5098c2ecf20Sopenharmony_ci for (i = 0; i < LPSS_PRIV_REG_COUNT; i++) 5108c2ecf20Sopenharmony_ci writel(lpss->priv_ctx[i], lpss->priv + i * 4); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_resume); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic int __init intel_lpss_init(void) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci intel_lpss_debugfs = debugfs_create_dir("intel_lpss", NULL); 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_cimodule_init(intel_lpss_init); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic void __exit intel_lpss_exit(void) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci ida_destroy(&intel_lpss_devid_ida); 5268c2ecf20Sopenharmony_ci debugfs_remove(intel_lpss_debugfs); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_cimodule_exit(intel_lpss_exit); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); 5318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); 5328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>"); 5338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>"); 5348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel LPSS core driver"); 5358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 5368c2ecf20Sopenharmony_ci/* 5378c2ecf20Sopenharmony_ci * Ensure the DMA driver is loaded before the host controller device appears, 5388c2ecf20Sopenharmony_ci * so that the host controller driver can request its DMA channels as early 5398c2ecf20Sopenharmony_ci * as possible. 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * If the DMA module is not there that's OK as well. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ciMODULE_SOFTDEP("pre: platform:" LPSS_IDMA64_DRIVER_NAME); 544