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, ®); 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"); |