162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Intel Sunrisepoint LPSS core support. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015, Intel Corporation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 862306a36Sopenharmony_ci * Mika Westerberg <mika.westerberg@linux.intel.com> 962306a36Sopenharmony_ci * Heikki Krogerus <heikki.krogerus@linux.intel.com> 1062306a36Sopenharmony_ci * Jarkko Nikula <jarkko.nikula@linux.intel.com> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/clk.h> 1462306a36Sopenharmony_ci#include <linux/clkdev.h> 1562306a36Sopenharmony_ci#include <linux/clk-provider.h> 1662306a36Sopenharmony_ci#include <linux/debugfs.h> 1762306a36Sopenharmony_ci#include <linux/idr.h> 1862306a36Sopenharmony_ci#include <linux/io.h> 1962306a36Sopenharmony_ci#include <linux/ioport.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/module.h> 2262306a36Sopenharmony_ci#include <linux/mfd/core.h> 2362306a36Sopenharmony_ci#include <linux/pm_qos.h> 2462306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2562306a36Sopenharmony_ci#include <linux/property.h> 2662306a36Sopenharmony_ci#include <linux/seq_file.h> 2762306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/dma/idma64.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "intel-lpss.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define LPSS_DEV_OFFSET 0x000 3462306a36Sopenharmony_ci#define LPSS_DEV_SIZE 0x200 3562306a36Sopenharmony_ci#define LPSS_PRIV_OFFSET 0x200 3662306a36Sopenharmony_ci#define LPSS_PRIV_SIZE 0x100 3762306a36Sopenharmony_ci#define LPSS_PRIV_REG_COUNT (LPSS_PRIV_SIZE / 4) 3862306a36Sopenharmony_ci#define LPSS_IDMA64_OFFSET 0x800 3962306a36Sopenharmony_ci#define LPSS_IDMA64_SIZE 0x800 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Offsets from lpss->priv */ 4262306a36Sopenharmony_ci#define LPSS_PRIV_RESETS 0x04 4362306a36Sopenharmony_ci#define LPSS_PRIV_RESETS_IDMA BIT(2) 4462306a36Sopenharmony_ci#define LPSS_PRIV_RESETS_FUNC 0x3 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define LPSS_PRIV_ACTIVELTR 0x10 4762306a36Sopenharmony_ci#define LPSS_PRIV_IDLELTR 0x14 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define LPSS_PRIV_LTR_REQ BIT(15) 5062306a36Sopenharmony_ci#define LPSS_PRIV_LTR_SCALE_MASK GENMASK(11, 10) 5162306a36Sopenharmony_ci#define LPSS_PRIV_LTR_SCALE_1US (2 << 10) 5262306a36Sopenharmony_ci#define LPSS_PRIV_LTR_SCALE_32US (3 << 10) 5362306a36Sopenharmony_ci#define LPSS_PRIV_LTR_VALUE_MASK GENMASK(9, 0) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define LPSS_PRIV_SSP_REG 0x20 5662306a36Sopenharmony_ci#define LPSS_PRIV_SSP_REG_DIS_DMA_FIN BIT(0) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define LPSS_PRIV_REMAP_ADDR 0x40 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define LPSS_PRIV_CAPS 0xfc 6162306a36Sopenharmony_ci#define LPSS_PRIV_CAPS_NO_IDMA BIT(8) 6262306a36Sopenharmony_ci#define LPSS_PRIV_CAPS_TYPE_MASK GENMASK(7, 4) 6362306a36Sopenharmony_ci#define LPSS_PRIV_CAPS_TYPE_SHIFT 4 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* This matches the type field in CAPS register */ 6662306a36Sopenharmony_cienum intel_lpss_dev_type { 6762306a36Sopenharmony_ci LPSS_DEV_I2C = 0, 6862306a36Sopenharmony_ci LPSS_DEV_UART, 6962306a36Sopenharmony_ci LPSS_DEV_SPI, 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct intel_lpss { 7362306a36Sopenharmony_ci const struct intel_lpss_platform_info *info; 7462306a36Sopenharmony_ci enum intel_lpss_dev_type type; 7562306a36Sopenharmony_ci struct clk *clk; 7662306a36Sopenharmony_ci struct clk_lookup *clock; 7762306a36Sopenharmony_ci struct mfd_cell *cell; 7862306a36Sopenharmony_ci struct device *dev; 7962306a36Sopenharmony_ci void __iomem *priv; 8062306a36Sopenharmony_ci u32 priv_ctx[LPSS_PRIV_REG_COUNT]; 8162306a36Sopenharmony_ci int devid; 8262306a36Sopenharmony_ci u32 caps; 8362306a36Sopenharmony_ci u32 active_ltr; 8462306a36Sopenharmony_ci u32 idle_ltr; 8562306a36Sopenharmony_ci struct dentry *debugfs; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic const struct resource intel_lpss_dev_resources[] = { 8962306a36Sopenharmony_ci DEFINE_RES_MEM_NAMED(LPSS_DEV_OFFSET, LPSS_DEV_SIZE, "lpss_dev"), 9062306a36Sopenharmony_ci DEFINE_RES_MEM_NAMED(LPSS_PRIV_OFFSET, LPSS_PRIV_SIZE, "lpss_priv"), 9162306a36Sopenharmony_ci DEFINE_RES_IRQ(0), 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic const struct resource intel_lpss_idma64_resources[] = { 9562306a36Sopenharmony_ci DEFINE_RES_MEM(LPSS_IDMA64_OFFSET, LPSS_IDMA64_SIZE), 9662306a36Sopenharmony_ci DEFINE_RES_IRQ(0), 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * Cells needs to be ordered so that the iDMA is created first. This is 10162306a36Sopenharmony_ci * because we need to be sure the DMA is available when the host controller 10262306a36Sopenharmony_ci * driver is probed. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic const struct mfd_cell intel_lpss_idma64_cell = { 10562306a36Sopenharmony_ci .name = LPSS_IDMA64_DRIVER_NAME, 10662306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(intel_lpss_idma64_resources), 10762306a36Sopenharmony_ci .resources = intel_lpss_idma64_resources, 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic const struct mfd_cell intel_lpss_i2c_cell = { 11162306a36Sopenharmony_ci .name = "i2c_designware", 11262306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), 11362306a36Sopenharmony_ci .resources = intel_lpss_dev_resources, 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic const struct mfd_cell intel_lpss_uart_cell = { 11762306a36Sopenharmony_ci .name = "dw-apb-uart", 11862306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), 11962306a36Sopenharmony_ci .resources = intel_lpss_dev_resources, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic const struct mfd_cell intel_lpss_spi_cell = { 12362306a36Sopenharmony_ci .name = "pxa2xx-spi", 12462306a36Sopenharmony_ci .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), 12562306a36Sopenharmony_ci .resources = intel_lpss_dev_resources, 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic DEFINE_IDA(intel_lpss_devid_ida); 12962306a36Sopenharmony_cistatic struct dentry *intel_lpss_debugfs; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic void intel_lpss_cache_ltr(struct intel_lpss *lpss) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci lpss->active_ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); 13462306a36Sopenharmony_ci lpss->idle_ltr = readl(lpss->priv + LPSS_PRIV_IDLELTR); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int intel_lpss_debugfs_add(struct intel_lpss *lpss) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct dentry *dir; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci dir = debugfs_create_dir(dev_name(lpss->dev), intel_lpss_debugfs); 14262306a36Sopenharmony_ci if (IS_ERR(dir)) 14362306a36Sopenharmony_ci return PTR_ERR(dir); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Cache the values into lpss structure */ 14662306a36Sopenharmony_ci intel_lpss_cache_ltr(lpss); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci debugfs_create_x32("capabilities", S_IRUGO, dir, &lpss->caps); 14962306a36Sopenharmony_ci debugfs_create_x32("active_ltr", S_IRUGO, dir, &lpss->active_ltr); 15062306a36Sopenharmony_ci debugfs_create_x32("idle_ltr", S_IRUGO, dir, &lpss->idle_ltr); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci lpss->debugfs = dir; 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void intel_lpss_debugfs_remove(struct intel_lpss *lpss) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci debugfs_remove_recursive(lpss->debugfs); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void intel_lpss_ltr_set(struct device *dev, s32 val) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct intel_lpss *lpss = dev_get_drvdata(dev); 16462306a36Sopenharmony_ci u32 ltr; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* 16762306a36Sopenharmony_ci * Program latency tolerance (LTR) accordingly what has been asked 16862306a36Sopenharmony_ci * by the PM QoS layer or disable it in case we were passed 16962306a36Sopenharmony_ci * negative value or PM_QOS_LATENCY_ANY. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (val == PM_QOS_LATENCY_ANY || val < 0) { 17462306a36Sopenharmony_ci ltr &= ~LPSS_PRIV_LTR_REQ; 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci ltr |= LPSS_PRIV_LTR_REQ; 17762306a36Sopenharmony_ci ltr &= ~LPSS_PRIV_LTR_SCALE_MASK; 17862306a36Sopenharmony_ci ltr &= ~LPSS_PRIV_LTR_VALUE_MASK; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (val > LPSS_PRIV_LTR_VALUE_MASK) 18162306a36Sopenharmony_ci ltr |= LPSS_PRIV_LTR_SCALE_32US | val >> 5; 18262306a36Sopenharmony_ci else 18362306a36Sopenharmony_ci ltr |= LPSS_PRIV_LTR_SCALE_1US | val; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (ltr == lpss->active_ltr) 18762306a36Sopenharmony_ci return; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci writel(ltr, lpss->priv + LPSS_PRIV_ACTIVELTR); 19062306a36Sopenharmony_ci writel(ltr, lpss->priv + LPSS_PRIV_IDLELTR); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Cache the values into lpss structure */ 19362306a36Sopenharmony_ci intel_lpss_cache_ltr(lpss); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void intel_lpss_ltr_expose(struct intel_lpss *lpss) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci lpss->dev->power.set_latency_tolerance = intel_lpss_ltr_set; 19962306a36Sopenharmony_ci dev_pm_qos_expose_latency_tolerance(lpss->dev); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void intel_lpss_ltr_hide(struct intel_lpss *lpss) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci dev_pm_qos_hide_latency_tolerance(lpss->dev); 20562306a36Sopenharmony_ci lpss->dev->power.set_latency_tolerance = NULL; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic int intel_lpss_assign_devs(struct intel_lpss *lpss) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci const struct mfd_cell *cell; 21162306a36Sopenharmony_ci unsigned int type; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK; 21462306a36Sopenharmony_ci type >>= LPSS_PRIV_CAPS_TYPE_SHIFT; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci switch (type) { 21762306a36Sopenharmony_ci case LPSS_DEV_I2C: 21862306a36Sopenharmony_ci cell = &intel_lpss_i2c_cell; 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci case LPSS_DEV_UART: 22162306a36Sopenharmony_ci cell = &intel_lpss_uart_cell; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci case LPSS_DEV_SPI: 22462306a36Sopenharmony_ci cell = &intel_lpss_spi_cell; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci default: 22762306a36Sopenharmony_ci return -ENODEV; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci lpss->cell = devm_kmemdup(lpss->dev, cell, sizeof(*cell), GFP_KERNEL); 23162306a36Sopenharmony_ci if (!lpss->cell) 23262306a36Sopenharmony_ci return -ENOMEM; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci lpss->type = type; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic bool intel_lpss_has_idma(const struct intel_lpss *lpss) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci return (lpss->caps & LPSS_PRIV_CAPS_NO_IDMA) == 0; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void intel_lpss_set_remap_addr(const struct intel_lpss *lpss) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci resource_size_t addr = lpss->info->mem->start; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci lo_hi_writeq(addr, lpss->priv + LPSS_PRIV_REMAP_ADDR); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void intel_lpss_deassert_reset(const struct intel_lpss *lpss) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci u32 value = LPSS_PRIV_RESETS_FUNC | LPSS_PRIV_RESETS_IDMA; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Bring out the device from reset */ 25662306a36Sopenharmony_ci writel(value, lpss->priv + LPSS_PRIV_RESETS); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic void intel_lpss_init_dev(const struct intel_lpss *lpss) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Set the device in reset state */ 26462306a36Sopenharmony_ci writel(0, lpss->priv + LPSS_PRIV_RESETS); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci intel_lpss_deassert_reset(lpss); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci intel_lpss_set_remap_addr(lpss); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (!intel_lpss_has_idma(lpss)) 27162306a36Sopenharmony_ci return; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Make sure that SPI multiblock DMA transfers are re-enabled */ 27462306a36Sopenharmony_ci if (lpss->type == LPSS_DEV_SPI) 27562306a36Sopenharmony_ci writel(value, lpss->priv + LPSS_PRIV_SSP_REG); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void intel_lpss_unregister_clock_tree(struct clk *clk) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct clk *parent; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci while (clk) { 28362306a36Sopenharmony_ci parent = clk_get_parent(clk); 28462306a36Sopenharmony_ci clk_unregister(clk); 28562306a36Sopenharmony_ci clk = parent; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic int intel_lpss_register_clock_divider(struct intel_lpss *lpss, 29062306a36Sopenharmony_ci const char *devname, 29162306a36Sopenharmony_ci struct clk **clk) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci char name[32]; 29462306a36Sopenharmony_ci struct clk *tmp = *clk; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci snprintf(name, sizeof(name), "%s-enable", devname); 29762306a36Sopenharmony_ci tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), 0, 29862306a36Sopenharmony_ci lpss->priv, 0, 0, NULL); 29962306a36Sopenharmony_ci if (IS_ERR(tmp)) 30062306a36Sopenharmony_ci return PTR_ERR(tmp); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci snprintf(name, sizeof(name), "%s-div", devname); 30362306a36Sopenharmony_ci tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp), 30462306a36Sopenharmony_ci 0, lpss->priv, 1, 15, 16, 15, 30562306a36Sopenharmony_ci CLK_FRAC_DIVIDER_POWER_OF_TWO_PS, 30662306a36Sopenharmony_ci NULL); 30762306a36Sopenharmony_ci if (IS_ERR(tmp)) 30862306a36Sopenharmony_ci return PTR_ERR(tmp); 30962306a36Sopenharmony_ci *clk = tmp; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci snprintf(name, sizeof(name), "%s-update", devname); 31262306a36Sopenharmony_ci tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), 31362306a36Sopenharmony_ci CLK_SET_RATE_PARENT, lpss->priv, 31, 0, NULL); 31462306a36Sopenharmony_ci if (IS_ERR(tmp)) 31562306a36Sopenharmony_ci return PTR_ERR(tmp); 31662306a36Sopenharmony_ci *clk = tmp; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int intel_lpss_register_clock(struct intel_lpss *lpss) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci const struct mfd_cell *cell = lpss->cell; 32462306a36Sopenharmony_ci struct clk *clk; 32562306a36Sopenharmony_ci char devname[24]; 32662306a36Sopenharmony_ci int ret; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (!lpss->info->clk_rate) 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* Root clock */ 33262306a36Sopenharmony_ci clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL, 0, 33362306a36Sopenharmony_ci lpss->info->clk_rate); 33462306a36Sopenharmony_ci if (IS_ERR(clk)) 33562306a36Sopenharmony_ci return PTR_ERR(clk); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci snprintf(devname, sizeof(devname), "%s.%d", cell->name, lpss->devid); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* 34062306a36Sopenharmony_ci * Support for clock divider only if it has some preset value. 34162306a36Sopenharmony_ci * Otherwise we assume that the divider is not used. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci if (lpss->type != LPSS_DEV_I2C) { 34462306a36Sopenharmony_ci ret = intel_lpss_register_clock_divider(lpss, devname, &clk); 34562306a36Sopenharmony_ci if (ret) 34662306a36Sopenharmony_ci goto err_clk_register; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci ret = -ENOMEM; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* Clock for the host controller */ 35262306a36Sopenharmony_ci lpss->clock = clkdev_create(clk, lpss->info->clk_con_id, "%s", devname); 35362306a36Sopenharmony_ci if (!lpss->clock) 35462306a36Sopenharmony_ci goto err_clk_register; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci lpss->clk = clk; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cierr_clk_register: 36162306a36Sopenharmony_ci intel_lpss_unregister_clock_tree(clk); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return ret; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic void intel_lpss_unregister_clock(struct intel_lpss *lpss) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci if (IS_ERR_OR_NULL(lpss->clk)) 36962306a36Sopenharmony_ci return; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci clkdev_drop(lpss->clock); 37262306a36Sopenharmony_ci intel_lpss_unregister_clock_tree(lpss->clk); 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ciint intel_lpss_probe(struct device *dev, 37662306a36Sopenharmony_ci const struct intel_lpss_platform_info *info) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct intel_lpss *lpss; 37962306a36Sopenharmony_ci int ret; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (!info || !info->mem || info->irq <= 0) 38262306a36Sopenharmony_ci return -EINVAL; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci lpss = devm_kzalloc(dev, sizeof(*lpss), GFP_KERNEL); 38562306a36Sopenharmony_ci if (!lpss) 38662306a36Sopenharmony_ci return -ENOMEM; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci lpss->priv = devm_ioremap_uc(dev, info->mem->start + LPSS_PRIV_OFFSET, 38962306a36Sopenharmony_ci LPSS_PRIV_SIZE); 39062306a36Sopenharmony_ci if (!lpss->priv) 39162306a36Sopenharmony_ci return -ENOMEM; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci lpss->info = info; 39462306a36Sopenharmony_ci lpss->dev = dev; 39562306a36Sopenharmony_ci lpss->caps = readl(lpss->priv + LPSS_PRIV_CAPS); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci dev_set_drvdata(dev, lpss); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ret = intel_lpss_assign_devs(lpss); 40062306a36Sopenharmony_ci if (ret) 40162306a36Sopenharmony_ci return ret; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci lpss->cell->swnode = info->swnode; 40462306a36Sopenharmony_ci lpss->cell->ignore_resource_conflicts = info->ignore_resource_conflicts; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci intel_lpss_init_dev(lpss); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL); 40962306a36Sopenharmony_ci if (lpss->devid < 0) 41062306a36Sopenharmony_ci return lpss->devid; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ret = intel_lpss_register_clock(lpss); 41362306a36Sopenharmony_ci if (ret) 41462306a36Sopenharmony_ci goto err_clk_register; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci intel_lpss_ltr_expose(lpss); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = intel_lpss_debugfs_add(lpss); 41962306a36Sopenharmony_ci if (ret) 42062306a36Sopenharmony_ci dev_warn(dev, "Failed to create debugfs entries\n"); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (intel_lpss_has_idma(lpss)) { 42362306a36Sopenharmony_ci ret = mfd_add_devices(dev, lpss->devid, &intel_lpss_idma64_cell, 42462306a36Sopenharmony_ci 1, info->mem, info->irq, NULL); 42562306a36Sopenharmony_ci if (ret) 42662306a36Sopenharmony_ci dev_warn(dev, "Failed to add %s, fallback to PIO\n", 42762306a36Sopenharmony_ci LPSS_IDMA64_DRIVER_NAME); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci ret = mfd_add_devices(dev, lpss->devid, lpss->cell, 43162306a36Sopenharmony_ci 1, info->mem, info->irq, NULL); 43262306a36Sopenharmony_ci if (ret) 43362306a36Sopenharmony_ci goto err_remove_ltr; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cierr_remove_ltr: 44062306a36Sopenharmony_ci intel_lpss_debugfs_remove(lpss); 44162306a36Sopenharmony_ci intel_lpss_ltr_hide(lpss); 44262306a36Sopenharmony_ci intel_lpss_unregister_clock(lpss); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cierr_clk_register: 44562306a36Sopenharmony_ci ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci return ret; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_probe); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_civoid intel_lpss_remove(struct device *dev) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct intel_lpss *lpss = dev_get_drvdata(dev); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci mfd_remove_devices(dev); 45662306a36Sopenharmony_ci intel_lpss_debugfs_remove(lpss); 45762306a36Sopenharmony_ci intel_lpss_ltr_hide(lpss); 45862306a36Sopenharmony_ci intel_lpss_unregister_clock(lpss); 45962306a36Sopenharmony_ci ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_remove); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci#ifdef CONFIG_PM 46462306a36Sopenharmony_cistatic int resume_lpss_device(struct device *dev, void *data) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) 46762306a36Sopenharmony_ci pm_runtime_resume(dev); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return 0; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ciint intel_lpss_prepare(struct device *dev) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * Resume both child devices before entering system sleep. This 47662306a36Sopenharmony_ci * ensures that they are in proper state before they get suspended. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci device_for_each_child_reverse(dev, NULL, resume_lpss_device); 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_prepare); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ciint intel_lpss_suspend(struct device *dev) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct intel_lpss *lpss = dev_get_drvdata(dev); 48662306a36Sopenharmony_ci unsigned int i; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Save device context */ 48962306a36Sopenharmony_ci for (i = 0; i < LPSS_PRIV_REG_COUNT; i++) 49062306a36Sopenharmony_ci lpss->priv_ctx[i] = readl(lpss->priv + i * 4); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* 49362306a36Sopenharmony_ci * If the device type is not UART, then put the controller into 49462306a36Sopenharmony_ci * reset. UART cannot be put into reset since S3/S0ix fail when 49562306a36Sopenharmony_ci * no_console_suspend flag is enabled. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ci if (lpss->type != LPSS_DEV_UART) 49862306a36Sopenharmony_ci writel(0, lpss->priv + LPSS_PRIV_RESETS); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_suspend); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ciint intel_lpss_resume(struct device *dev) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct intel_lpss *lpss = dev_get_drvdata(dev); 50762306a36Sopenharmony_ci unsigned int i; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci intel_lpss_deassert_reset(lpss); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* Restore device context */ 51262306a36Sopenharmony_ci for (i = 0; i < LPSS_PRIV_REG_COUNT; i++) 51362306a36Sopenharmony_ci writel(lpss->priv_ctx[i], lpss->priv + i * 4); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_lpss_resume); 51862306a36Sopenharmony_ci#endif 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int __init intel_lpss_init(void) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci intel_lpss_debugfs = debugfs_create_dir("intel_lpss", NULL); 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_cimodule_init(intel_lpss_init); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void __exit intel_lpss_exit(void) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci ida_destroy(&intel_lpss_devid_ida); 53062306a36Sopenharmony_ci debugfs_remove(intel_lpss_debugfs); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_cimodule_exit(intel_lpss_exit); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciMODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); 53562306a36Sopenharmony_ciMODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); 53662306a36Sopenharmony_ciMODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>"); 53762306a36Sopenharmony_ciMODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>"); 53862306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel LPSS core driver"); 53962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 54062306a36Sopenharmony_ci/* 54162306a36Sopenharmony_ci * Ensure the DMA driver is loaded before the host controller device appears, 54262306a36Sopenharmony_ci * so that the host controller driver can request its DMA channels as early 54362306a36Sopenharmony_ci * as possible. 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * If the DMA module is not there that's OK as well. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ciMODULE_SOFTDEP("pre: platform:" LPSS_IDMA64_DRIVER_NAME); 548