From 95099d4622f8cb224d94e314c7a8e0df60b13f87 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Sat, 09 Dec 2023 08:38:01 +0000
Subject: [PATCH] enable docker ppp
---
kernel/drivers/mfd/madera-core.c | 254 +++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 207 insertions(+), 47 deletions(-)
diff --git a/kernel/drivers/mfd/madera-core.c b/kernel/drivers/mfd/madera-core.c
index 45c7d8b..4ed6ad8 100644
--- a/kernel/drivers/mfd/madera-core.c
+++ b/kernel/drivers/mfd/madera-core.c
@@ -1,12 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Core MFD support for Cirrus Logic Madera codecs
*
* Copyright (C) 2015-2018 Cirrus Logic
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2.
*/
#include <linux/device.h>
@@ -15,6 +11,7 @@
#include <linux/gpio.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
@@ -30,11 +27,16 @@
#include "madera.h"
+#define CS47L15_SILICON_ID 0x6370
#define CS47L35_SILICON_ID 0x6360
#define CS47L85_SILICON_ID 0x6338
#define CS47L90_SILICON_ID 0x6364
+#define CS47L92_SILICON_ID 0x6371
#define MADERA_32KZ_MCLK2 1
+
+#define MADERA_RESET_MIN_US 2000
+#define MADERA_RESET_MAX_US 3000
static const char * const madera_core_supplies[] = {
"AVDD",
@@ -42,7 +44,32 @@
};
static const struct mfd_cell madera_ldo1_devs[] = {
- { .name = "madera-ldo1" },
+ {
+ .name = "madera-ldo1",
+ .level = MFD_DEP_LEVEL_HIGH,
+ },
+};
+
+static const char * const cs47l15_supplies[] = {
+ "MICVDD",
+ "CPVDD1",
+ "SPKVDD",
+};
+
+static const struct mfd_cell cs47l15_devs[] = {
+ { .name = "madera-pinctrl", },
+ { .name = "madera-irq", },
+ { .name = "madera-gpio", },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l15_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
+ {
+ .name = "cs47l15-codec",
+ .parent_supplies = cs47l15_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs47l15_supplies),
+ },
};
static const char * const cs47l35_supplies[] = {
@@ -58,7 +85,11 @@
{ .name = "madera-irq", },
{ .name = "madera-micsupp", },
{ .name = "madera-gpio", },
- { .name = "madera-extcon", },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l35_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
{
.name = "cs47l35-codec",
.parent_supplies = cs47l35_supplies,
@@ -80,9 +111,13 @@
static const struct mfd_cell cs47l85_devs[] = {
{ .name = "madera-pinctrl", },
{ .name = "madera-irq", },
- { .name = "madera-micsupp" },
+ { .name = "madera-micsupp", },
{ .name = "madera-gpio", },
- { .name = "madera-extcon", },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l85_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
{
.name = "cs47l85-codec",
.parent_supplies = cs47l85_supplies,
@@ -104,7 +139,11 @@
{ .name = "madera-irq", },
{ .name = "madera-micsupp", },
{ .name = "madera-gpio", },
- { .name = "madera-extcon", },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l90_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
{
.name = "cs47l90-codec",
.parent_supplies = cs47l90_supplies,
@@ -112,10 +151,35 @@
},
};
+static const char * const cs47l92_supplies[] = {
+ "MICVDD",
+ "CPVDD1",
+ "CPVDD2",
+};
+
+static const struct mfd_cell cs47l92_devs[] = {
+ { .name = "madera-pinctrl", },
+ { .name = "madera-irq", },
+ { .name = "madera-micsupp", },
+ { .name = "madera-gpio", },
+ {
+ .name = "madera-extcon",
+ .parent_supplies = cs47l92_supplies,
+ .num_parent_supplies = 1, /* We only need MICVDD */
+ },
+ {
+ .name = "cs47l92-codec",
+ .parent_supplies = cs47l92_supplies,
+ .num_parent_supplies = ARRAY_SIZE(cs47l92_supplies),
+ },
+};
+
/* Used by madera-i2c and madera-spi drivers */
const char *madera_name_from_type(enum madera_type type)
{
switch (type) {
+ case CS47L15:
+ return "CS47L15";
case CS47L35:
return "CS47L35";
case CS47L85:
@@ -124,6 +188,12 @@
return "CS47L90";
case CS47L91:
return "CS47L91";
+ case CS42L92:
+ return "CS42L92";
+ case CS47L92:
+ return "CS47L92";
+ case CS47L93:
+ return "CS47L93";
case WM1840:
return "WM1840";
default:
@@ -132,32 +202,46 @@
}
EXPORT_SYMBOL_GPL(madera_name_from_type);
-#define MADERA_BOOT_POLL_MAX_INTERVAL_US 5000
-#define MADERA_BOOT_POLL_TIMEOUT_US 25000
+#define MADERA_BOOT_POLL_INTERVAL_USEC 5000
+#define MADERA_BOOT_POLL_TIMEOUT_USEC 25000
-static int madera_wait_for_boot(struct madera *madera)
+static int madera_wait_for_boot_noack(struct madera *madera)
{
- unsigned int val;
- int ret;
+ ktime_t timeout;
+ unsigned int val = 0;
+ int ret = 0;
/*
* We can't use an interrupt as we need to runtime resume to do so,
* so we poll the status bit. This won't race with the interrupt
* handler because it will be blocked on runtime resume.
+ * The chip could NAK a read request while it is booting so ignore
+ * errors from regmap_read.
*/
- ret = regmap_read_poll_timeout(madera->regmap,
- MADERA_IRQ1_RAW_STATUS_1,
- val,
- (val & MADERA_BOOT_DONE_STS1),
- MADERA_BOOT_POLL_MAX_INTERVAL_US,
- MADERA_BOOT_POLL_TIMEOUT_US);
+ timeout = ktime_add_us(ktime_get(), MADERA_BOOT_POLL_TIMEOUT_USEC);
+ regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val);
+ while (!(val & MADERA_BOOT_DONE_STS1) &&
+ !ktime_after(ktime_get(), timeout)) {
+ usleep_range(MADERA_BOOT_POLL_INTERVAL_USEC / 2,
+ MADERA_BOOT_POLL_INTERVAL_USEC);
+ regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val);
+ }
- if (ret)
- dev_err(madera->dev, "Polling BOOT_DONE_STS failed: %d\n", ret);
+ if (!(val & MADERA_BOOT_DONE_STS1)) {
+ dev_err(madera->dev, "Polling BOOT_DONE_STS timed out\n");
+ ret = -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static int madera_wait_for_boot(struct madera *madera)
+{
+ int ret = madera_wait_for_boot_noack(madera);
/*
* BOOT_DONE defaults to unmasked on boot so we must ack it.
- * Do this unconditionally to avoid interrupt storms.
+ * Do this even after a timeout to avoid interrupt storms.
*/
regmap_write(madera->regmap, MADERA_IRQ1_STATUS_1,
MADERA_BOOT_DONE_EINT1);
@@ -178,16 +262,13 @@
}
/* Allow time for internal clocks to startup after reset */
- usleep_range(1000, 2000);
+ usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
return 0;
}
static void madera_enable_hard_reset(struct madera *madera)
{
- if (!madera->pdata.reset)
- return;
-
/*
* There are many existing out-of-tree users of these codecs that we
* can't break so preserve the expected behaviour of setting the line
@@ -198,11 +279,9 @@
static void madera_disable_hard_reset(struct madera *madera)
{
- if (!madera->pdata.reset)
- return;
-
gpiod_set_raw_value_cansleep(madera->pdata.reset, 1);
- usleep_range(1000, 2000);
+
+ usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
}
static int __maybe_unused madera_runtime_resume(struct device *dev)
@@ -220,6 +299,8 @@
regcache_cache_only(madera->regmap, false);
regcache_cache_only(madera->regmap_32bit, false);
+
+ usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
ret = madera_wait_for_boot(madera);
if (ret)
@@ -271,10 +352,14 @@
EXPORT_SYMBOL_GPL(madera_pm_ops);
const struct of_device_id madera_of_match[] = {
+ { .compatible = "cirrus,cs47l15", .data = (void *)CS47L15 },
{ .compatible = "cirrus,cs47l35", .data = (void *)CS47L35 },
{ .compatible = "cirrus,cs47l85", .data = (void *)CS47L85 },
{ .compatible = "cirrus,cs47l90", .data = (void *)CS47L90 },
{ .compatible = "cirrus,cs47l91", .data = (void *)CS47L91 },
+ { .compatible = "cirrus,cs42l92", .data = (void *)CS42L92 },
+ { .compatible = "cirrus,cs47l92", .data = (void *)CS47L92 },
+ { .compatible = "cirrus,cs47l93", .data = (void *)CS47L93 },
{ .compatible = "cirrus,wm1840", .data = (void *)WM1840 },
{}
};
@@ -284,19 +369,14 @@
static int madera_get_reset_gpio(struct madera *madera)
{
struct gpio_desc *reset;
- int ret;
if (madera->pdata.reset)
return 0;
reset = devm_gpiod_get_optional(madera->dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(reset)) {
- ret = PTR_ERR(reset);
- if (ret != -EPROBE_DEFER)
- dev_err(madera->dev, "Failed to request /RESET: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(reset))
+ return dev_err_probe(madera->dev, PTR_ERR(reset),
+ "Failed to request /RESET");
/*
* A hard reset is needed for full reset of the chip. We allow running
@@ -319,6 +399,10 @@
* childbiases for each micbias. Unspecified values default to 0.
*/
switch (madera->type) {
+ case CS47L15:
+ madera->num_micbias = 1;
+ madera->num_childbias[0] = 3;
+ return;
case CS47L35:
madera->num_micbias = 2;
madera->num_childbias[0] = 2;
@@ -334,6 +418,13 @@
madera->num_micbias = 2;
madera->num_childbias[0] = 4;
madera->num_childbias[1] = 4;
+ return;
+ case CS42L92:
+ case CS47L92:
+ case CS47L93:
+ madera->num_micbias = 2;
+ madera->num_childbias[0] = 4;
+ madera->num_childbias[1] = 2;
return;
default:
return;
@@ -351,6 +442,8 @@
dev_set_drvdata(madera->dev, madera);
BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier);
+ mutex_init(&madera->dapm_ptr_lock);
+
madera_set_micbias_info(madera);
/*
@@ -361,6 +454,21 @@
memcpy(&madera->pdata, dev_get_platdata(madera->dev),
sizeof(madera->pdata));
}
+
+ madera->mclk[MADERA_MCLK1].id = "mclk1";
+ madera->mclk[MADERA_MCLK2].id = "mclk2";
+ madera->mclk[MADERA_MCLK3].id = "mclk3";
+
+ ret = devm_clk_bulk_get_optional(madera->dev, ARRAY_SIZE(madera->mclk),
+ madera->mclk);
+ if (ret) {
+ dev_err(madera->dev, "Failed to get clocks: %d\n", ret);
+ return ret;
+ }
+
+ /* Not using devm_clk_get to prevent breakage of existing DTs */
+ if (!madera->mclk[MADERA_MCLK2].clk)
+ dev_warn(madera->dev, "Missing MCLK2, requires 32kHz clock\n");
ret = madera_get_reset_gpio(madera);
if (ret)
@@ -380,9 +488,13 @@
* No devm_ because we need to control shutdown order of children.
*/
switch (madera->type) {
+ case CS47L15:
case CS47L35:
case CS47L90:
case CS47L91:
+ case CS42L92:
+ case CS47L92:
+ case CS47L93:
break;
case CS47L85:
case WM1840:
@@ -438,6 +550,12 @@
regcache_cache_only(madera->regmap, false);
regcache_cache_only(madera->regmap_32bit, false);
+ ret = madera_wait_for_boot_noack(madera);
+ if (ret) {
+ dev_err(madera->dev, "Device failed initial boot: %d\n", ret);
+ goto err_reset;
+ }
+
/*
* Now we can power up and verify that this is a chip we know about
* before we start doing any writes to its registers.
@@ -449,6 +567,19 @@
}
switch (hwid) {
+ case CS47L15_SILICON_ID:
+ if (IS_ENABLED(CONFIG_MFD_CS47L15)) {
+ switch (madera->type) {
+ case CS47L15:
+ patch_fn = &cs47l15_patch;
+ mfd_devs = cs47l15_devs;
+ n_devs = ARRAY_SIZE(cs47l15_devs);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
case CS47L35_SILICON_ID:
if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
switch (madera->type) {
@@ -490,6 +621,21 @@
}
}
break;
+ case CS47L92_SILICON_ID:
+ if (IS_ENABLED(CONFIG_MFD_CS47L92)) {
+ switch (madera->type) {
+ case CS42L92:
+ case CS47L92:
+ case CS47L93:
+ patch_fn = cs47l92_patch;
+ mfd_devs = cs47l92_devs;
+ n_devs = ARRAY_SIZE(cs47l92_devs);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
default:
dev_err(madera->dev, "Unknown device ID: %x\n", hwid);
ret = -EINVAL;
@@ -515,7 +661,7 @@
ret = madera_wait_for_boot(madera);
if (ret) {
- dev_err(madera->dev, "Device failed initial boot: %d\n", ret);
+ dev_err(madera->dev, "Failed to clear boot done: %d\n", ret);
goto err_reset;
}
@@ -540,13 +686,19 @@
}
/* Init 32k clock sourced from MCLK2 */
+ ret = clk_prepare_enable(madera->mclk[MADERA_MCLK2].clk);
+ if (ret) {
+ dev_err(madera->dev, "Failed to enable 32k clock: %d\n", ret);
+ goto err_reset;
+ }
+
ret = regmap_update_bits(madera->regmap,
MADERA_CLOCK_32K_1,
MADERA_CLK_32K_ENA_MASK | MADERA_CLK_32K_SRC_MASK,
MADERA_CLK_32K_ENA | MADERA_32KZ_MCLK2);
if (ret) {
dev_err(madera->dev, "Failed to init 32k clock: %d\n", ret);
- goto err_reset;
+ goto err_clock;
}
pm_runtime_set_active(madera->dev);
@@ -567,6 +719,8 @@
err_pm_runtime:
pm_runtime_disable(madera->dev);
+err_clock:
+ clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk);
err_reset:
madera_enable_hard_reset(madera);
regulator_disable(madera->dcvdd);
@@ -587,16 +741,22 @@
/* Prevent any IRQs being serviced while we clean up */
disable_irq(madera->irq);
- /*
- * DCVDD could be supplied by a child node, we must disable it before
- * removing the children, and prevent PM runtime from turning it back on
- */
+ pm_runtime_get_sync(madera->dev);
+
+ mfd_remove_devices(madera->dev);
+
pm_runtime_disable(madera->dev);
regulator_disable(madera->dcvdd);
regulator_put(madera->dcvdd);
- mfd_remove_devices(madera->dev);
+ mfd_remove_devices_late(madera->dev);
+
+ pm_runtime_set_suspended(madera->dev);
+ pm_runtime_put_noidle(madera->dev);
+
+ clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk);
+
madera_enable_hard_reset(madera);
regulator_bulk_disable(madera->num_core_supplies,
--
Gitblit v1.6.2