cs42l42.c (5982b5a8ec7ddb076e774bdd0b17d74681ab0943) cs42l42.c (f8593e88540052b3feaf1fb36f2c1c0484c9dc14)
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * cs42l42.c -- CS42L42 ALSA SoC audio driver
4 *
5 * Copyright 2016 Cirrus Logic, Inc.
6 *
7 * Author: James Schulman <james.schulman@cirrus.com>
8 * Author: Brian Austin <brian.austin@cirrus.com>

--- 1600 unchanged lines hidden (view full) ---

1609 unsigned int stickies[12];
1610 unsigned int masks[12];
1611 unsigned int current_plug_status;
1612 unsigned int current_button_status;
1613 unsigned int i;
1614 int report = 0;
1615
1616 mutex_lock(&cs42l42->irq_lock);
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * cs42l42.c -- CS42L42 ALSA SoC audio driver
4 *
5 * Copyright 2016 Cirrus Logic, Inc.
6 *
7 * Author: James Schulman <james.schulman@cirrus.com>
8 * Author: Brian Austin <brian.austin@cirrus.com>

--- 1600 unchanged lines hidden (view full) ---

1609 unsigned int stickies[12];
1610 unsigned int masks[12];
1611 unsigned int current_plug_status;
1612 unsigned int current_button_status;
1613 unsigned int i;
1614 int report = 0;
1615
1616 mutex_lock(&cs42l42->irq_lock);
1617 if (cs42l42->suspended) {
1618 mutex_unlock(&cs42l42->irq_lock);
1619 return IRQ_NONE;
1620 }
1617
1618 /* Read sticky registers to clear interurpt */
1619 for (i = 0; i < ARRAY_SIZE(stickies); i++) {
1620 regmap_read(cs42l42->regmap, irq_params_table[i].status_addr,
1621 &(stickies[i]));
1622 regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr,
1623 &(masks[i]));
1624 stickies[i] = stickies[i] & (~masks[i]) &

--- 417 unchanged lines hidden (view full) ---

2042 if (device_property_read_bool(dev, "cirrus,hs-bias-sense-disable"))
2043 cs42l42->hs_bias_sense_en = 0;
2044 else
2045 cs42l42->hs_bias_sense_en = 1;
2046
2047 return 0;
2048}
2049
1621
1622 /* Read sticky registers to clear interurpt */
1623 for (i = 0; i < ARRAY_SIZE(stickies); i++) {
1624 regmap_read(cs42l42->regmap, irq_params_table[i].status_addr,
1625 &(stickies[i]));
1626 regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr,
1627 &(masks[i]));
1628 stickies[i] = stickies[i] & (~masks[i]) &

--- 417 unchanged lines hidden (view full) ---

2046 if (device_property_read_bool(dev, "cirrus,hs-bias-sense-disable"))
2047 cs42l42->hs_bias_sense_en = 0;
2048 else
2049 cs42l42->hs_bias_sense_en = 1;
2050
2051 return 0;
2052}
2053
2054/* Datasheet suspend sequence */
2055static const struct reg_sequence __maybe_unused cs42l42_shutdown_seq[] = {
2056 REG_SEQ0(CS42L42_MIC_DET_CTL1, 0x9F),
2057 REG_SEQ0(CS42L42_ADC_OVFL_INT_MASK, 0x01),
2058 REG_SEQ0(CS42L42_MIXER_INT_MASK, 0x0F),
2059 REG_SEQ0(CS42L42_SRC_INT_MASK, 0x0F),
2060 REG_SEQ0(CS42L42_ASP_RX_INT_MASK, 0x1F),
2061 REG_SEQ0(CS42L42_ASP_TX_INT_MASK, 0x0F),
2062 REG_SEQ0(CS42L42_CODEC_INT_MASK, 0x03),
2063 REG_SEQ0(CS42L42_SRCPL_INT_MASK, 0x7F),
2064 REG_SEQ0(CS42L42_VPMON_INT_MASK, 0x01),
2065 REG_SEQ0(CS42L42_PLL_LOCK_INT_MASK, 0x01),
2066 REG_SEQ0(CS42L42_TSRS_PLUG_INT_MASK, 0x0F),
2067 REG_SEQ0(CS42L42_WAKE_CTL, 0xE1),
2068 REG_SEQ0(CS42L42_DET_INT1_MASK, 0xE0),
2069 REG_SEQ0(CS42L42_DET_INT2_MASK, 0xFF),
2070 REG_SEQ0(CS42L42_MIXER_CHA_VOL, 0x3F),
2071 REG_SEQ0(CS42L42_MIXER_ADC_VOL, 0x3F),
2072 REG_SEQ0(CS42L42_MIXER_CHB_VOL, 0x3F),
2073 REG_SEQ0(CS42L42_HP_CTL, 0x0F),
2074 REG_SEQ0(CS42L42_ASP_RX_DAI0_EN, 0x00),
2075 REG_SEQ0(CS42L42_ASP_CLK_CFG, 0x00),
2076 REG_SEQ0(CS42L42_HSDET_CTL2, 0x00),
2077 REG_SEQ0(CS42L42_PWR_CTL1, 0xFE),
2078 REG_SEQ0(CS42L42_PWR_CTL2, 0x8C),
2079 REG_SEQ0(CS42L42_DAC_CTL2, 0x02),
2080 REG_SEQ0(CS42L42_HS_CLAMP_DISABLE, 0x00),
2081 REG_SEQ0(CS42L42_MISC_DET_CTL, 0x03),
2082 REG_SEQ0(CS42L42_TIPSENSE_CTL, 0x02),
2083 REG_SEQ0(CS42L42_HSBIAS_SC_AUTOCTL, 0x03),
2084 REG_SEQ0(CS42L42_PWR_CTL1, 0xFF)
2085};
2086
2087static int __maybe_unused cs42l42_suspend(struct device *dev)
2088{
2089 struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
2090 unsigned int reg;
2091 u8 save_regs[ARRAY_SIZE(cs42l42_shutdown_seq)];
2092 int i, ret;
2093
2094 /*
2095 * Wait for threaded irq handler to be idle and stop it processing
2096 * future interrupts. This ensures a safe disable if the interrupt
2097 * is shared.
2098 */
2099 mutex_lock(&cs42l42->irq_lock);
2100 cs42l42->suspended = true;
2101
2102 /* Save register values that will be overwritten by shutdown sequence */
2103 for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) {
2104 regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, &reg);
2105 save_regs[i] = (u8)reg;
2106 }
2107
2108 /* Shutdown codec */
2109 regmap_multi_reg_write(cs42l42->regmap,
2110 cs42l42_shutdown_seq,
2111 ARRAY_SIZE(cs42l42_shutdown_seq));
2112
2113 /* All interrupt sources are now disabled */
2114 mutex_unlock(&cs42l42->irq_lock);
2115
2116 /* Wait for power-down complete */
2117 msleep(CS42L42_PDN_DONE_TIME_MS);
2118 ret = regmap_read_poll_timeout(cs42l42->regmap,
2119 CS42L42_CODEC_STATUS, reg,
2120 (reg & CS42L42_PDN_DONE_MASK),
2121 CS42L42_PDN_DONE_POLL_US,
2122 CS42L42_PDN_DONE_TIMEOUT_US);
2123 if (ret)
2124 dev_warn(dev, "Failed to get PDN_DONE: %d\n", ret);
2125
2126 /* Discharge FILT+ */
2127 regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL2,
2128 CS42L42_DISCHARGE_FILT_MASK, CS42L42_DISCHARGE_FILT_MASK);
2129 msleep(CS42L42_FILT_DISCHARGE_TIME_MS);
2130
2131 regcache_cache_only(cs42l42->regmap, true);
2132 gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
2133 regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies);
2134
2135 /* Restore register values to the regmap cache */
2136 for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i)
2137 regmap_write(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, save_regs[i]);
2138
2139 /* The cached address page register value is now stale */
2140 regcache_drop_region(cs42l42->regmap, CS42L42_PAGE_REGISTER, CS42L42_PAGE_REGISTER);
2141
2142 dev_dbg(dev, "System suspended\n");
2143
2144 return 0;
2145
2146}
2147
2148static int __maybe_unused cs42l42_resume(struct device *dev)
2149{
2150 struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
2151 int ret;
2152
2153 /*
2154 * If jack was unplugged and re-plugged during suspend it could
2155 * have changed type but the tip-sense state hasn't changed.
2156 * Force a plugged state to be re-evaluated.
2157 */
2158 if (cs42l42->plug_state != CS42L42_TS_UNPLUG)
2159 cs42l42->plug_state = CS42L42_TS_TRANS;
2160
2161 ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies);
2162 if (ret != 0) {
2163 dev_err(dev, "Failed to enable supplies: %d\n", ret);
2164 return ret;
2165 }
2166
2167 gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
2168 usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
2169
2170 regcache_cache_only(cs42l42->regmap, false);
2171 regcache_mark_dirty(cs42l42->regmap);
2172
2173 mutex_lock(&cs42l42->irq_lock);
2174 /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */
2175 regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
2176 regcache_sync(cs42l42->regmap);
2177
2178 cs42l42->suspended = false;
2179 mutex_unlock(&cs42l42->irq_lock);
2180
2181 dev_dbg(dev, "System resumed\n");
2182
2183 return 0;
2184}
2185
2050static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
2051 const struct i2c_device_id *id)
2052{
2053 struct cs42l42_private *cs42l42;
2054 int ret, i, devid;
2055 unsigned int reg;
2056
2057 cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private),

--- 154 unchanged lines hidden (view full) ---

2212 regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff);
2213
2214 gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
2215 regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies);
2216
2217 return 0;
2218}
2219
2186static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
2187 const struct i2c_device_id *id)
2188{
2189 struct cs42l42_private *cs42l42;
2190 int ret, i, devid;
2191 unsigned int reg;
2192
2193 cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private),

--- 154 unchanged lines hidden (view full) ---

2348 regmap_write(cs42l42->regmap, CS42L42_PWR_CTL1, 0xff);
2349
2350 gpiod_set_value_cansleep(cs42l42->reset_gpio, 0);
2351 regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), cs42l42->supplies);
2352
2353 return 0;
2354}
2355
2356static const struct dev_pm_ops cs42l42_pm_ops = {
2357 SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_resume)
2358};
2359
2220#ifdef CONFIG_OF
2221static const struct of_device_id cs42l42_of_match[] = {
2222 { .compatible = "cirrus,cs42l42", },
2223 {}
2224};
2225MODULE_DEVICE_TABLE(of, cs42l42_of_match);
2226#endif
2227

--- 10 unchanged lines hidden (view full) ---

2238 {}
2239};
2240
2241MODULE_DEVICE_TABLE(i2c, cs42l42_id);
2242
2243static struct i2c_driver cs42l42_i2c_driver = {
2244 .driver = {
2245 .name = "cs42l42",
2360#ifdef CONFIG_OF
2361static const struct of_device_id cs42l42_of_match[] = {
2362 { .compatible = "cirrus,cs42l42", },
2363 {}
2364};
2365MODULE_DEVICE_TABLE(of, cs42l42_of_match);
2366#endif
2367

--- 10 unchanged lines hidden (view full) ---

2378 {}
2379};
2380
2381MODULE_DEVICE_TABLE(i2c, cs42l42_id);
2382
2383static struct i2c_driver cs42l42_i2c_driver = {
2384 .driver = {
2385 .name = "cs42l42",
2386 .pm = &cs42l42_pm_ops,
2246 .of_match_table = of_match_ptr(cs42l42_of_match),
2247 .acpi_match_table = ACPI_PTR(cs42l42_acpi_match),
2248 },
2249 .id_table = cs42l42_id,
2250 .probe = cs42l42_i2c_probe,
2251 .remove = cs42l42_i2c_remove,
2252};
2253
2254module_i2c_driver(cs42l42_i2c_driver);
2255
2256MODULE_DESCRIPTION("ASoC CS42L42 driver");
2257MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
2258MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
2259MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>");
2260MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
2261MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
2262MODULE_AUTHOR("Vitaly Rodionov <vitalyr@opensource.cirrus.com>");
2263MODULE_LICENSE("GPL");
2387 .of_match_table = of_match_ptr(cs42l42_of_match),
2388 .acpi_match_table = ACPI_PTR(cs42l42_acpi_match),
2389 },
2390 .id_table = cs42l42_id,
2391 .probe = cs42l42_i2c_probe,
2392 .remove = cs42l42_i2c_remove,
2393};
2394
2395module_i2c_driver(cs42l42_i2c_driver);
2396
2397MODULE_DESCRIPTION("ASoC CS42L42 driver");
2398MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");
2399MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
2400MODULE_AUTHOR("Michael White, Cirrus Logic Inc, <michael.white@cirrus.com>");
2401MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
2402MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
2403MODULE_AUTHOR("Vitaly Rodionov <vitalyr@opensource.cirrus.com>");
2404MODULE_LICENSE("GPL");