diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts index 7bbcb280b05f..9c765bcc1f2f 100644 --- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts +++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts @@ -27,34 +27,6 @@ serial1 = &uart11; }; - /* - * The sensor I2C bus sits on TLMM eGPIO pads that have no AP QUP - * function; on the stock OS it is driven by an island QUP of the - * Snapdragon Sensor Core (ADSP). From the AP the pads are only - * usable as software GPIOs, so bit-bang the bus. - * Devices on the bus: QMC6308 magnetometer @ 0x2c, SPL07 - * barometer @ 0x76, STK3BCx ALS/proximity @ 0x48. - */ - i2c-sensors { - compatible = "i2c-gpio"; - sda-gpios = <&tlmm 153 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; - scl-gpios = <&tlmm 154 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; - i2c-gpio,delay-us = <2>; - pinctrl-0 = <&sensor_i2c_default>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - - magnetometer@2c { - compatible = "qstcorp,qmc6308"; - reg = <0x2c>; - vdd-supply = <&vreg_l10b>; - mount-matrix = "0", "-1", "0", - "1", "0", "0", - "0", "0", "1"; - }; - }; - gpio-keys { compatible = "gpio-keys"; @@ -237,34 +209,14 @@ sound { compatible = "qcom,milos-sndcard", "qcom,sm8450-sndcard"; model = "Fairphone (Gen. 6)"; - audio-routing = "AMIC1", "MIC BIAS1", - "AMIC2", "MIC BIAS2", - "AMIC3", "MIC BIAS3", - "TX SWR_INPUT0", "ADC1_OUTPUT", - "TX SWR_INPUT1", "ADC2_OUTPUT", - "TX SWR_INPUT2", "ADC3_OUTPUT"; + // audio-routing = ... pinctrl-0 = <&lpi_i2s2_active>; pinctrl-1 = <&lpi_i2s2_sleep>; pinctrl-names = "default", "sleep"; - wcd-capture-dai-link { - link-name = "WCD Capture"; - - codec { - sound-dai = <&wcd9378 1>, <&swr2 0>, <&lpass_txmacro 0>; - }; - - cpu { - sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>; - }; - - platform { - sound-dai = <&q6apm>; - }; - }; - + /* i2s-dai-link { link-name = "Senary MI2S Playback"; @@ -280,29 +232,7 @@ sound-dai = <&q6apm>; }; }; - }; - - wcd9378: audio-codec { - compatible = "qcom,wcd9378-codec"; - - pinctrl-0 = <&wcd_reset_n_active>; - pinctrl-names = "default"; - - reset-gpios = <&tlmm 162 GPIO_ACTIVE_LOW>; - - vdd-buck-supply = <&vreg_l8b>; - vdd-rxtx-supply = <&vreg_l7b>; - vdd-io-supply = <&vreg_l7b>; - vdd-mic-bias-supply = <&vreg_bob>; - - qcom,micbias1-microvolt = <1800000>; - qcom,micbias2-microvolt = <1800000>; - qcom,micbias3-microvolt = <1800000>; - - qcom,rx-device = <&wcd9378_rx>; - qcom,tx-device = <&wcd9378_tx>; - - #sound-dai-cells = <1>; + */ }; thermal-zones { @@ -1175,36 +1105,6 @@ }; }; -&swr1 { - status = "okay"; - - /* WCD9378 RX */ - wcd9378_rx: codec@0,4 { - compatible = "sdw20217011000"; - reg = <0 4>; - qcom,rx-port-mapping = <1 2 3 4 5>; - }; -}; - -&swr2 { - status = "okay"; - - /* WCD9378 TX */ - wcd9378_tx: codec@0,3 { - compatible = "sdw20217011000"; - reg = <0 3>; - - /* - * WCD9378 TX port 1 (ADC1) <=> SWR2 port 1 (SWRM_TX1) - * WCD9378 TX port 2 (ADC2) <=> SWR2 port 1 - * WCD9378 TX port 3 (ADC3) <=> SWR2 port 1 - * WCD9378 TX port 4 (DMIC0,1, MBHC) <=> SWR2 port 2 - * WCD9378 TX port 5 (DMIC2..5) <=> SWR2 port 3 - */ - qcom,tx-port-mapping = <1 1 1 2 3>; - }; -}; - &tlmm { gpio-reserved-ranges = <8 4>, /* Fingerprint SPI */ <13 1>, /* NC */ @@ -1217,14 +1117,6 @@ bias-disable; }; - sensor_i2c_default: sensor-i2c-default-state { - /* SDA, SCL; external pull-ups to vreg_l10b */ - pins = "gpio153", "gpio154"; - function = "gpio"; - drive-strength = <2>; - bias-disable; - }; - ts_active: ts-irq-active-state { pins = "gpio19"; function = "gpio"; @@ -1365,13 +1257,6 @@ drive-strength = <2>; bias-pull-down; }; - - wcd_reset_n_active: wcd-reset-n-active-state { - pins = "gpio162"; - function = "gpio"; - drive-strength = <16>; - output-high; - }; }; &uart5 { diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 7cd4d751e1d2..fb313e591e85 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -198,17 +198,6 @@ config INFINEON_TLV493D To compile this driver as a module, choose M here: the module will be called tlv493d. -config QMC6308 - tristate "QST QMC6308 3-Axis Magnetic Sensor" - depends on I2C - select REGMAP_I2C - help - Say Y here to add support for the QST QMC6308 3-Axis - Magnetic Sensor. - - To compile this driver as a module, choose M here: the - module will be called qmc6308. - config SENSORS_HMC5843 tristate select IIO_BUFFER diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 59ea5cf17287..5bd227f8c120 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -26,8 +26,6 @@ obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o obj-$(CONFIG_INFINEON_TLV493D) += tlv493d.o -obj-$(CONFIG_QMC6308) += qmc6308.o - obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o diff --git a/drivers/iio/magnetometer/qmc6308.c b/drivers/iio/magnetometer/qmc6308.c deleted file mode 100644 index ceb4b98402bb..000000000000 --- a/drivers/iio/magnetometer/qmc6308.c +++ /dev/null @@ -1,590 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -/* - * Support for QST QMC6308 3-Axis Magnetic Sensor on I2C bus. - * - * Copyright (C) 2026 Jorijn van der Graaf - * - * Datasheet available at - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#define QMC6308_REG_ID 0x00 -#define QMC6308_REG_X_LSB 0x01 -#define QMC6308_REG_STATUS 0x09 -#define QMC6308_REG_CTRL1 0x0A -#define QMC6308_REG_CTRL2 0x0B -#define QMC6308_REG_CTRL3 0x0D -#define QMC6308_REG_CTRL4 0x29 - -#define QMC6308_CHIP_ID 0x80 - -/* Control register 1 */ -#define QMC6308_MODE_MASK GENMASK(1, 0) -#define QMC6308_ODR_MASK GENMASK(3, 2) -#define QMC6308_OSR1_MASK GENMASK(5, 4) -#define QMC6308_OSR2_MASK GENMASK(7, 6) - -#define QMC6308_MODE_SUSPEND 0x00 -#define QMC6308_MODE_NORMAL 0x01 - -#define QMC6308_ODR_10HZ 0x00 -#define QMC6308_ODR_50HZ 0x01 -#define QMC6308_ODR_100HZ 0x02 -#define QMC6308_ODR_200HZ 0x03 - -#define QMC6308_OSR1_8 0x00 -#define QMC6308_OSR1_4 0x01 -#define QMC6308_OSR1_2 0x02 -#define QMC6308_OSR1_1 0x03 - -/* Control register 2 */ -#define QMC6308_SET_RESET_MASK GENMASK(1, 0) -#define QMC6308_RNG_MASK GENMASK(3, 2) -#define QMC6308_SELF_TEST BIT(6) -#define QMC6308_SOFT_RST BIT(7) - -#define QMC6308_SET_RESET_ON 0x00 - -#define QMC6308_RNG_30G 0x00 -#define QMC6308_RNG_12G 0x01 -#define QMC6308_RNG_8G 0x02 -#define QMC6308_RNG_2G 0x03 - -/* Status register */ -#define QMC6308_STATUS_DRDY BIT(0) -#define QMC6308_STATUS_OVFL BIT(1) - -/* - * Power-on completion time (datasheet Table 7), also used as a - * conservative bound after soft reset, for which the datasheet - * gives no figure. - */ -#define QMC6308_POR_US 250 - -#define QMC6308_AUTOSUSPEND_DELAY_MS 500 - -struct qmc6308_data { - struct regmap *regmap; - /* - * Protect data->range/odr/osr. - * Protect poll and read during measurement (reading the status - * register clears DRDY). - */ - struct mutex mutex; - struct iio_mount_matrix orientation; - u8 range; - u8 odr; - u8 osr; -}; - -enum qmc6308_axis { - QMC6308_AXIS_X, - QMC6308_AXIS_Y, - QMC6308_AXIS_Z, -}; - -static const int qmc6308_odr_avail[] = { - [QMC6308_ODR_10HZ] = 10, - [QMC6308_ODR_50HZ] = 50, - [QMC6308_ODR_100HZ] = 100, - [QMC6308_ODR_200HZ] = 200, -}; - -static const int qmc6308_osr1_avail[] = { - [QMC6308_OSR1_8] = 8, - [QMC6308_OSR1_4] = 4, - [QMC6308_OSR1_2] = 2, - [QMC6308_OSR1_1] = 1, -}; - -/* - * Sensitivity is 1000/2500/3750/15000 LSB/Gauss for the - * +-30/12/8/2 Gauss ranges respectively. - */ -static const int qmc6308_scales[][2] = { - [QMC6308_RNG_30G] = { 0, 1000000 }, - [QMC6308_RNG_12G] = { 0, 400000 }, - [QMC6308_RNG_8G] = { 0, 266667 }, - [QMC6308_RNG_2G] = { 0, 66667 }, -}; - -static int qmc6308_set_mode(struct qmc6308_data *data, unsigned int mode) -{ - return regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, - QMC6308_MODE_MASK, - FIELD_PREP(QMC6308_MODE_MASK, mode)); -} - -static int qmc6308_take_measurement(struct iio_dev *indio_dev, int index, - int *val) -{ - struct qmc6308_data *data = iio_priv(indio_dev); - struct regmap *map = data->regmap; - struct device *dev = regmap_get_device(map); - unsigned int status; - __le16 buf[3]; - int ret; - - ret = pm_runtime_resume_and_get(dev); - if (ret) { - /* EACCES means a read raced runtime PM disable on suspend */ - if (ret != -EACCES) - dev_err(dev, "Failed to power on (%d)\n", ret); - return ret; - } - - scoped_guard(mutex, &data->mutex) { - /* 50ms headroom over the slowest ODR (10Hz) */ - ret = regmap_read_poll_timeout(map, QMC6308_REG_STATUS, - status, - (status & QMC6308_STATUS_DRDY), - 2 * USEC_PER_MSEC, - 150 * USEC_PER_MSEC); - if (ret) - goto out_rpm_put; - - ret = regmap_bulk_read(map, QMC6308_REG_X_LSB, buf, - sizeof(buf)); - if (ret) - goto out_rpm_put; - - if (status & QMC6308_STATUS_OVFL) - ret = -ERANGE; - } - -out_rpm_put: - pm_runtime_put_autosuspend(dev); - if (ret) - return ret; - - *val = (s16)le16_to_cpu(buf[index]); - - return 0; -} - -static int qmc6308_read_raw(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - int *val, int *val2, long mask) -{ - struct qmc6308_data *data = iio_priv(indio_dev); - int ret; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - ret = qmc6308_take_measurement(indio_dev, chan->address, val); - if (ret) - return ret; - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: { - guard(mutex)(&data->mutex); - - *val = qmc6308_scales[data->range][0]; - *val2 = qmc6308_scales[data->range][1]; - - return IIO_VAL_INT_PLUS_NANO; - } - case IIO_CHAN_INFO_SAMP_FREQ: { - guard(mutex)(&data->mutex); - - *val = qmc6308_odr_avail[data->odr]; - - return IIO_VAL_INT; - } - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { - guard(mutex)(&data->mutex); - - *val = qmc6308_osr1_avail[data->osr]; - - return IIO_VAL_INT; - } - default: - return -EINVAL; - } -} - -static int qmc6308_write_raw(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - int val, int val2, long mask) -{ - struct qmc6308_data *data = iio_priv(indio_dev); - unsigned int status; - unsigned int i; - int ret; - - switch (mask) { - case IIO_CHAN_INFO_SCALE: { - if (val != 0) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(qmc6308_scales); i++) { - if (val2 == qmc6308_scales[i][1]) - break; - } - if (i == ARRAY_SIZE(qmc6308_scales)) - return -EINVAL; - - guard(mutex)(&data->mutex); - - ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL2, - QMC6308_RNG_MASK, - FIELD_PREP(QMC6308_RNG_MASK, i)); - if (ret) - return ret; - - data->range = i; - - /* - * The data registers still hold (and DRDY still - * advertises) a sample converted at the previous range; - * discard it so that the next read returns data matching - * the new scale. - */ - return regmap_read(data->regmap, QMC6308_REG_STATUS, - &status); - } - case IIO_CHAN_INFO_SAMP_FREQ: { - for (i = 0; i < ARRAY_SIZE(qmc6308_odr_avail); i++) { - if (val == qmc6308_odr_avail[i]) - break; - } - if (i == ARRAY_SIZE(qmc6308_odr_avail)) - return -EINVAL; - - guard(mutex)(&data->mutex); - - ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, - QMC6308_ODR_MASK, - FIELD_PREP(QMC6308_ODR_MASK, i)); - if (ret) - return ret; - - data->odr = i; - - return 0; - } - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { - for (i = 0; i < ARRAY_SIZE(qmc6308_osr1_avail); i++) { - if (val == qmc6308_osr1_avail[i]) - break; - } - if (i == ARRAY_SIZE(qmc6308_osr1_avail)) - return -EINVAL; - - guard(mutex)(&data->mutex); - - ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, - QMC6308_OSR1_MASK, - FIELD_PREP(QMC6308_OSR1_MASK, i)); - if (ret) - return ret; - - data->osr = i; - - return 0; - } - default: - return -EINVAL; - } -} - -static int qmc6308_read_avail(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - const int **vals, int *type, int *length, - long mask) -{ - switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: - *vals = qmc6308_odr_avail; - *type = IIO_VAL_INT; - *length = ARRAY_SIZE(qmc6308_odr_avail); - return IIO_AVAIL_LIST; - case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - *vals = qmc6308_osr1_avail; - *type = IIO_VAL_INT; - *length = ARRAY_SIZE(qmc6308_osr1_avail); - return IIO_AVAIL_LIST; - case IIO_CHAN_INFO_SCALE: - *vals = (const int *)qmc6308_scales; - *type = IIO_VAL_INT_PLUS_NANO; - *length = ARRAY_SIZE(qmc6308_scales) * 2; - return IIO_AVAIL_LIST; - default: - return -EINVAL; - } -} - -static int qmc6308_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) -{ - switch (mask) { - case IIO_CHAN_INFO_SCALE: - return IIO_VAL_INT_PLUS_NANO; - default: - return IIO_VAL_INT; - } -} - -static const struct iio_mount_matrix * -qmc6308_get_mount_matrix(const struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) -{ - struct qmc6308_data *data = iio_priv(indio_dev); - - return &data->orientation; -} - -static const struct iio_chan_spec_ext_info qmc6308_ext_info[] = { - IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, qmc6308_get_mount_matrix), - { } -}; - -static const struct iio_info qmc6308_info = { - .read_raw = qmc6308_read_raw, - .write_raw = qmc6308_write_raw, - .read_avail = qmc6308_read_avail, - .write_raw_get_fmt = qmc6308_write_raw_get_fmt, -}; - -static int qmc6308_init(struct qmc6308_data *data) -{ - struct regmap *map = data->regmap; - unsigned int reg; - int ret; - - ret = regmap_read(map, QMC6308_REG_ID, ®); - if (ret) - return ret; - - /* Allow unknown IDs so that fallback compatibles work */ - if (reg != QMC6308_CHIP_ID) - dev_warn(regmap_get_device(map), - "Unknown chip id: 0x%02x, continuing\n", reg); - - /* The SOFT_RST bit is not auto-cleared and must be written back 0 */ - ret = regmap_write(map, QMC6308_REG_CTRL2, QMC6308_SOFT_RST); - if (ret) - return ret; - - fsleep(QMC6308_POR_US); - - data->range = QMC6308_RNG_30G; - - ret = regmap_write(map, QMC6308_REG_CTRL2, - FIELD_PREP(QMC6308_SET_RESET_MASK, - QMC6308_SET_RESET_ON) | - FIELD_PREP(QMC6308_RNG_MASK, data->range)); - if (ret) - return ret; - - data->odr = QMC6308_ODR_50HZ; - data->osr = QMC6308_OSR1_8; - - return regmap_write(map, QMC6308_REG_CTRL1, - FIELD_PREP(QMC6308_MODE_MASK, - QMC6308_MODE_NORMAL) | - FIELD_PREP(QMC6308_ODR_MASK, data->odr) | - FIELD_PREP(QMC6308_OSR1_MASK, data->osr)); -} - -static void qmc6308_power_down_action(void *priv) -{ - struct qmc6308_data *data = priv; - - if (!pm_runtime_status_suspended(regmap_get_device(data->regmap))) - qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); -} - -static bool qmc6308_volatile_reg(struct device *dev, unsigned int reg) -{ - return reg >= QMC6308_REG_X_LSB && reg <= QMC6308_REG_STATUS; -} - -static bool qmc6308_writable_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case QMC6308_REG_CTRL1: - case QMC6308_REG_CTRL2: - case QMC6308_REG_CTRL3: - case QMC6308_REG_CTRL4: - return true; - default: - return false; - } -} - -static const struct regmap_config qmc6308_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = QMC6308_REG_CTRL4, - .cache_type = REGCACHE_MAPLE, - .volatile_reg = qmc6308_volatile_reg, - .writeable_reg = qmc6308_writable_reg, -}; - -#define QMC6308_CHANNEL(_axis) \ - { \ - .type = IIO_MAGN, \ - .modified = 1, \ - .channel2 = IIO_MOD_##_axis, \ - .address = QMC6308_AXIS_##_axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - .info_mask_shared_by_type_available = \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ - .ext_info = qmc6308_ext_info, \ - } - -static const struct iio_chan_spec qmc6308_channels[] = { - QMC6308_CHANNEL(X), - QMC6308_CHANNEL(Y), - QMC6308_CHANNEL(Z), -}; - -static int qmc6308_probe(struct i2c_client *client) -{ - struct device *dev = &client->dev; - struct qmc6308_data *data; - struct iio_dev *indio_dev; - struct regmap *map; - int ret; - - indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - - i2c_set_clientdata(client, indio_dev); - - map = devm_regmap_init_i2c(client, &qmc6308_regmap_config); - if (IS_ERR(map)) - return dev_err_probe(dev, PTR_ERR(map), - "regmap initialization failed\n"); - - ret = devm_regulator_get_enable(dev, "vdd"); - if (ret) - return dev_err_probe(dev, ret, - "Failed to enable VDD regulator\n"); - - fsleep(QMC6308_POR_US); - - data = iio_priv(indio_dev); - data->regmap = map; - - ret = devm_mutex_init(dev, &data->mutex); - if (ret) - return ret; - - ret = iio_read_mount_matrix(dev, &data->orientation); - if (ret) - return dev_err_probe(dev, ret, - "Failed to read mount matrix\n"); - - indio_dev->name = "qmc6308"; - indio_dev->info = &qmc6308_info; - indio_dev->channels = qmc6308_channels; - indio_dev->num_channels = ARRAY_SIZE(qmc6308_channels); - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = qmc6308_init(data); - if (ret) - return dev_err_probe(dev, ret, "qmc6308 init failed\n"); - - pm_runtime_set_active(dev); - - ret = devm_add_action_or_reset(dev, qmc6308_power_down_action, data); - if (ret) - return ret; - - pm_runtime_get_noresume(dev); - pm_runtime_use_autosuspend(dev); - pm_runtime_set_autosuspend_delay(dev, QMC6308_AUTOSUSPEND_DELAY_MS); - ret = devm_pm_runtime_enable(dev); - if (ret) - return ret; - - pm_runtime_put_autosuspend(dev); - - return devm_iio_device_register(dev, indio_dev); -} - -static int qmc6308_runtime_suspend(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct qmc6308_data *data = iio_priv(indio_dev); - - return qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); -} - -static int qmc6308_runtime_resume(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct qmc6308_data *data = iio_priv(indio_dev); - unsigned int status; - int ret; - - ret = qmc6308_set_mode(data, QMC6308_MODE_NORMAL); - if (ret) - return ret; - - /* - * DRDY may still be set for a sample converted before the last - * suspend; clear it so the next read waits for fresh data. - */ - return regmap_read(data->regmap, QMC6308_REG_STATUS, &status); -} - -static DEFINE_RUNTIME_DEV_PM_OPS(qmc6308_pm_ops, qmc6308_runtime_suspend, - qmc6308_runtime_resume, NULL); - -static const struct of_device_id qmc6308_match[] = { - { .compatible = "qstcorp,qmc6308" }, - { } -}; -MODULE_DEVICE_TABLE(of, qmc6308_match); - -static const struct i2c_device_id qmc6308_id[] = { - { .name = "qmc6308" }, - { } -}; -MODULE_DEVICE_TABLE(i2c, qmc6308_id); - -static struct i2c_driver qmc6308_driver = { - .driver = { - .name = "qmc6308", - .of_match_table = qmc6308_match, - .pm = pm_ptr(&qmc6308_pm_ops), - }, - .id_table = qmc6308_id, - .probe = qmc6308_probe, -}; -module_i2c_driver(qmc6308_driver); - -MODULE_DESCRIPTION("QST QMC6308 3-Axis Magnetic Sensor driver"); -MODULE_AUTHOR("Jorijn van der Graaf "); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 9d8aa6a75c48..3d8f5a81eff1 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -976,20 +976,6 @@ static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus, struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); int ret, i, len; - if (msg->page) { - ret = qcom_swrm_cmd_fifo_wr_cmd(ctrl, msg->addr_page1, - msg->dev_num, - SDW_SCP_ADDRPAGE1); - if (ret) - return SDW_CMD_IGNORED; - - ret = qcom_swrm_cmd_fifo_wr_cmd(ctrl, msg->addr_page2, - msg->dev_num, - SDW_SCP_ADDRPAGE2); - if (ret) - return SDW_CMD_IGNORED; - } - if (msg->flags == SDW_MSG_FLAG_READ) { for (i = 0; i < msg->len;) { len = min(msg->len - i, QCOM_SWRM_MAX_RD_LEN); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index d902df62b184..269c31ce0814 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -301,7 +301,6 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WCD9335 imply SND_SOC_WCD934X imply SND_SOC_WCD937X_SDW - imply SND_SOC_WCD9378_SDW imply SND_SOC_WCD938X_SDW imply SND_SOC_WCD939X_SDW imply SND_SOC_LPASS_MACRO_COMMON @@ -2432,24 +2431,6 @@ config SND_SOC_WCD937X_SDW via soundwire. To compile this codec driver say Y or m. -config SND_SOC_WCD9378 - depends on SND_SOC_WCD9378_SDW - tristate - depends on SOUNDWIRE || !SOUNDWIRE - select SND_SOC_WCD_COMMON - -config SND_SOC_WCD9378_SDW - tristate "WCD9378 Codec - SDW" - select SND_SOC_WCD9378 - depends on SOUNDWIRE - select REGMAP_SOUNDWIRE - help - The WCD9378 is an audio codec IC connected to the host over - SoundWire, found on Qualcomm SM7635 boards such as the - Fairphone 6. It has three ADCs for analog microphones, mic - bias supplies, headphone/earpiece outputs and MBHC. - To compile this codec driver say Y or m. - config SND_SOC_WCD938X depends on SND_SOC_WCD938X_SDW tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 73eaf37fd4a5..172861d17cfd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -356,8 +356,6 @@ snd-soc-wcd9335-y := wcd9335.o snd-soc-wcd934x-y := wcd934x.o snd-soc-wcd937x-y := wcd937x.o snd-soc-wcd937x-sdw-y := wcd937x-sdw.o -snd-soc-wcd9378-y := wcd9378.o -snd-soc-wcd9378-sdw-y := wcd9378-sdw.o snd-soc-wcd938x-y := wcd938x.o snd-soc-wcd938x-sdw-y := wcd938x-sdw.o snd-soc-wcd939x-y := wcd939x.o @@ -798,11 +796,6 @@ ifdef CONFIG_SND_SOC_WCD937X_SDW # avoid link failure by forcing sdw code built-in when needed obj-$(CONFIG_SND_SOC_WCD937X) += snd-soc-wcd937x-sdw.o endif -obj-$(CONFIG_SND_SOC_WCD9378) += snd-soc-wcd9378.o -ifdef CONFIG_SND_SOC_WCD9378_SDW -# avoid link failure by forcing sdw code built-in when needed -obj-$(CONFIG_SND_SOC_WCD9378) += snd-soc-wcd9378-sdw.o -endif obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x.o ifdef CONFIG_SND_SOC_WCD938X_SDW # avoid link failure by forcing sdw code built-in when needed diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c index dbdf51188cf5..a6805d5405cd 100644 --- a/sound/soc/codecs/aw88261.c +++ b/sound/soc/codecs/aw88261.c @@ -10,12 +10,9 @@ #include #include -#include #include #include #include -#include -#include #include "aw88261.h" #include "aw88395/aw88395_data_type.h" #include "aw88395/aw88395_device.h" @@ -30,10 +27,64 @@ static const struct regmap_config aw88261_remap_config = { static void aw88261_dev_set_volume(struct aw_device *aw_dev, unsigned int value) { - unsigned int volume = min(value, (unsigned int)AW88261_MUTE_VOL); + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int real_value, volume; + unsigned int reg_value; - regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL2_REG, - ~AW88261_VOL_MASK, DB_TO_REG_VAL(volume)); + volume = min((value + vol_desc->init_volume), (unsigned int)AW88261_MUTE_VOL); + real_value = DB_TO_REG_VAL(volume); + + regmap_read(aw_dev->regmap, AW88261_SYSCTRL2_REG, ®_value); + + real_value = (real_value | (reg_value & AW88261_VOL_START_MASK)); + + dev_dbg(aw_dev->dev, "value 0x%x , real_value:0x%x", value, real_value); + + regmap_write(aw_dev->regmap, AW88261_SYSCTRL2_REG, real_value); +} + +static void aw88261_dev_fade_in(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_in_vol = desc->ctl_volume; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_in_time == 0) { + aw88261_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88261_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw88261_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, + aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw88261_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw88261_dev_fade_out(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_out_time == 0) { + aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88261_MUTE_VOL; i += fade_step) { + aw88261_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88261_MUTE_VOL) { + aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } } static void aw88261_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) @@ -69,13 +120,13 @@ static void aw88261_dev_amppd(struct aw_device *aw_dev, bool amppd) static void aw88261_dev_mute(struct aw_device *aw_dev, bool is_mute) { if (is_mute) { - aw88261_dev_set_volume(aw_dev, AW88261_MUTE_VOL); + aw88261_dev_fade_out(aw_dev); regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, ~AW88261_HMUTE_MASK, AW88261_HMUTE_ENABLE_VALUE); } else { regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, ~AW88261_HMUTE_MASK, AW88261_HMUTE_DISABLE_VALUE); - aw88261_dev_set_volume(aw_dev, aw_dev->volume_desc.ctl_volume); + aw88261_dev_fade_in(aw_dev); } } @@ -100,21 +151,21 @@ static int aw88261_dev_get_iis_status(struct aw_device *aw_dev) if (ret) return ret; if ((reg_val & AW88261_BIT_PLL_CHECK) != AW88261_BIT_PLL_CHECK) { - dev_dbg(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val); + dev_err(aw_dev->dev, "check pll lock fail,reg_val:0x%04x", reg_val); return -EINVAL; } return ret; } -static int aw88261_dev_check_pll(struct aw_device *aw_dev) +static int aw88261_dev_check_mode1_pll(struct aw_device *aw_dev) { int ret, i; for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { ret = aw88261_dev_get_iis_status(aw_dev); if (ret) { - dev_dbg(aw_dev->dev, "mode1 iis signal check error"); + dev_err(aw_dev->dev, "mode1 iis signal check error"); usleep_range(AW88261_2000_US, AW88261_2000_US + 10); } else { return ret; @@ -124,74 +175,71 @@ static int aw88261_dev_check_pll(struct aw_device *aw_dev) return -EPERM; } -static int aw88261_dev_configure_syspll(struct aw88261 *aw88261) +static int aw88261_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88261_PLLCTRL1_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88261_CCO_MUX_MASK); + if (reg_val == AW88261_CCO_MUX_DIVIDED_VALUE) { + dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); + return -EPERM; + } + + /* change mode2 */ + ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG, + ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG, + ~AW88261_CCO_MUX_MASK, AW88261_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + for (i = 0; i < AW88261_DEV_SYSST_CHECK_MAX; i++) { + ret = aw88261_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); + usleep_range(AW88261_2000_US, AW88261_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +static int aw88261_dev_check_syspll(struct aw_device *aw_dev) { - struct aw_device *aw_dev = aw88261->aw_pa; int ret; - /* Configure TDM slots (I2S is represented as no slots) */ - ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL2_REG, - ~AW88261_SLOT_NUM_MASK, aw88261->slot_num_value); - if (ret) - return ret; + ret = aw88261_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw88261_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } - ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL2_REG, - ~AW88261_I2S_TX_SLOTVLD_MASK, - aw88261->tx_slotvld_mask); - if (ret) - return ret; - - ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL2_REG, - ~AW88261_I2S_RXL_SLOTVLD_MASK, - aw88261->rxl_slotvld_mask); - if (ret) - return ret; - - ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL2_REG, - ~AW88261_I2S_RXR_SLOTVLD_MASK, - aw88261->rxr_slotvld_mask); - if (ret) - return ret; - - /* PLL divider must be used for 8/16/32 kHz modes */ - ret = regmap_update_bits(aw_dev->regmap, AW88261_PLLCTRL1_REG, - ~AW88261_CCO_MUX_MASK, aw88261->cco_mux_value); - if (ret) - return ret; - - /* The word clock (WCK) defines the beginning of a frame */ - ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL1_REG, - ~AW88261_I2SSR_MASK, aw88261->sr_value); - if (ret) - return ret; - - /* The bit clock (BCK) defines the length of a frame */ - ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL1_REG, - ~AW88261_I2SBCK_MASK, - (aw88261->tdm_bck_value != AW88261_TDM_BCK_UNSET) - ? aw88261->tdm_bck_value : aw88261->bck_value); - if (ret) - return ret; - - /* The logical frame size is the width of data for 1 slot */ - ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL1_REG, - ~AW88261_I2SFS_MASK, aw88261->fs_value); - if (ret) - return ret; - - /* The I2S interface mode (Philips standard, LSB/MSB justified) */ - ret = regmap_update_bits(aw_dev->regmap, AW88261_I2SCTRL1_REG, - ~AW88261_I2SMD_MASK, aw88261->md_value); - if (ret) - return ret; - - /* The polarity of the bit clock (BCK) */ - ret = regmap_update_bits(aw_dev->regmap, AW88261_SYSCTRL_REG, - ~AW88261_BCKINV_MASK, aw88261->bck_inv_value); - if (ret) - return ret; - - return aw88261_dev_check_pll(aw_dev); + return ret; } static int aw88261_dev_check_sysst(struct aw_device *aw_dev) @@ -206,10 +254,10 @@ static int aw88261_dev_check_sysst(struct aw_device *aw_dev) return ret; check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK) - & AW88261_BIT_PLL_CHECK; - if (check_val != AW88261_BIT_PLL_CHECK) { - dev_dbg(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", - reg_val, AW88261_BIT_PLL_CHECK); + & AW88261_BIT_SYSST_CHECK; + if (check_val != AW88261_BIT_SYSST_CHECK) { + dev_err(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x", + reg_val, AW88261_BIT_SYSST_CHECK); usleep_range(AW88261_2000_US, AW88261_2000_US + 10); } else { return 0; @@ -236,22 +284,22 @@ static void aw88261_reg_force_set(struct aw88261 *aw88261) if (aw88261->frcset_en == AW88261_FRCSET_ENABLE) { /* set FORCE_PWM */ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL3_REG, - ~AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE); + AW88261_FORCE_PWM_MASK, AW88261_FORCE_PWM_FORCEMINUS_PWM_VALUE); /* set BOOST_OS_WIDTH */ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL5_REG, - ~AW88261_BST_OS_WIDTH_MASK, AW88261_BST_OS_WIDTH_50NS_VALUE); + AW88261_BST_OS_WIDTH_MASK, AW88261_BST_OS_WIDTH_50NS_VALUE); /* set BURST_LOOPR */ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL6_REG, - ~AW88261_BST_LOOPR_MASK, AW88261_BST_LOOPR_340K_VALUE); + AW88261_BST_LOOPR_MASK, AW88261_BST_LOOPR_340K_VALUE); /* set RSQN_DLY */ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL7_REG, - ~AW88261_RSQN_DLY_MASK, AW88261_RSQN_DLY_35NS_VALUE); + AW88261_RSQN_DLY_MASK, AW88261_RSQN_DLY_35NS_VALUE); /* set BURST_SSMODE */ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL8_REG, - ~AW88261_BURST_SSMODE_MASK, AW88261_BURST_SSMODE_FAST_VALUE); + AW88261_BURST_SSMODE_MASK, AW88261_BURST_SSMODE_FAST_VALUE); /* set BST_BURST */ regmap_update_bits(aw88261->regmap, AW88261_BSTCTRL9_REG, - ~AW88261_BST_BURST_MASK, AW88261_BST_BURST_30MA_VALUE); + AW88261_BST_BURST_MASK, AW88261_BST_BURST_30MA_VALUE); } else { dev_dbg(aw88261->aw_pa->dev, "needn't set reg value"); } @@ -502,7 +550,7 @@ static int aw88261_dev_start(struct aw88261 *aw88261) int ret; if (aw_dev->status == AW88261_DEV_PW_ON) { - dev_dbg(aw_dev->dev, "already power on"); + dev_info(aw_dev->dev, "already power on"); return 0; } @@ -510,9 +558,9 @@ static int aw88261_dev_start(struct aw88261 *aw88261) aw88261_dev_pwd(aw_dev, false); usleep_range(AW88261_2000_US, AW88261_2000_US + 10); - ret = aw88261_dev_configure_syspll(aw88261); + ret = aw88261_dev_check_syspll(aw_dev); if (ret) { - dev_dbg(aw_dev->dev, "pll check failed"); + dev_err(aw_dev->dev, "pll check failed cannot start"); goto pll_check_fail; } @@ -523,7 +571,7 @@ static int aw88261_dev_start(struct aw88261 *aw88261) /* check i2s status */ ret = aw88261_dev_check_sysst(aw_dev); if (ret) { - dev_dbg(aw_dev->dev, "sysst check failed"); + dev_err(aw_dev->dev, "sysst check failed"); goto sysst_check_fail; } @@ -624,25 +672,31 @@ static void aw88261_start_pa(struct aw88261 *aw88261) for (i = 0; i < AW88261_START_RETRIES; i++) { ret = aw88261_reg_update(aw88261, aw88261->phase_sync); if (ret) { - dev_dbg(aw88261->aw_pa->dev, - "aw88261_reg_update failed, cnt:%d, ret:%d\n", i, ret); + dev_err(aw88261->aw_pa->dev, "fw update failed, cnt:%d\n", i); continue; } ret = aw88261_dev_start(aw88261); if (ret) { - dev_dbg(aw88261->aw_pa->dev, - "aw88261_dev_start failed, cnt:%d, ret:%d\n", i, ret); + dev_err(aw88261->aw_pa->dev, "aw88261 device start failed. retry = %d", i); continue; } else { - dev_dbg(aw88261->aw_pa->dev, "start success\n"); + dev_info(aw88261->aw_pa->dev, "start success\n"); break; } } - if (ret != 0) - dev_err(aw88261->aw_pa->dev, "start failure (%d)\n", ret); } -static void aw88261_start(struct aw88261 *aw88261) +static void aw88261_startup_work(struct work_struct *work) +{ + struct aw88261 *aw88261 = + container_of(work, struct aw88261, start_work.work); + + mutex_lock(&aw88261->lock); + aw88261_start_pa(aw88261); + mutex_unlock(&aw88261->lock); +} + +static void aw88261_start(struct aw88261 *aw88261, bool sync_start) { if (aw88261->aw_pa->fw_status != AW88261_DEV_FW_OK) return; @@ -650,226 +704,14 @@ static void aw88261_start(struct aw88261 *aw88261) if (aw88261->aw_pa->status == AW88261_DEV_PW_ON) return; - aw88261_start_pa(aw88261); + if (sync_start == AW88261_SYNC_START) + aw88261_start_pa(aw88261); + else + queue_delayed_work(system_dfl_wq, + &aw88261->start_work, + AW88261_START_WORK_DELAY_MS); } -static int aw88261_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) -{ - struct snd_soc_component *component = dai->component; - struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); - - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - aw88261->bck_inv_value = AW88261_BCKINV_NOT_INVERT_VALUE; - break; - case SND_SOC_DAIFMT_IB_NF: - aw88261->bck_inv_value = AW88261_BCKINV_INVERTED_VALUE; - break; - default: - dev_err(aw88261->aw_pa->dev, "unsupported invert mode 0x%x\n", - fmt & SND_SOC_DAIFMT_INV_MASK); - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_DSP_A: - aw88261->md_value = AW88261_I2SMD_PHILIPS_STANDARD_VALUE; - break; - case SND_SOC_DAIFMT_MSB: - case SND_SOC_DAIFMT_DSP_B: - aw88261->md_value = AW88261_I2SMD_MSB_JUSTIFIED_VALUE; - break; - case SND_SOC_DAIFMT_LSB: - aw88261->md_value = AW88261_I2SMD_LSB_JUSTIFIED_VALUE; - break; - default: - dev_err(aw88261->aw_pa->dev, "unsupported DAI format 0x%x\n", - fmt & SND_SOC_DAIFMT_FORMAT_MASK); - return -EINVAL; - } - - return 0; -} - -static int aw88261_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - return 0; - - aw88261->cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE; - switch (params_rate(params)) { - case 8000: - aw88261->sr_value = AW88261_I2SSR_8KHZ_VALUE; - aw88261->cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE; - break; - case 11025: - aw88261->sr_value = AW88261_I2SSR_11P025KHZ_VALUE; - break; - case 12000: - aw88261->sr_value = AW88261_I2SSR_12KHZ_VALUE; - break; - case 16000: - aw88261->sr_value = AW88261_I2SSR_16KHZ_VALUE; - aw88261->cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE; - break; - case 22050: - aw88261->sr_value = AW88261_I2SSR_22P05KHZ_VALUE; - break; - case 24000: - aw88261->sr_value = AW88261_I2SSR_24KHZ_VALUE; - break; - case 32000: - aw88261->sr_value = AW88261_I2SSR_32KHZ_VALUE; - aw88261->cco_mux_value = AW88261_CCO_MUX_DIVIDED_VALUE; - break; - case 44100: - aw88261->sr_value = AW88261_I2SSR_44P1KHZ_VALUE; - break; - case 48000: - aw88261->sr_value = AW88261_I2SSR_48KHZ_VALUE; - break; - case 96000: - aw88261->sr_value = AW88261_I2SSR_96KHZ_VALUE; - break; - case 192000: - aw88261->sr_value = AW88261_I2SSR_192KHZ_VALUE; - break; - default: - dev_err(aw88261->aw_pa->dev, "unsupported sample rate %d\n", - params_rate(params)); - return -EINVAL; - } - - switch (params_width(params)) { - case 16: - aw88261->fs_value = AW88261_I2SFS_16_BITS_VALUE; - break; - case 20: - aw88261->fs_value = AW88261_I2SFS_20_BITS_VALUE; - break; - case 24: - aw88261->fs_value = AW88261_I2SFS_24_BITS_VALUE; - break; - case 32: - aw88261->fs_value = AW88261_I2SFS_32_BITS_VALUE; - break; - default: - dev_err(aw88261->aw_pa->dev, "unsupported bit width %d\n", - params_width(params)); - return -EINVAL; - } - - switch (params_physical_width(params)) { - case 16: - aw88261->bck_value = AW88261_I2SBCK_32FS_VALUE; - break; - case 24: - aw88261->bck_value = AW88261_I2SBCK_48FS_VALUE; - break; - case 32: - aw88261->bck_value = AW88261_I2SBCK_64FS_VALUE; - break; - default: - dev_err(aw88261->aw_pa->dev, "unsupported physical bit width %d\n", - params_physical_width(params)); - return -EINVAL; - } - - return 0; -} - -static int aw88261_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) -{ - struct snd_soc_component *component = dai->component; - struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); - int chan; - - switch (slots) { - case 0: - /* Just reset everything TDM related to I2S values */ - aw88261->slot_num_value = AW88261_SLOT_NUM_I2S_MODE_VALUE; - aw88261->tdm_bck_value = AW88261_TDM_BCK_UNSET; - aw88261->tx_slotvld_mask = 0 << AW88261_I2S_TX_SLOTVLD_START_BIT; - aw88261->rxl_slotvld_mask = 0 << AW88261_I2S_RXL_SLOTVLD_START_BIT; - aw88261->rxr_slotvld_mask = 1 << AW88261_I2S_RXR_SLOTVLD_START_BIT; - return 0; - case 1: - aw88261->slot_num_value = AW88261_SLOT_NUM_TDM1S_VALUE; - break; - case 2: - aw88261->slot_num_value = AW88261_SLOT_NUM_TDM2S_VALUE; - break; - case 4: - aw88261->slot_num_value = AW88261_SLOT_NUM_TDM4S_VALUE; - break; - case 6: - aw88261->slot_num_value = AW88261_SLOT_NUM_TDM6S_VALUE; - break; - case 8: - aw88261->slot_num_value = AW88261_SLOT_NUM_TDM8S_VALUE; - break; - case 16: - aw88261->slot_num_value = AW88261_SLOT_NUM_TDM16S_VALUE; - break; - default: - dev_err(aw88261->aw_pa->dev, "unsupported slot count %d\n", slots); - return -EINVAL; - } - - switch (slot_width) { - case 16: - aw88261->tdm_bck_value = AW88261_I2SBCK_32FS_VALUE; - break; - case 20: - case 24: - aw88261->tdm_bck_value = AW88261_I2SBCK_48FS_VALUE; - break; - case 32: - aw88261->tdm_bck_value = AW88261_I2SBCK_64FS_VALUE; - break; - default: - dev_err(aw88261->aw_pa->dev, "unsupported slot width %d\n", - slot_width); - return -EINVAL; - } - - if (tx_mask != 0) { - if ((chan = __ffs(tx_mask)) > 16) - return -EINVAL; - - aw88261->tx_slotvld_mask = chan << AW88261_I2S_TX_SLOTVLD_START_BIT; - } - - if (rx_mask != 0) { - if ((chan = __ffs(rx_mask)) > 16) - return -EINVAL; - - aw88261->rxl_slotvld_mask = chan << AW88261_I2S_RXL_SLOTVLD_START_BIT; - } - - if ((rx_mask & ~BIT(chan)) != 0) { - if ((chan = __ffs(rx_mask & ~BIT(chan))) > 16) - return -EINVAL; - - aw88261->rxr_slotvld_mask = chan << AW88261_I2S_RXR_SLOTVLD_START_BIT; - } - - return 0; -} - -static const struct snd_soc_dai_ops aw88261_dai_ops = { - .set_fmt = aw88261_set_fmt, - .hw_params = aw88261_hw_params, - .set_tdm_slot = aw88261_set_tdm_slot, -}; - static struct snd_soc_dai_driver aw88261_dai[] = { { .name = "aw88261-aif", @@ -888,10 +730,78 @@ static struct snd_soc_dai_driver aw88261_dai[] = { .rates = AW88261_RATES, .formats = AW88261_FORMATS, }, - .ops = &aw88261_dai_ops, }, }; +static int aw88261_get_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88261->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_in_time; + + return 0; +} + +static int aw88261_set_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88261->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_in_time) { + aw_dev->fade_in_time = time; + return 1; + } + + return 0; +} + +static int aw88261_get_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88261->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_out_time; + + return 0; +} + +static int aw88261_set_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88261->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_out_time) { + aw_dev->fade_out_time = time; + return 1; + } + + return 0; +} + static int aw88261_dev_set_profile_index(struct aw_device *aw_dev, int index) { /* check the index whether is valid */ @@ -970,7 +880,7 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol, if (aw88261->aw_pa->status) { aw88261_dev_stop(aw88261->aw_pa); - aw88261_start(aw88261); + aw88261_start(aw88261, AW88261_SYNC_START); } mutex_unlock(&aw88261->lock); @@ -985,8 +895,7 @@ static int aw88261_volume_get(struct snd_kcontrol *kcontrol, struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc; - ucontrol->value.integer.value[0] = - (AW88261_MUTE_VOL - vol_desc->ctl_volume) / 2; + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; return 0; } @@ -999,13 +908,13 @@ static int aw88261_volume_set(struct snd_kcontrol *kcontrol, struct aw_volume_desc *vol_desc = &aw88261->aw_pa->volume_desc; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int value = ucontrol->value.integer.value[0]; + int value; + + value = ucontrol->value.integer.value[0]; if (value < mc->min || value > mc->max) return -EINVAL; - value = AW88261_MUTE_VOL - (value * 2); - if (vol_desc->ctl_volume != value) { vol_desc->ctl_volume = value; aw88261_dev_set_volume(aw88261->aw_pa, vol_desc->ctl_volume); @@ -1016,18 +925,48 @@ static int aw88261_volume_set(struct snd_kcontrol *kcontrol, return 0; } -/* - * The field contains 4 bits in units of 6dB + 6 bits in units of 0.125dB - * which is too precise for TLV (!) so we have to multiply the scale by 2. - * - * The range is clamped at -90dB to prevent overflowing the 4-bit part. - */ -static const DECLARE_TLV_DB_SCALE(volume_tlv, -9000, 25, 0); +static int aw88261_get_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88261->aw_pa->fade_step; + + return 0; +} + +static int aw88261_set_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol); + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (aw88261->aw_pa->fade_step != value) { + aw88261->aw_pa->fade_step = value; + return 1; + } + + return 0; +} static const struct snd_kcontrol_new aw88261_controls[] = { - SOC_SINGLE_EXT_TLV("PCM Playback Volume", AW88261_SYSCTRL2_REG, - 6, AW88261_CTL_MAX_VOL, 1, - aw88261_volume_get, aw88261_volume_set, volume_tlv), + SOC_SINGLE_EXT("PCM Playback Volume", AW88261_SYSCTRL2_REG, + 6, AW88261_MUTE_VOL, 0, aw88261_volume_get, + aw88261_volume_set), + SOC_SINGLE_EXT("Fade Step", 0, 0, AW88261_MUTE_VOL, 0, + aw88261_get_fade_step, aw88261_set_fade_step), + SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88261_get_fade_in_time, aw88261_set_fade_in_time), + SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88261_get_fade_out_time, aw88261_set_fade_out_time), AW88261_PROFILE_EXT("Profile Set", aw88261_profile_info, aw88261_profile_get, aw88261_profile_set), }; @@ -1041,7 +980,7 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w, mutex_lock(&aw88261->lock); switch (event) { case SND_SOC_DAPM_PRE_PMU: - aw88261_start(aw88261); + aw88261_start(aw88261, AW88261_ASYNC_START); break; case SND_SOC_DAPM_POST_PMD: aw88261_dev_stop(aw88261->aw_pa); @@ -1118,6 +1057,8 @@ static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg if (ret) return ret; + aw_dev->fade_in_time = AW88261_500_US; + aw_dev->fade_out_time = AW88261_500_US; aw_dev->prof_cur = AW88261_INIT_PROFILE; aw_dev->prof_index = AW88261_INIT_PROFILE; @@ -1153,7 +1094,6 @@ static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg static int aw88261_request_firmware_file(struct aw88261 *aw88261) { const struct firmware *cont = NULL; - struct aw_container *aw_cfg; const char *fw_name; int ret; @@ -1171,17 +1111,15 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261) dev_info(aw88261->aw_pa->dev, "loaded %s - size: %zu\n", fw_name, cont ? cont->size : 0); - aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL); - if (!aw_cfg) { + aw88261->aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, cont->size + sizeof(int), GFP_KERNEL); + if (!aw88261->aw_cfg) { release_firmware(cont); return -ENOMEM; } - aw_cfg->len = (int)cont->size; - memcpy(aw_cfg->data, cont->data, cont->size); + aw88261->aw_cfg->len = (int)cont->size; + memcpy(aw88261->aw_cfg->data, cont->data, cont->size); release_firmware(cont); - aw88261->aw_cfg = aw_cfg; - ret = aw88395_dev_load_acf_check(aw88261->aw_pa, aw88261->aw_cfg); if (ret) { dev_err(aw88261->aw_pa->dev, "load [%s] failed !", fw_name); @@ -1204,6 +1142,8 @@ static int aw88261_codec_probe(struct snd_soc_component *component) struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component); int ret; + INIT_DELAYED_WORK(&aw88261->start_work, aw88261_startup_work); + ret = aw88261_request_firmware_file(aw88261); if (ret) return dev_err_probe(aw88261->aw_pa->dev, ret, @@ -1227,8 +1167,16 @@ static int aw88261_codec_probe(struct snd_soc_component *component) return ret; } +static void aw88261_codec_remove(struct snd_soc_component *aw_codec) +{ + struct aw88261 *aw88261 = snd_soc_component_get_drvdata(aw_codec); + + cancel_delayed_work_sync(&aw88261->start_work); +} + static const struct snd_soc_component_driver soc_codec_dev_aw88261 = { .probe = aw88261_codec_probe, + .remove = aw88261_codec_remove, }; static void aw88261_parse_channel_dt(struct aw88261 *aw88261) @@ -1260,7 +1208,7 @@ static int aw88261_init(struct aw88261 *aw88261, struct i2c_client *i2c, struct return ret; } if (chip_id != AW88261_CHIP_ID) { - dev_err(&i2c->dev, "unsupported device id = %x", chip_id); + dev_err(&i2c->dev, "unsupported device"); return -ENXIO; } @@ -1281,7 +1229,8 @@ static int aw88261_init(struct aw88261 *aw88261, struct i2c_client *i2c, struct aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; aw_dev->channel = 0; aw_dev->fw_status = AW88261_DEV_FW_FAILED; - aw_dev->volume_desc.ctl_volume = AW88261_CTL_DEFAULT_VOL; + aw_dev->fade_step = AW88261_VOLUME_STEP_DB; + aw_dev->volume_desc.ctl_volume = AW88261_VOL_DEFAULT_VALUE; aw_dev->volume_desc.mute_volume = AW88261_MUTE_VOL; aw88261_parse_channel_dt(aw88261); @@ -1300,17 +1249,6 @@ static int aw88261_i2c_probe(struct i2c_client *i2c) if (!aw88261) return -ENOMEM; - /* set defaults */ - aw88261->slot_num_value = AW88261_SLOT_NUM_I2S_MODE_VALUE; - aw88261->sr_value = AW88261_I2SSR_48KHZ_VALUE; - aw88261->cco_mux_value = AW88261_CCO_MUX_BYPASS_VALUE; - aw88261->fs_value = AW88261_I2SFS_24_BITS_VALUE; - aw88261->bck_value = AW88261_I2SBCK_64FS_VALUE; - aw88261->bck_inv_value = AW88261_BCKINV_NOT_INVERT_VALUE; - aw88261->tdm_bck_value = AW88261_TDM_BCK_UNSET; - aw88261->md_value = AW88261_I2SMD_PHILIPS_STANDARD_VALUE; - aw88261->rxr_slotvld_mask = 1 << AW88261_I2S_RXR_SLOTVLD_START_BIT; - mutex_init(&aw88261->lock); i2c_set_clientdata(i2c, aw88261); @@ -1336,7 +1274,7 @@ static int aw88261_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id aw88261_i2c_id[] = { - { .name = "aw88261" }, + { "aw88261" }, { } }; MODULE_DEVICE_TABLE(i2c, aw88261_i2c_id); diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h index f16f9f8c40a2..1fee589608d6 100644 --- a/sound/soc/codecs/aw88261.h +++ b/sound/soc/codecs/aw88261.h @@ -116,19 +116,6 @@ #define AW88261_VCALK_SHIFT (0) #define AW88261_VCALKL_SHIFT (0) -#define AW88261_BCKINV_START_BIT (4) -#define AW88261_BCKINV_BITS_LEN (1) -#define AW88261_BCKINV_MASK \ - (~(((1<> AW88261_VOL_6DB_START) * \ @@ -551,6 +403,11 @@ .put = profile_set, \ } +enum { + AW88261_SYNC_START = 0, + AW88261_ASYNC_START, +}; + enum aw88261_id { AW88261_CHIP_ID = 0x2113, }; @@ -585,6 +442,7 @@ struct aw88261 { struct aw_device *aw_pa; struct mutex lock; struct gpio_desc *reset_gpio; + struct delayed_work start_work; struct regmap *regmap; struct aw_container *aw_cfg; @@ -593,19 +451,6 @@ struct aw88261 { unsigned int mute_st; unsigned int amppd_st; - unsigned int sr_value; - unsigned int cco_mux_value; - unsigned int fs_value; - unsigned int bck_value; - unsigned int bck_inv_value; - unsigned int tdm_bck_value; - unsigned int md_value; - - unsigned int slot_num_value; - unsigned int tx_slotvld_mask; - unsigned int rxl_slotvld_mask; - unsigned int rxr_slotvld_mask; - bool phase_sync; }; diff --git a/sound/soc/codecs/wcd9378-sdw.c b/sound/soc/codecs/wcd9378-sdw.c deleted file mode 100644 index d9a99a6db500..000000000000 --- a/sound/soc/codecs/wcd9378-sdw.c +++ /dev/null @@ -1,495 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2026, Jorijn van der Graaf - * - * SoundWire slave driver for the Qualcomm WCD9378 audio codec. - * - * The codec presents two SoundWire slaves (RX and TX, mfg 0x0217 part - * 0x0110); the SDCA control space is a 32-bit paged register map accessed - * through the TX slave. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wcd-common.h" -#include "wcd9378.h" - -#define WCD9378_SDW_CH(id, pn, cmask, mmask) \ - [id] = { \ - .port_num = pn, \ - .ch_mask = cmask, \ - .master_ch_mask = mmask, \ - } - -/* - * Each ADC sits alone on its own TX device port (channel 1); by default - * they land on channels 1/2/3 of the same master port (SWRM_TX1 on the - * FP6). DMIC/MBHC masks per the downstream qcom,tx_swr_ch_map. - */ -static struct wcd_sdw_ch_info wcd9378_sdw_tx_ch_info[] = { - WCD9378_SDW_CH(WCD9378_ADC1, WCD9378_ADC_1_PORT, BIT(0), BIT(0)), - WCD9378_SDW_CH(WCD9378_ADC2, WCD9378_ADC_2_PORT, BIT(0), BIT(1)), - WCD9378_SDW_CH(WCD9378_ADC3, WCD9378_ADC_3_PORT, BIT(0), BIT(2)), - WCD9378_SDW_CH(WCD9378_DMIC0, WCD9378_DMIC_0_1_MBHC_PORT, BIT(2), BIT(0)), - WCD9378_SDW_CH(WCD9378_DMIC1, WCD9378_DMIC_0_1_MBHC_PORT, BIT(3), BIT(1)), - WCD9378_SDW_CH(WCD9378_MBHC, WCD9378_DMIC_0_1_MBHC_PORT, BIT(2), BIT(2)), - WCD9378_SDW_CH(WCD9378_DMIC2, WCD9378_DMIC_2_5_PORT, BIT(0), BIT(2)), - WCD9378_SDW_CH(WCD9378_DMIC3, WCD9378_DMIC_2_5_PORT, BIT(1), BIT(3)), - WCD9378_SDW_CH(WCD9378_DMIC4, WCD9378_DMIC_2_5_PORT, BIT(2), BIT(0)), - WCD9378_SDW_CH(WCD9378_DMIC5, WCD9378_DMIC_2_5_PORT, BIT(3), BIT(1)), -}; - -static struct wcd_sdw_ch_info wcd9378_sdw_rx_ch_info[] = { - WCD9378_SDW_CH(WCD9378_HPH_L, WCD9378_HPH_PORT, BIT(0), BIT(0)), - WCD9378_SDW_CH(WCD9378_HPH_R, WCD9378_HPH_PORT, BIT(1), BIT(1)), - WCD9378_SDW_CH(WCD9378_CLSH, WCD9378_CLSH_PORT, BIT(0), BIT(0)), - WCD9378_SDW_CH(WCD9378_COMP_L, WCD9378_COMP_PORT, BIT(0), BIT(0)), - WCD9378_SDW_CH(WCD9378_COMP_R, WCD9378_COMP_PORT, BIT(1), BIT(1)), - WCD9378_SDW_CH(WCD9378_LO, WCD9378_LO_PORT, BIT(0), BIT(0)), - WCD9378_SDW_CH(WCD9378_DSD_L, WCD9378_DSD_PORT, BIT(0), BIT(0)), - WCD9378_SDW_CH(WCD9378_DSD_R, WCD9378_DSD_PORT, BIT(1), BIT(1)), -}; - -static struct sdw_dpn_prop wcd9378_dpn_prop[WCD9378_MAX_SWR_PORTS] = { - { - .num = 1, - .type = SDW_DPN_SIMPLE, - .min_ch = 1, - .max_ch = 8, - .simple_ch_prep_sm = true, - }, { - .num = 2, - .type = SDW_DPN_SIMPLE, - .min_ch = 1, - .max_ch = 4, - .simple_ch_prep_sm = true, - }, { - .num = 3, - .type = SDW_DPN_SIMPLE, - .min_ch = 1, - .max_ch = 4, - .simple_ch_prep_sm = true, - }, { - .num = 4, - .type = SDW_DPN_SIMPLE, - .min_ch = 1, - .max_ch = 4, - .simple_ch_prep_sm = true, - }, { - .num = 5, - .type = SDW_DPN_SIMPLE, - .min_ch = 1, - .max_ch = 4, - .simple_ch_prep_sm = true, - } -}; - -int wcd9378_sdw_hw_params(struct wcd9378_sdw_priv *wcd, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct sdw_port_config port_config[WCD9378_MAX_SWR_PORTS]; - unsigned long ch_mask; - int i, j; - - wcd->sconfig.ch_count = 1; - wcd->active_ports = 0; - for (i = 0; i < WCD9378_MAX_SWR_PORTS; i++) { - ch_mask = wcd->port_config[i].ch_mask; - if (!ch_mask) - continue; - - for_each_set_bit(j, &ch_mask, 4) - wcd->sconfig.ch_count++; - - port_config[wcd->active_ports] = wcd->port_config[i]; - wcd->active_ports++; - } - - wcd->sconfig.bps = 1; - wcd->sconfig.frame_rate = params_rate(params); - wcd->sconfig.direction = wcd->is_tx ? SDW_DATA_DIR_TX : SDW_DATA_DIR_RX; - wcd->sconfig.type = SDW_STREAM_PCM; - - return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig, - &port_config[0], wcd->active_ports, - wcd->sruntime); -} -EXPORT_SYMBOL_GPL(wcd9378_sdw_hw_params); - -/* - * Tell the codec the bus clock: base 19.2 MHz plus a scale (div) per bank. - * The downstream driver writes these raw SCP registers on every capture - * start; here the bus_config callback covers bank switches. - */ -static int wcd9378_bus_config(struct sdw_slave *slave, - struct sdw_bus_params *params) -{ - u8 scale; - - switch (params->curr_dr_freq) { - case 4800000: - scale = WCD9378_SWRS_CLK_SCALE_DIV4; - break; - case 9600000: - default: - scale = WCD9378_SWRS_CLK_SCALE_DIV2; - break; - } - - sdw_write(slave, WCD9378_SWRS_SCP_HOST_CLK_DIV2_CTL(params->next_bank), - 0x01); - sdw_write(slave, WCD9378_SWRS_SCP_BASE_CLK, - WCD9378_SWRS_BASE_CLK_19P2MHZ); - sdw_write(slave, WCD9378_SWRS_SCP_BUSCLK_SCALE_BANK0, scale); - sdw_write(slave, WCD9378_SWRS_SCP_BUSCLK_SCALE_BANK1, scale); - - return 0; -} - -static const struct sdw_slave_ops wcd9378_slave_ops = { - .update_status = wcd_update_status, - .bus_config = wcd9378_bus_config, -}; - -static const struct reg_default wcd9378_defaults[] = { - { WCD9378_ANA_BIAS, 0x00 }, - { WCD9378_ANA_TX_CH1, 0x20 }, - { WCD9378_ANA_TX_CH2, 0x00 }, - { WCD9378_ANA_TX_CH3, 0x20 }, - { WCD9378_ANA_TX_CH3_HPF, 0x00 }, - { WCD9378_ANA_MICB2_RAMP, 0x00 }, - { WCD9378_BIAS_VBG_FINE_ADJ, 0x55 }, - { WCD9378_MBHC_CTL_SPARE_1, 0x02 }, - { WCD9378_MICB1_TEST_CTL_2, 0x00 }, - { WCD9378_MICB2_TEST_CTL_2, 0x00 }, - { WCD9378_MICB3_TEST_CTL_2, 0x80 }, - { WCD9378_TX_COM_TXFE_DIV_CTL, 0x22 }, - { WCD9378_SLEEP_CTL, 0x16 }, - { WCD9378_TX_NEW_CH12_MUX, 0x11 }, - { WCD9378_TX_NEW_CH34_MUX, 0x23 }, - { WCD9378_TOP_CLK_CFG, 0x00 }, - { WCD9378_CDC_ANA_TX_CLK_CTL, 0x0e }, - { WCD9378_CDC_AMIC_CTL, 0x07 }, - { WCD9378_PDM_WD_CTL0, 0x0f }, - { WCD9378_PDM_WD_CTL1, 0x0f }, - { WCD9378_PLATFORM_CTL, 0x01 }, - { WCD9378_SYS_USAGE_CTRL, 0x00 }, - { WCD9378_HPH_UP_T0, 0x02 }, - { WCD9378_HPH_UP_T9, 0x02 }, - { WCD9378_HPH_DN_T0, 0x05 }, - { WCD9378_MICB_REMAP_TABLE_VAL_3, 0x00 }, - { WCD9378_MICB_REMAP_TABLE_VAL_4, 0x00 }, - { WCD9378_MICB_REMAP_TABLE_VAL_5, 0x00 }, - { WCD9378_SM0_MB_SEL, 0x00 }, - { WCD9378_SM1_MB_SEL, 0x00 }, - { WCD9378_SM2_MB_SEL, 0x00 }, - { WCD9378_MB_PULLUP_EN, 0x00 }, - { WCD9378_SMP_AMP_FUNC_ACT, 0x00 }, - { WCD9378_CMT_GRP_MASK, 0x00 }, - { WCD9378_SMP_JACK_IT31_MICB, 0x00 }, - { WCD9378_SMP_JACK_IT31_USAGE, 0x03 }, - { WCD9378_SMP_JACK_PDE34_REQ_PS, 0x03 }, - { WCD9378_SMP_JACK_FUNC_ACT, 0x00 }, - { WCD9378_SMP_MIC_IT11_MICB(0), 0x00 }, - { WCD9378_SMP_MIC_IT11_USAGE(0), 0x03 }, - { WCD9378_SMP_MIC_PDE11_REQ_PS(0), 0x03 }, - { WCD9378_SMP_MIC_FUNC_ACT(0), 0x00 }, - { WCD9378_SMP_MIC_IT11_MICB(1), 0x00 }, - { WCD9378_SMP_MIC_IT11_USAGE(1), 0x03 }, - { WCD9378_SMP_MIC_PDE11_REQ_PS(1), 0x03 }, - { WCD9378_SMP_MIC_FUNC_ACT(1), 0x00 }, - { WCD9378_SMP_MIC_IT11_MICB(2), 0x00 }, - { WCD9378_SMP_MIC_IT11_USAGE(2), 0x03 }, - { WCD9378_SMP_MIC_PDE11_REQ_PS(2), 0x03 }, - { WCD9378_SMP_MIC_FUNC_ACT(2), 0x00 }, -}; - -static bool wcd9378_rdwr_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case WCD9378_ANA_BIAS: - case WCD9378_ANA_TX_CH1: - case WCD9378_ANA_TX_CH2: - case WCD9378_ANA_TX_CH3: - case WCD9378_ANA_TX_CH3_HPF: - case WCD9378_ANA_MICB2_RAMP: - case WCD9378_BIAS_VBG_FINE_ADJ: - case WCD9378_MBHC_CTL_SPARE_1: - case WCD9378_MICB1_TEST_CTL_2: - case WCD9378_MICB2_TEST_CTL_2: - case WCD9378_MICB3_TEST_CTL_2: - case WCD9378_TX_COM_TXFE_DIV_CTL: - case WCD9378_SLEEP_CTL: - case WCD9378_TX_NEW_CH12_MUX: - case WCD9378_TX_NEW_CH34_MUX: - case WCD9378_HPH_RDAC_GAIN_CTL: - case WCD9378_HPH_RDAC_HD2_CTL_L: - case WCD9378_HPH_RDAC_HD2_CTL_R: - case WCD9378_TOP_CLK_CFG: - case WCD9378_CDC_ANA_TX_CLK_CTL: - case WCD9378_CDC_AMIC_CTL: - case WCD9378_PDM_WD_CTL0: - case WCD9378_PDM_WD_CTL1: - case WCD9378_PLATFORM_CTL: - case WCD9378_SYS_USAGE_CTRL: - case WCD9378_HPH_UP_T0: - case WCD9378_HPH_UP_T9: - case WCD9378_HPH_DN_T0: - case WCD9378_MICB_REMAP_TABLE_VAL_3: - case WCD9378_MICB_REMAP_TABLE_VAL_4: - case WCD9378_MICB_REMAP_TABLE_VAL_5: - case WCD9378_SM0_MB_SEL: - case WCD9378_SM1_MB_SEL: - case WCD9378_SM2_MB_SEL: - case WCD9378_MB_PULLUP_EN: - case WCD9378_SMP_AMP_FUNC_STAT: - case WCD9378_SMP_AMP_FUNC_ACT: - case WCD9378_CMT_GRP_MASK: - case WCD9378_SMP_JACK_IT31_MICB: - case WCD9378_SMP_JACK_IT31_USAGE: - case WCD9378_SMP_JACK_PDE34_REQ_PS: - case WCD9378_SMP_JACK_FUNC_STAT: - case WCD9378_SMP_JACK_FUNC_ACT: - case WCD9378_SMP_MIC_IT11_MICB(0): - case WCD9378_SMP_MIC_IT11_USAGE(0): - case WCD9378_SMP_MIC_PDE11_REQ_PS(0): - case WCD9378_SMP_MIC_FUNC_STAT(0): - case WCD9378_SMP_MIC_FUNC_ACT(0): - case WCD9378_SMP_MIC_IT11_MICB(1): - case WCD9378_SMP_MIC_IT11_USAGE(1): - case WCD9378_SMP_MIC_PDE11_REQ_PS(1): - case WCD9378_SMP_MIC_FUNC_STAT(1): - case WCD9378_SMP_MIC_FUNC_ACT(1): - case WCD9378_SMP_MIC_IT11_MICB(2): - case WCD9378_SMP_MIC_IT11_USAGE(2): - case WCD9378_SMP_MIC_PDE11_REQ_PS(2): - case WCD9378_SMP_MIC_FUNC_STAT(2): - case WCD9378_SMP_MIC_FUNC_ACT(2): - return true; - } - - return false; -} - -static bool wcd9378_volatile_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case WCD9378_FUNC_EXT_ID_0: - case WCD9378_FUNC_EXT_ID_1: - case WCD9378_FUNC_EXT_VER: - case WCD9378_FUNC_STAT: - case WCD9378_DEV_MANU_ID_0: - case WCD9378_DEV_MANU_ID_1: - case WCD9378_DEV_PART_ID_0: - case WCD9378_DEV_PART_ID_1: - case WCD9378_DEV_VER: - case WCD9378_EFUSE_REG_16: - case WCD9378_EFUSE_REG_29: - case WCD9378_SEQ_TX0_STAT: - case WCD9378_SEQ_TX1_STAT: - case WCD9378_SEQ_TX2_STAT: - case WCD9378_SMP_AMP_FUNC_STAT: - case WCD9378_SMP_JACK_FUNC_STAT: - case WCD9378_SMP_JACK_PDE34_ACT_PS: - case WCD9378_SMP_MIC_FUNC_STAT(0): - case WCD9378_SMP_MIC_FUNC_STAT(1): - case WCD9378_SMP_MIC_FUNC_STAT(2): - case WCD9378_SMP_MIC_OT10_USAGE(0): - case WCD9378_SMP_MIC_PDE11_ACT_PS(0): - case WCD9378_SMP_MIC_OT10_USAGE(1): - case WCD9378_SMP_MIC_PDE11_ACT_PS(1): - case WCD9378_SMP_MIC_OT10_USAGE(2): - case WCD9378_SMP_MIC_PDE11_ACT_PS(2): - return true; - } - - return false; -} - -static bool wcd9378_readable_register(struct device *dev, unsigned int reg) -{ - if (wcd9378_volatile_register(dev, reg)) - return true; - - return wcd9378_rdwr_register(dev, reg); -} - -static const struct regmap_config wcd9378_regmap_config = { - .name = "wcd9378_csr", - .reg_bits = 32, - .val_bits = 8, - .cache_type = REGCACHE_MAPLE, - .reg_defaults = wcd9378_defaults, - .num_reg_defaults = ARRAY_SIZE(wcd9378_defaults), - .max_register = WCD9378_MAX_REGISTER, - .readable_reg = wcd9378_readable_register, - .writeable_reg = wcd9378_rdwr_register, - .volatile_reg = wcd9378_volatile_register, -}; - -static int wcd9378_sdw_probe(struct sdw_slave *pdev, - const struct sdw_device_id *id) -{ - struct device *dev = &pdev->dev; - struct wcd9378_sdw_priv *wcd; - u8 master_ch_mask[WCD9378_MAX_SWR_CH_IDS]; - int master_ch_mask_size = 0; - int ret, i; - - wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); - if (!wcd) - return -ENOMEM; - - /* Port map index starts at 0, however the data ports start at index 1 */ - if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) { - wcd->is_tx = true; - ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", - &pdev->m_port_map[1], - WCD9378_MAX_TX_SWR_PORTS); - } else { - ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping", - &pdev->m_port_map[1], - WCD9378_MAX_SWR_PORTS); - } - if (ret < 0) - dev_info(dev, "Error getting static port mapping for %s (%d)\n", - wcd->is_tx ? "TX" : "RX", ret); - - wcd->sdev = pdev; - dev_set_drvdata(dev, wcd); - - pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | - SDW_SCP_INT1_PARITY; - pdev->prop.lane_control_support = true; - pdev->prop.simple_clk_stop_capable = true; - /* The SDCA control space sits above the 16-bit address range */ - pdev->prop.paging_support = true; - - memset(master_ch_mask, 0, WCD9378_MAX_SWR_CH_IDS); - - if (wcd->is_tx) { - master_ch_mask_size = of_property_count_u8_elems(dev->of_node, - "qcom,tx-channel-mapping"); - master_ch_mask_size = min_t(int, master_ch_mask_size, - ARRAY_SIZE(wcd9378_sdw_tx_ch_info)); - - if (master_ch_mask_size > 0) - ret = of_property_read_u8_array(dev->of_node, - "qcom,tx-channel-mapping", - master_ch_mask, - master_ch_mask_size); - } else { - master_ch_mask_size = of_property_count_u8_elems(dev->of_node, - "qcom,rx-channel-mapping"); - master_ch_mask_size = min_t(int, master_ch_mask_size, - ARRAY_SIZE(wcd9378_sdw_rx_ch_info)); - - if (master_ch_mask_size > 0) - ret = of_property_read_u8_array(dev->of_node, - "qcom,rx-channel-mapping", - master_ch_mask, - master_ch_mask_size); - } - - if (wcd->is_tx) { - pdev->prop.source_ports = GENMASK(WCD9378_MAX_TX_SWR_PORTS, 1); - pdev->prop.src_dpn_prop = wcd9378_dpn_prop; - wcd->ch_info = &wcd9378_sdw_tx_ch_info[0]; - - for (i = 0; i < master_ch_mask_size; i++) - wcd->ch_info[i].master_ch_mask = WCD9378_SWRM_CH_MASK(master_ch_mask[i]); - - pdev->prop.wake_capable = true; - - wcd->regmap = devm_regmap_init_sdw(pdev, &wcd9378_regmap_config); - if (IS_ERR(wcd->regmap)) - return dev_err_probe(dev, PTR_ERR(wcd->regmap), - "Regmap init failed\n"); - - /* Start in cache-only until device is enumerated */ - regcache_cache_only(wcd->regmap, true); - } else { - pdev->prop.sink_ports = GENMASK(WCD9378_MAX_SWR_PORTS, 1); - pdev->prop.sink_dpn_prop = wcd9378_dpn_prop; - wcd->ch_info = &wcd9378_sdw_rx_ch_info[0]; - - for (i = 0; i < master_ch_mask_size; i++) - wcd->ch_info[i].master_ch_mask = WCD9378_SWRM_CH_MASK(master_ch_mask[i]); - } - - ret = component_add(dev, &wcd_sdw_component_ops); - if (ret) - return ret; - - /* Set suspended until aggregate device is bind */ - pm_runtime_set_suspended(dev); - - return 0; -} - -static void wcd9378_sdw_remove(struct sdw_slave *pdev) -{ - struct device *dev = &pdev->dev; - - component_del(dev, &wcd_sdw_component_ops); -} - -static const struct sdw_device_id wcd9378_sdw_id[] = { - SDW_SLAVE_ENTRY(0x0217, 0x0110, 0), - { }, -}; -MODULE_DEVICE_TABLE(sdw, wcd9378_sdw_id); - -static int wcd9378_sdw_runtime_suspend(struct device *dev) -{ - struct wcd9378_sdw_priv *wcd = dev_get_drvdata(dev); - - if (wcd->regmap) { - regcache_cache_only(wcd->regmap, true); - regcache_mark_dirty(wcd->regmap); - } - - return 0; -} - -static int wcd9378_sdw_runtime_resume(struct device *dev) -{ - struct wcd9378_sdw_priv *wcd = dev_get_drvdata(dev); - - if (wcd->regmap) { - regcache_cache_only(wcd->regmap, false); - regcache_sync(wcd->regmap); - } - - return 0; -} - -static const struct dev_pm_ops wcd9378_sdw_pm_ops = { - RUNTIME_PM_OPS(wcd9378_sdw_runtime_suspend, wcd9378_sdw_runtime_resume, NULL) -}; - -static struct sdw_driver wcd9378_sdw_driver = { - .probe = wcd9378_sdw_probe, - .remove = wcd9378_sdw_remove, - .ops = &wcd9378_slave_ops, - .id_table = wcd9378_sdw_id, - .driver = { - .name = "wcd9378-sdw", - .pm = pm_ptr(&wcd9378_sdw_pm_ops), - } -}; -module_sdw_driver(wcd9378_sdw_driver); - -MODULE_DESCRIPTION("WCD9378 SDW codec driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd9378.c b/sound/soc/codecs/wcd9378.c deleted file mode 100644 index 38acb6b20388..000000000000 --- a/sound/soc/codecs/wcd9378.c +++ /dev/null @@ -1,1390 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2026, Jorijn van der Graaf - * - * Qualcomm WCD9378 audio codec driver. - * - * The WCD9378 pairs a WCD937x-compatible analog core with SDCA-style - * function blocks (SmartMIC0/1/2, SmartJACK, SmartAMP) whose built-in - * sequencers perform the analog power-up/down autonomously: capture is - * started by programming the ADC usage mode (ITxx_USAGE), requesting - * power state 0 on the function's PDE, and letting the sequencer ramp - * the micbias selected through SMx_MB_SEL. - * - * TX/capture paths only for now; RX (earpiece/headphone), MBHC and the - * SmartAMP function are not implemented. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wcd-common.h" -#include "wcd9378.h" - -enum { - AIF1_PB = 0, - AIF1_CAP, - NUM_CODEC_DAIS, -}; - -enum { - MIC_BIAS_1 = 1, - MIC_BIAS_2, - MIC_BIAS_3, -}; - -enum { - MICB_PULLUP_ENABLE, - MICB_PULLUP_DISABLE, - MICB_ENABLE, - MICB_DISABLE, -}; - -/* sys-usage capability bits (SYS_USAGE_CTRL profile contents) */ -enum { - WCD9378_SYS_USAGE_CLASS_AB = 0, - WCD9378_SYS_USAGE_TX1_FOR_JACK, - WCD9378_SYS_USAGE_TX2_AMIC4, - WCD9378_SYS_USAGE_TX2_AMIC1, - WCD9378_SYS_USAGE_TX1_AMIC3, - WCD9378_SYS_USAGE_TX1_AMIC2, - WCD9378_SYS_USAGE_TX0_AMIC2, - WCD9378_SYS_USAGE_TX0_AMIC1, - WCD9378_SYS_USAGE_RX2_EAR, - WCD9378_SYS_USAGE_RX2_AUX, - WCD9378_SYS_USAGE_RX1_AUX, - WCD9378_SYS_USAGE_RX0_EAR, - WCD9378_SYS_USAGE_RX0_RX1_HPH, -}; - -/* Capability sets of the 13 canned SYS_USAGE_CTRL profiles */ -static const unsigned int wcd9378_sys_usage_profiles[] = { - 0x0c95, 0x12a7, 0x0c99, 0x1aab, 0x0894, 0x11a6, 0x0898, - 0x11ab, 0x126a, 0x116b, 0x1ca7, 0x1195, 0x1296, -}; - -struct wcd9378_priv { - struct sdw_slave *tx_sdw_dev; - struct wcd9378_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; - struct device *txdev; - struct device *rxdev; - struct device_node *rxnode; - struct device_node *txnode; - struct regmap *regmap; - struct wcd_common common; - /* micbias refcount lock */ - struct mutex micb_lock; - u8 micb_usage_val[WCD9378_MAX_MICBIAS]; - int micb_ref[WCD9378_MAX_MICBIAS]; - int pullup_ref[WCD9378_MAX_MICBIAS]; - unsigned long sys_usage_mask; - /* per-ADC profile bit and target function, latched at power-up */ - int tx_sys_bit[3]; - bool tx_is_jack[3]; - u32 tx_mode[3]; - struct gpio_desc *reset_gpio; -}; - -static const char * const wcd9378_supplies[] = { - "vdd-rxtx", "vdd-io", "vdd-buck", "vdd-mic-bias", -}; - -/* SDCA function block registers driving one ADC */ -struct wcd9378_smp_fn { - u32 usage_reg; - u32 micb_reg; - u32 req_reg; - u32 act_reg; - u32 hpf_reg; - u8 hpf_mask; -}; - -/* ADC1/2/3 through SmartMIC0/1/2 */ -static const struct wcd9378_smp_fn wcd9378_smp_mic[] = { - { - .usage_reg = WCD9378_SMP_MIC_IT11_USAGE(0), - .micb_reg = WCD9378_SMP_MIC_IT11_MICB(0), - .req_reg = WCD9378_SMP_MIC_PDE11_REQ_PS(0), - .act_reg = WCD9378_SMP_MIC_PDE11_ACT_PS(0), - .hpf_reg = WCD9378_ANA_TX_CH2, - .hpf_mask = WCD9378_ANA_TX_CH2_HPF1_INIT, - }, { - .usage_reg = WCD9378_SMP_MIC_IT11_USAGE(1), - .micb_reg = WCD9378_SMP_MIC_IT11_MICB(1), - .req_reg = WCD9378_SMP_MIC_PDE11_REQ_PS(1), - .act_reg = WCD9378_SMP_MIC_PDE11_ACT_PS(1), - .hpf_reg = WCD9378_ANA_TX_CH2, - .hpf_mask = WCD9378_ANA_TX_CH2_HPF2_INIT, - }, { - .usage_reg = WCD9378_SMP_MIC_IT11_USAGE(2), - .micb_reg = WCD9378_SMP_MIC_IT11_MICB(2), - .req_reg = WCD9378_SMP_MIC_PDE11_REQ_PS(2), - .act_reg = WCD9378_SMP_MIC_PDE11_ACT_PS(2), - .hpf_reg = WCD9378_ANA_TX_CH3_HPF, - .hpf_mask = WCD9378_ANA_TX_CH3_HPF3_INIT, - }, -}; - -/* ADC2 fed from AMIC2 runs through the SmartJACK function instead */ -static const struct wcd9378_smp_fn wcd9378_smp_jack_adc2 = { - .usage_reg = WCD9378_SMP_JACK_IT31_USAGE, - .micb_reg = WCD9378_SMP_JACK_IT31_MICB, - .req_reg = WCD9378_SMP_JACK_PDE34_REQ_PS, - .act_reg = WCD9378_SMP_JACK_PDE34_ACT_PS, -}; - -/* - * Measured acoustically on the FP6: the TX gain field steps 1.5 dB per - * code (+6 dB per 4 codes, +30 dB over the full 0..20 range). The - * wcd937x-family drivers claim 0.25 dB steps for the same field. - */ -static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 150, 0); - -static void wcd9378_reset(struct wcd9378_priv *wcd9378) -{ - gpiod_set_value(wcd9378->reset_gpio, 1); - usleep_range(20, 30); - gpiod_set_value(wcd9378->reset_gpio, 0); - usleep_range(20, 30); -} - -/* - * Activate the SDCA function classes. Without FUNC_ACT the sequencer - * ignores all PDE power-state requests. - */ -static void wcd9378_class_load(struct snd_soc_component *component) -{ - int i; - - /* - * Plain writes, not update_bits, so the 0->1 activation edge - * always reaches the hardware regardless of regcache state. - * The engine boots from this edge only on a freshly reset - * codec; once it dies (bus clock-stop) no register write - * revives it, see the TX bus PM hold in wcd9378_bind(). - */ - snd_soc_component_write(component, WCD9378_SMP_AMP_FUNC_ACT, 0x00); - snd_soc_component_write(component, WCD9378_SMP_AMP_FUNC_ACT, 0x01); - usleep_range(20000, 20010); - snd_soc_component_write(component, WCD9378_SMP_AMP_FUNC_STAT, 0xff); - - snd_soc_component_write(component, WCD9378_SMP_JACK_FUNC_ACT, 0x00); - snd_soc_component_write(component, WCD9378_SMP_JACK_FUNC_ACT, 0x01); - usleep_range(30000, 30010); - snd_soc_component_update_bits(component, WCD9378_CMT_GRP_MASK, - 0xff, 0x02); - snd_soc_component_write(component, WCD9378_SMP_JACK_FUNC_STAT, 0xff); - - for (i = 0; i < 3; i++) { - snd_soc_component_write(component, - WCD9378_SMP_MIC_FUNC_ACT(i), 0x00); - snd_soc_component_write(component, - WCD9378_SMP_MIC_FUNC_ACT(i), 0x01); - usleep_range(5000, 5010); - snd_soc_component_write(component, - WCD9378_SMP_MIC_FUNC_STAT(i), 0xff); - } -} - -static void wcd9378_io_init(struct snd_soc_component *component) -{ - u32 efuse; - - /* Bandgap and analog master bias, with precharge pulse */ - efuse = snd_soc_component_read(component, WCD9378_EFUSE_REG_16); - snd_soc_component_update_bits(component, WCD9378_MBHC_CTL_SPARE_1, - 0x03, efuse == 0 ? 0x03 : 0x01); - snd_soc_component_update_bits(component, WCD9378_SLEEP_CTL, - WCD9378_SLEEP_CTL_BG_CTL_MASK, 0x0e); - snd_soc_component_update_bits(component, WCD9378_SLEEP_CTL, - WCD9378_SLEEP_CTL_BG_EN, - WCD9378_SLEEP_CTL_BG_EN); - usleep_range(1000, 1010); - snd_soc_component_update_bits(component, WCD9378_SLEEP_CTL, - WCD9378_SLEEP_CTL_LDOL_BG_SEL, - WCD9378_SLEEP_CTL_LDOL_BG_SEL); - usleep_range(1000, 1010); - snd_soc_component_update_bits(component, WCD9378_BIAS_VBG_FINE_ADJ, - 0xf0, 0xb0); - snd_soc_component_update_bits(component, WCD9378_ANA_BIAS, - WCD9378_ANA_BIAS_ANALOG_BIAS_EN, - WCD9378_ANA_BIAS_ANALOG_BIAS_EN); - snd_soc_component_update_bits(component, WCD9378_ANA_BIAS, - WCD9378_ANA_BIAS_PRECHRG_EN, - WCD9378_ANA_BIAS_PRECHRG_EN); - usleep_range(10000, 10010); - snd_soc_component_update_bits(component, WCD9378_ANA_BIAS, - WCD9378_ANA_BIAS_PRECHRG_EN, 0x00); - - /* TX supporting clocks/dividers */ - snd_soc_component_update_bits(component, WCD9378_CDC_ANA_TX_CLK_CTL, - WCD9378_CDC_ANA_TXSCBIAS_CLK_EN, - WCD9378_CDC_ANA_TXSCBIAS_CLK_EN); - snd_soc_component_update_bits(component, WCD9378_TX_COM_TXFE_DIV_CTL, - WCD9378_TX_COM_TXFE_DIV_SEQ_BYPASS, - WCD9378_TX_COM_TXFE_DIV_SEQ_BYPASS); - snd_soc_component_update_bits(component, WCD9378_PDM_WD_CTL0, - 0x18, 0x10); - snd_soc_component_update_bits(component, WCD9378_PDM_WD_CTL1, - 0x18, 0x10); - - /* Micbias LDO driver bias */ - snd_soc_component_update_bits(component, WCD9378_MICB1_TEST_CTL_2, - 0x07, 0x01); - snd_soc_component_update_bits(component, WCD9378_MICB2_TEST_CTL_2, - 0x07, 0x01); - snd_soc_component_update_bits(component, WCD9378_MICB3_TEST_CTL_2, - 0x07, 0x01); - - /* RX defaults (harmless while RX is unimplemented) */ - snd_soc_component_update_bits(component, WCD9378_HPH_RDAC_HD2_CTL_L, - 0x0f, 0x04); - snd_soc_component_update_bits(component, WCD9378_HPH_RDAC_HD2_CTL_R, - 0x0f, 0x04); - snd_soc_component_update_bits(component, WCD9378_HPH_RDAC_GAIN_CTL, - 0xf0, 0x50); - snd_soc_component_update_bits(component, WCD9378_HPH_UP_T0, - 0x07, 0x05); - snd_soc_component_update_bits(component, WCD9378_HPH_UP_T9, - 0x07, 0x05); - snd_soc_component_update_bits(component, WCD9378_HPH_DN_T0, - 0x07, 0x06); - - /* SmartMIC function N powers the micbias SMx_MB_SEL points at */ - snd_soc_component_update_bits(component, WCD9378_SM0_MB_SEL, - WCD9378_SM_MB_SEL_MASK, 0x01); - snd_soc_component_update_bits(component, WCD9378_SM1_MB_SEL, - WCD9378_SM_MB_SEL_MASK, 0x02); - snd_soc_component_update_bits(component, WCD9378_SM2_MB_SEL, - WCD9378_SM_MB_SEL_MASK, 0x03); - snd_soc_component_update_bits(component, WCD9378_SYS_USAGE_CTRL, - WCD9378_SYS_USAGE_CTRL_MASK, 0x00); - - wcd9378_class_load(component); -} - -/* - * Derive the sys-usage capability bit for an ADC from its input mux. - * Only combinations the canned profiles cover are usable. - */ -static int wcd9378_sys_usage_bit_get(struct snd_soc_component *component, - int adc, bool *is_jack) -{ - u32 val; - - *is_jack = false; - - switch (adc) { - case 0: - val = snd_soc_component_read(component, WCD9378_TX_NEW_CH12_MUX) & - WCD9378_TX_NEW_CH12_MUX_CH1_SEL_MASK; - if (val == 0x01) - return WCD9378_SYS_USAGE_TX0_AMIC1; - if (val == 0x02) - return WCD9378_SYS_USAGE_TX0_AMIC2; - break; - case 1: - val = (snd_soc_component_read(component, WCD9378_TX_NEW_CH12_MUX) & - WCD9378_TX_NEW_CH12_MUX_CH2_SEL_MASK) >> 3; - if (val == 0x02) { - *is_jack = true; - return WCD9378_SYS_USAGE_TX1_AMIC2; - } - if (val == 0x03) - return WCD9378_SYS_USAGE_TX1_AMIC3; - break; - case 2: - val = snd_soc_component_read(component, WCD9378_TX_NEW_CH34_MUX) & - WCD9378_TX_NEW_CH34_MUX_CH3_SEL_MASK; - if (val == 0x01) - return WCD9378_SYS_USAGE_TX2_AMIC1; - if (val == 0x03) - return WCD9378_SYS_USAGE_TX2_AMIC4; - break; - } - - dev_err(component->dev, - "ADC%d input mux selection not supported by any sys-usage profile\n", - adc + 1); - return -EINVAL; -} - -static int wcd9378_sys_usage_update(struct snd_soc_component *component, - int bit, bool enable) -{ - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); - int i; - - if (!enable) { - clear_bit(bit, &wcd9378->sys_usage_mask); - return 0; - } - - set_bit(bit, &wcd9378->sys_usage_mask); - - for (i = 0; i < ARRAY_SIZE(wcd9378_sys_usage_profiles); i++) { - if ((wcd9378_sys_usage_profiles[i] & wcd9378->sys_usage_mask) == - wcd9378->sys_usage_mask) - break; - } - - if (i == ARRAY_SIZE(wcd9378_sys_usage_profiles)) { - clear_bit(bit, &wcd9378->sys_usage_mask); - dev_err(component->dev, - "no sys-usage profile covers active paths (mask %#lx)\n", - wcd9378->sys_usage_mask); - return -EINVAL; - } - - snd_soc_component_update_bits(component, WCD9378_SYS_USAGE_CTRL, - WCD9378_SYS_USAGE_CTRL_MASK, i); - - return 0; -} - -static u32 wcd9378_get_mode_val(struct wcd9378_priv *wcd9378, int adc) -{ - switch (wcd9378->tx_mode[adc]) { - case 1: - return WCD9378_ADC_USAGE_HIFI; - case 2: - return WCD9378_ADC_USAGE_LO_HIF; - case 4: - return WCD9378_ADC_USAGE_LP; - case 0: /* ADC_INVALID (unset) */ - case 3: - default: - return WCD9378_ADC_USAGE_NORMAL; - } -} - -/* - * Indicate the bus clock to the codec through the standard SCP - * BusClock_Base/Scale registers. The TX sequencers clock off the - * SoundWire bus clock and stall without this; the downstream driver - * writes these on every capture start and clears them on the last - * teardown. - */ -/* Actual bus clock is half the SoundWire double-rate frequency */ -static unsigned int wcd9378_tx_bus_clk(struct wcd9378_priv *wcd9378) -{ - return wcd9378->tx_sdw_dev->bus->params.curr_dr_freq / 2; -} - -static void wcd9378_swr_clk_indicate(struct wcd9378_priv *wcd9378, bool enable) -{ - struct sdw_slave *tx = wcd9378->tx_sdw_dev; - u8 scale; - - if (enable) { - if (wcd9378_tx_bus_clk(wcd9378) >= 9600000) - scale = WCD9378_SWRS_CLK_SCALE_DIV2; - else - scale = WCD9378_SWRS_CLK_SCALE_DIV4; - - /* - * The downstream master broadcasts HOST_CLK_DIV2_CTL = 0x01 - * (both banks) on every capture start; the sequencer does not - * power up without it. - */ - sdw_write(tx, WCD9378_SWRS_SCP_HOST_CLK_DIV2_CTL(0), 0x01); - sdw_write(tx, WCD9378_SWRS_SCP_HOST_CLK_DIV2_CTL(1), 0x01); - sdw_write(tx, WCD9378_SWRS_SCP_BASE_CLK, - WCD9378_SWRS_BASE_CLK_19P2MHZ); - sdw_write(tx, WCD9378_SWRS_SCP_BUSCLK_SCALE_BANK0, scale); - sdw_write(tx, WCD9378_SWRS_SCP_BUSCLK_SCALE_BANK1, scale); - sdw_write(tx, SDW_SCP_COMMIT, 0x02); - } else { - sdw_write(tx, WCD9378_SWRS_SCP_BASE_CLK, 0x00); - sdw_write(tx, WCD9378_SWRS_SCP_BUSCLK_SCALE_BANK0, 0x00); - sdw_write(tx, WCD9378_SWRS_SCP_BUSCLK_SCALE_BANK1, 0x00); - } -} - -#define WCD9378_SYS_USAGE_TX_MASK (BIT(WCD9378_SYS_USAGE_TX2_AMIC4) | \ - BIT(WCD9378_SYS_USAGE_TX2_AMIC1) | \ - BIT(WCD9378_SYS_USAGE_TX1_AMIC3) | \ - BIT(WCD9378_SYS_USAGE_TX1_AMIC2) | \ - BIT(WCD9378_SYS_USAGE_TX0_AMIC2) | \ - BIT(WCD9378_SYS_USAGE_TX0_AMIC1)) - -static int wcd9378_tx_sequencer_enable(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); - const struct wcd9378_smp_fn *fn; - int adc = w->shift; - bool is_jack = false; - int sys_bit, retries; - u32 val; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - sys_bit = wcd9378_sys_usage_bit_get(component, adc, &is_jack); - if (sys_bit < 0) - return sys_bit; - - /* - * Latch the profile bit and the target function: the input - * mux can be rewritten while the path is powered, and - * power-down must tear down what was actually powered up. - */ - wcd9378->tx_sys_bit[adc] = sys_bit; - wcd9378->tx_is_jack[adc] = is_jack; - if (is_jack) - fn = &wcd9378_smp_jack_adc2; - else - fn = &wcd9378_smp_mic[adc]; - - if (wcd9378_sys_usage_update(component, sys_bit, true)) - return -EINVAL; - - /* - * NORMAL/HIFI ADC modes need a 9.6 MHz bus clock; on a - * 4.8 MHz bus only the LP mode is valid and anything else - * makes the sequencer refuse to power up. - */ - if (wcd9378_tx_bus_clk(wcd9378) < 9600000) - val = WCD9378_ADC_USAGE_LP; - else - val = wcd9378_get_mode_val(wcd9378, adc); - - snd_soc_component_update_bits(component, fn->usage_reg, 0xff, val); - if (fn->hpf_reg) - snd_soc_component_update_bits(component, fn->hpf_reg, - fn->hpf_mask, fn->hpf_mask); - snd_soc_component_update_bits(component, fn->req_reg, 0xff, - WCD9378_PDE_PS0_ON); - usleep_range(800, 810); - - wcd9378_swr_clk_indicate(wcd9378, true); - - if (fn->hpf_reg) - snd_soc_component_update_bits(component, fn->hpf_reg, - fn->hpf_mask, 0x00); - - /* Wait for the sequencer to reach PS0 */ - retries = 20; - do { - val = snd_soc_component_read(component, fn->act_reg); - if (val == WCD9378_PDE_PS0_ON) - break; - usleep_range(500, 510); - } while (--retries); - if (val != WCD9378_PDE_PS0_ON) - dev_warn(component->dev, - "TX%d sequencer not in PS0 (act_ps %#x, bus %u Hz)\n", - adc, val, - wcd9378->tx_sdw_dev->bus->params.curr_dr_freq); - break; - case SND_SOC_DAPM_POST_PMD: - sys_bit = wcd9378->tx_sys_bit[adc]; - if (sys_bit < 0) - break; - if (wcd9378->tx_is_jack[adc]) - fn = &wcd9378_smp_jack_adc2; - else - fn = &wcd9378_smp_mic[adc]; - - snd_soc_component_update_bits(component, fn->usage_reg, 0xff, - WCD9378_ADC_USAGE_OFF); - if (fn->hpf_reg) - snd_soc_component_update_bits(component, fn->hpf_reg, - fn->hpf_mask, 0x00); - snd_soc_component_update_bits(component, fn->req_reg, 0xff, - WCD9378_PDE_PS3_OFF); - usleep_range(800, 810); - wcd9378_sys_usage_update(component, sys_bit, false); - wcd9378->tx_sys_bit[adc] = -1; - - if (!(wcd9378->sys_usage_mask & WCD9378_SYS_USAGE_TX_MASK)) - wcd9378_swr_clk_indicate(wcd9378, false); - break; - } - - return 0; -} - -static int wcd9378_micbias_control(struct snd_soc_component *component, - int micb_num, int req) -{ - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); - int mb_index = micb_num - 1; - u32 usage_reg; - u8 usage_val; - u8 pullup_bit; - - if (micb_num < MIC_BIAS_1 || micb_num > MIC_BIAS_3) - return -EINVAL; - - usage_reg = wcd9378_smp_mic[mb_index].micb_reg; - usage_val = wcd9378->micb_usage_val[mb_index]; - pullup_bit = BIT(mb_index); - - mutex_lock(&wcd9378->micb_lock); - - switch (req) { - case MICB_ENABLE: - wcd9378->micb_ref[mb_index]++; - if (wcd9378->micb_ref[mb_index] == 1) { - if (micb_num == MIC_BIAS_2) { - snd_soc_component_update_bits(component, - WCD9378_ANA_MICB2_RAMP, - WCD9378_ANA_MICB2_RAMP_SHIFT_CTL_MASK, - 0x0c); - snd_soc_component_update_bits(component, - WCD9378_ANA_MICB2_RAMP, - WCD9378_ANA_MICB2_RAMP_EN, 0x00); - } - snd_soc_component_update_bits(component, usage_reg, - 0xff, usage_val); - if (micb_num == MIC_BIAS_2) - snd_soc_component_update_bits(component, - WCD9378_SMP_JACK_IT31_MICB, - 0xff, usage_val); - } - break; - case MICB_DISABLE: - if (wcd9378->micb_ref[mb_index] > 0) - wcd9378->micb_ref[mb_index]--; - if (wcd9378->micb_ref[mb_index] == 0 && - wcd9378->pullup_ref[mb_index] > 0) { - snd_soc_component_update_bits(component, - WCD9378_MB_PULLUP_EN, - pullup_bit, pullup_bit); - snd_soc_component_update_bits(component, usage_reg, 0xff, - WCD9378_MICB_USAGE_1P8V_OR_PULLUP); - if (micb_num == MIC_BIAS_2) - snd_soc_component_update_bits(component, - WCD9378_SMP_JACK_IT31_MICB, 0xff, - WCD9378_MICB_USAGE_1P8V_OR_PULLUP); - } else if (wcd9378->micb_ref[mb_index] == 0) { - snd_soc_component_update_bits(component, usage_reg, - 0xff, WCD9378_MICB_USAGE_OFF); - if (micb_num == MIC_BIAS_2) { - snd_soc_component_update_bits(component, - WCD9378_SMP_JACK_IT31_MICB, - 0xff, WCD9378_MICB_USAGE_OFF); - snd_soc_component_update_bits(component, - WCD9378_ANA_MICB2_RAMP, - WCD9378_ANA_MICB2_RAMP_SHIFT_CTL_MASK, - 0x0c); - snd_soc_component_update_bits(component, - WCD9378_ANA_MICB2_RAMP, - WCD9378_ANA_MICB2_RAMP_EN, - WCD9378_ANA_MICB2_RAMP_EN); - } - } - break; - case MICB_PULLUP_ENABLE: - wcd9378->pullup_ref[mb_index]++; - if (wcd9378->pullup_ref[mb_index] == 1 && - wcd9378->micb_ref[mb_index] == 0) { - snd_soc_component_update_bits(component, - WCD9378_MB_PULLUP_EN, - pullup_bit, pullup_bit); - snd_soc_component_update_bits(component, usage_reg, 0xff, - WCD9378_MICB_USAGE_1P8V_OR_PULLUP); - if (micb_num == MIC_BIAS_2) - snd_soc_component_update_bits(component, - WCD9378_SMP_JACK_IT31_MICB, 0xff, - WCD9378_MICB_USAGE_1P8V_OR_PULLUP); - } - break; - case MICB_PULLUP_DISABLE: - if (wcd9378->pullup_ref[mb_index] > 0) - wcd9378->pullup_ref[mb_index]--; - if (wcd9378->pullup_ref[mb_index] == 0 && - wcd9378->micb_ref[mb_index] == 0) { - snd_soc_component_update_bits(component, - WCD9378_MB_PULLUP_EN, pullup_bit, 0x00); - snd_soc_component_update_bits(component, usage_reg, 0xff, - WCD9378_MICB_USAGE_PULL_DOWN); - if (micb_num == MIC_BIAS_2) - snd_soc_component_update_bits(component, - WCD9378_SMP_JACK_IT31_MICB, 0xff, - WCD9378_MICB_USAGE_PULL_DOWN); - } - break; - } - - mutex_unlock(&wcd9378->micb_lock); - - return 0; -} - -static int wcd9378_codec_enable_micbias(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - int micb_num = w->shift; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - wcd9378_micbias_control(component, micb_num, MICB_ENABLE); - break; - case SND_SOC_DAPM_POST_PMU: - usleep_range(1000, 1100); - break; - case SND_SOC_DAPM_POST_PMD: - wcd9378_micbias_control(component, micb_num, MICB_DISABLE); - break; - } - - return 0; -} - -static int wcd9378_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) -{ - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - int micb_num = w->shift; - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - wcd9378_micbias_control(component, micb_num, - MICB_PULLUP_ENABLE); - break; - case SND_SOC_DAPM_POST_PMU: - usleep_range(1000, 1100); - break; - case SND_SOC_DAPM_POST_PMD: - wcd9378_micbias_control(component, micb_num, - MICB_PULLUP_DISABLE); - break; - } - - return 0; -} - -static int wcd9378_connect_port(struct wcd9378_sdw_priv *wcd, u8 port_idx, - u8 ch_id, bool enable) -{ - struct sdw_port_config *port_config = &wcd->port_config[port_idx - 1]; - const struct wcd_sdw_ch_info *ch_info = &wcd->ch_info[ch_id]; - u8 port_num = ch_info->port_num; - u8 ch_mask = ch_info->ch_mask; - u8 mstr_port_num, mstr_ch_mask; - struct sdw_slave *sdev = wcd->sdev; - - port_config->num = port_num; - - mstr_port_num = sdev->m_port_map[port_num]; - mstr_ch_mask = ch_info->master_ch_mask; - - if (enable) { - port_config->ch_mask |= ch_mask; - wcd->master_channel_map[mstr_port_num] |= mstr_ch_mask; - } else { - port_config->ch_mask &= ~ch_mask; - wcd->master_channel_map[mstr_port_num] &= ~mstr_ch_mask; - } - - return 0; -} - -static int wcd9378_get_swr_port(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(comp); - struct wcd9378_sdw_priv *wcd; - int dai_id = mixer->shift; - int ch_idx = mixer->reg; - int portidx; - - wcd = wcd9378->sdw_priv[dai_id]; - portidx = wcd->ch_info[ch_idx].port_num; - - ucontrol->value.integer.value[0] = wcd->port_enable[portidx]; - - return 0; -} - -static int wcd9378_set_swr_port(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(comp); - struct wcd9378_sdw_priv *wcd; - int dai_id = mixer->shift; - int ch_idx = mixer->reg; - int portidx; - bool enable; - - wcd = wcd9378->sdw_priv[dai_id]; - portidx = wcd->ch_info[ch_idx].port_num; - - enable = ucontrol->value.integer.value[0]; - - if (enable == wcd->port_enable[portidx]) { - wcd9378_connect_port(wcd, portidx, ch_idx, enable); - return 0; - } - - wcd->port_enable[portidx] = enable; - wcd9378_connect_port(wcd, portidx, ch_idx, enable); - - return 1; -} - -static int wcd9378_tx_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int adc = e->shift_l; - - ucontrol->value.enumerated.item[0] = wcd9378->tx_mode[adc]; - - return 0; -} - -static int wcd9378_tx_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - int adc = e->shift_l; - u32 mode_val = ucontrol->value.enumerated.item[0]; - - if (mode_val == wcd9378->tx_mode[adc]) - return 0; - - wcd9378->tx_mode[adc] = mode_val; - - return 1; -} - -static const char * const tx_mode_mux_text[] = { - "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", -}; - -static const struct soc_enum tx0_mode_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text), - tx_mode_mux_text); -static const struct soc_enum tx1_mode_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text), - tx_mode_mux_text); -static const struct soc_enum tx2_mode_enum = - SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text), - tx_mode_mux_text); - -static const struct snd_kcontrol_new wcd9378_snd_controls[] = { - SOC_SINGLE_TLV("ADC1 Volume", WCD9378_ANA_TX_CH1, 0, 20, 0, - analog_gain), - SOC_SINGLE_TLV("ADC2 Volume", WCD9378_ANA_TX_CH2, 0, 20, 0, - analog_gain), - SOC_SINGLE_TLV("ADC3 Volume", WCD9378_ANA_TX_CH3, 0, 20, 0, - analog_gain), - - SOC_ENUM_EXT("TX0 MODE", tx0_mode_enum, - wcd9378_tx_mode_get, wcd9378_tx_mode_put), - SOC_ENUM_EXT("TX1 MODE", tx1_mode_enum, - wcd9378_tx_mode_get, wcd9378_tx_mode_put), - SOC_ENUM_EXT("TX2 MODE", tx2_mode_enum, - wcd9378_tx_mode_get, wcd9378_tx_mode_put), - - SOC_SINGLE_EXT("ADC1 Switch", WCD9378_ADC1, AIF1_CAP, 1, 0, - wcd9378_get_swr_port, wcd9378_set_swr_port), - SOC_SINGLE_EXT("ADC2 Switch", WCD9378_ADC2, AIF1_CAP, 1, 0, - wcd9378_get_swr_port, wcd9378_set_swr_port), - SOC_SINGLE_EXT("ADC3 Switch", WCD9378_ADC3, AIF1_CAP, 1, 0, - wcd9378_get_swr_port, wcd9378_set_swr_port), -}; - -static const char * const adc1_mux_text[] = { - "CH1_AMIC_DISABLE", "CH1_AMIC1", "CH1_AMIC2", "CH1_AMIC3", "CH1_AMIC4", -}; - -static const char * const adc2_mux_text[] = { - "CH2_AMIC_DISABLE", "CH2_AMIC1", "CH2_AMIC2", "CH2_AMIC3", "CH2_AMIC4", -}; - -static const char * const adc3_mux_text[] = { - "CH3_AMIC_DISABLE", "CH3_AMIC1", "CH3_AMIC3", "CH3_AMIC4", -}; - -static const struct soc_enum adc1_mux_enum = - SOC_ENUM_SINGLE(WCD9378_TX_NEW_CH12_MUX, 0, - ARRAY_SIZE(adc1_mux_text), adc1_mux_text); -static const struct soc_enum adc2_mux_enum = - SOC_ENUM_SINGLE(WCD9378_TX_NEW_CH12_MUX, 3, - ARRAY_SIZE(adc2_mux_text), adc2_mux_text); -static const struct soc_enum adc3_mux_enum = - SOC_ENUM_SINGLE(WCD9378_TX_NEW_CH34_MUX, 0, - ARRAY_SIZE(adc3_mux_text), adc3_mux_text); - -static const struct snd_kcontrol_new adc1_mux = SOC_DAPM_ENUM("ADC1 MUX", adc1_mux_enum); -static const struct snd_kcontrol_new adc2_mux = SOC_DAPM_ENUM("ADC2 MUX", adc2_mux_enum); -static const struct snd_kcontrol_new adc3_mux = SOC_DAPM_ENUM("ADC3 MUX", adc3_mux_enum); - -static const struct snd_kcontrol_new tx0_seq_switch = - SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); -static const struct snd_kcontrol_new tx1_seq_switch = - SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); -static const struct snd_kcontrol_new tx2_seq_switch = - SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); - -static const struct snd_soc_dapm_widget wcd9378_dapm_widgets[] = { - /* Analog mic inputs */ - SND_SOC_DAPM_INPUT("AMIC1"), - SND_SOC_DAPM_INPUT("AMIC2"), - SND_SOC_DAPM_INPUT("AMIC3"), - SND_SOC_DAPM_INPUT("AMIC4"), - - /* ADC input muxes */ - SND_SOC_DAPM_MUX("ADC1 MUX", SND_SOC_NOPM, 0, 0, &adc1_mux), - SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &adc2_mux), - SND_SOC_DAPM_MUX("ADC3 MUX", SND_SOC_NOPM, 0, 0, &adc3_mux), - - /* SDCA TX sequencers (widget shift = ADC index) */ - SND_SOC_DAPM_MIXER_E("TX0 SEQUENCER", SND_SOC_NOPM, 0, 0, - &tx0_seq_switch, 1, wcd9378_tx_sequencer_enable, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("TX1 SEQUENCER", SND_SOC_NOPM, 1, 0, - &tx1_seq_switch, 1, wcd9378_tx_sequencer_enable, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("TX2 SEQUENCER", SND_SOC_NOPM, 2, 0, - &tx2_seq_switch, 1, wcd9378_tx_sequencer_enable, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - - /* Micbias supplies (widget shift = micbias number) */ - SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, - wcd9378_codec_enable_micbias, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, - wcd9378_codec_enable_micbias, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, - wcd9378_codec_enable_micbias, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), - - SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, - wcd9378_codec_enable_micbias_pullup, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, - wcd9378_codec_enable_micbias_pullup, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, - wcd9378_codec_enable_micbias_pullup, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_POST_PMD), - - /* Outputs towards the SoundWire TX bus / LPASS TX macro */ - SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), - SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), - SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), -}; - -static const struct snd_soc_dapm_route wcd9378_audio_map[] = { - { "ADC1_OUTPUT", NULL, "TX0 SEQUENCER" }, - { "TX0 SEQUENCER", "Switch", "ADC1 MUX" }, - { "ADC1 MUX", "CH1_AMIC1", "AMIC1" }, - { "ADC1 MUX", "CH1_AMIC2", "AMIC2" }, - { "ADC1 MUX", "CH1_AMIC3", "AMIC3" }, - { "ADC1 MUX", "CH1_AMIC4", "AMIC4" }, - - { "ADC2_OUTPUT", NULL, "TX1 SEQUENCER" }, - { "TX1 SEQUENCER", "Switch", "ADC2 MUX" }, - { "ADC2 MUX", "CH2_AMIC1", "AMIC1" }, - { "ADC2 MUX", "CH2_AMIC2", "AMIC2" }, - { "ADC2 MUX", "CH2_AMIC3", "AMIC3" }, - { "ADC2 MUX", "CH2_AMIC4", "AMIC4" }, - - { "ADC3_OUTPUT", NULL, "TX2 SEQUENCER" }, - { "TX2 SEQUENCER", "Switch", "ADC3 MUX" }, - { "ADC3 MUX", "CH3_AMIC1", "AMIC1" }, - { "ADC3 MUX", "CH3_AMIC3", "AMIC3" }, - { "ADC3 MUX", "CH3_AMIC4", "AMIC4" }, -}; - -/* - * Map the DT micbias millivolt values onto ITxx_MICB usage codes; - * non-standard voltages go through the sequencer remap table. - */ -static void wcd9378_set_micb_usage_vals(struct snd_soc_component *component) -{ - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); - static const u32 remap_regs[] = { - WCD9378_MICB_REMAP_TABLE_VAL_3, - WCD9378_MICB_REMAP_TABLE_VAL_4, - WCD9378_MICB_REMAP_TABLE_VAL_5, - }; - int i, vout; - - for (i = 0; i < WCD9378_MAX_MICBIAS; i++) { - switch (wcd9378->common.micb_mv[i]) { - case 1200: - wcd9378->micb_usage_val[i] = WCD9378_MICB_USAGE_1P2V; - break; - case 1800: - wcd9378->micb_usage_val[i] = WCD9378_MICB_USAGE_1P8V_OR_PULLUP; - break; - case 2200: - wcd9378->micb_usage_val[i] = WCD9378_MICB_USAGE_2P2V; - break; - case 2500: - wcd9378->micb_usage_val[i] = WCD9378_MICB_USAGE_2P5V; - break; - case 2700: - wcd9378->micb_usage_val[i] = WCD9378_MICB_USAGE_2P7V; - break; - case 2750: - wcd9378->micb_usage_val[i] = WCD9378_MICB_USAGE_2P75V; - break; - case 2800: - wcd9378->micb_usage_val[i] = WCD9378_MICB_USAGE_2P8V; - break; - default: - vout = wcd_get_micb_vout_ctl_val(component->dev, - wcd9378->common.micb_mv[i]); - if (vout < 0) { - wcd9378->micb_usage_val[i] = - WCD9378_MICB_USAGE_1P8V_OR_PULLUP; - break; - } - snd_soc_component_update_bits(component, remap_regs[i], - 0xff, vout); - wcd9378->micb_usage_val[i] = - WCD9378_MICB_USAGE_REMAP_TABLE_3 + i; - break; - } - } -} - -static int wcd9378_soc_codec_probe(struct snd_soc_component *component) -{ - struct wcd9378_priv *wcd9378 = snd_soc_component_get_drvdata(component); - struct device *dev = component->dev; - unsigned int part0 = 0, part1 = 0; - unsigned long time_left; - int ret; - - /* - * Mainline uses sdw_slave_wait_for_init() here; the v7.1.2 base - * predates that helper, open-code it. - */ - time_left = wait_for_completion_timeout(&wcd9378->tx_sdw_dev->initialization_complete, - msecs_to_jiffies(5000)); - if (!time_left) { - dev_err(dev, "soundwire device init timeout\n"); - return -ETIMEDOUT; - } - - snd_soc_component_init_regmap(component, wcd9378->regmap); - - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - return ret; - - regmap_read(wcd9378->regmap, WCD9378_DEV_PART_ID_0, &part0); - regmap_read(wcd9378->regmap, WCD9378_DEV_PART_ID_1, &part1); - dev_dbg(dev, "WCD9378 part id %#x\n", (part1 << 8) | part0); - - /* - * SDCA interrupt type configuration, mirroring the downstream init - * sequence. Nothing consumes these interrupts yet (no MBHC support); - * kept so the bring-up sequence validated on hardware is unchanged. - */ - sdw_write(wcd9378->tx_sdw_dev, WCD9378_SWRS_SCP_SDCA_INTRTYPE_1, 0xff); - sdw_write(wcd9378->tx_sdw_dev, WCD9378_SWRS_SCP_SDCA_INTRTYPE_2, 0x0b); - sdw_write(wcd9378->tx_sdw_dev, WCD9378_SWRS_SCP_SDCA_INTRTYPE_3, 0xff); - - wcd9378_io_init(component); - wcd9378_set_micb_usage_vals(component); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - - return 0; -} - -static const struct snd_soc_component_driver soc_codec_dev_wcd9378 = { - .name = "wcd9378_codec", - .probe = wcd9378_soc_codec_probe, - .controls = wcd9378_snd_controls, - .num_controls = ARRAY_SIZE(wcd9378_snd_controls), - .dapm_widgets = wcd9378_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(wcd9378_dapm_widgets), - .dapm_routes = wcd9378_audio_map, - .num_dapm_routes = ARRAY_SIZE(wcd9378_audio_map), - .endianness = 1, -}; - -static int wcd9378_codec_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct wcd9378_priv *wcd9378 = dev_get_drvdata(dai->dev); - struct wcd9378_sdw_priv *wcd = wcd9378->sdw_priv[dai->id]; - - return wcd9378_sdw_hw_params(wcd, substream, params, dai); -} - -static int wcd9378_codec_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct wcd9378_priv *wcd9378 = dev_get_drvdata(dai->dev); - struct wcd9378_sdw_priv *wcd = wcd9378->sdw_priv[dai->id]; - - return sdw_stream_remove_slave(wcd->sdev, wcd->sruntime); -} - -static int wcd9378_codec_set_sdw_stream(struct snd_soc_dai *dai, - void *stream, int direction) -{ - struct wcd9378_priv *wcd9378 = dev_get_drvdata(dai->dev); - struct wcd9378_sdw_priv *wcd = wcd9378->sdw_priv[dai->id]; - - wcd->sruntime = stream; - - return 0; -} - -static int wcd9378_get_channel_map(const struct snd_soc_dai *dai, - unsigned int *tx_num, unsigned int *tx_slot, - unsigned int *rx_num, unsigned int *rx_slot) -{ - struct wcd9378_priv *wcd9378 = dev_get_drvdata(dai->dev); - struct wcd9378_sdw_priv *wcd = wcd9378->sdw_priv[dai->id]; - int i; - - switch (dai->id) { - case AIF1_PB: - if (!rx_slot || !rx_num) { - dev_err(dai->dev, "Invalid rx_slot %p or rx_num %p\n", - rx_slot, rx_num); - return -EINVAL; - } - - for (i = 0; i < SDW_MAX_PORTS; i++) - rx_slot[i] = wcd->master_channel_map[i]; - - *rx_num = i; - break; - case AIF1_CAP: - if (!tx_slot || !tx_num) { - dev_err(dai->dev, "Invalid tx_slot %p or tx_num %p\n", - tx_slot, tx_num); - return -EINVAL; - } - - for (i = 0; i < SDW_MAX_PORTS; i++) - tx_slot[i] = wcd->master_channel_map[i]; - - *tx_num = i; - break; - default: - break; - } - - return 0; -} - -static const struct snd_soc_dai_ops wcd9378_sdw_dai_ops = { - .hw_params = wcd9378_codec_hw_params, - .hw_free = wcd9378_codec_free, - .set_stream = wcd9378_codec_set_sdw_stream, - .get_channel_map = wcd9378_get_channel_map, -}; - -#define WCD9378_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ - SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) -#define WCD9378_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) - -static struct snd_soc_dai_driver wcd9378_dais[] = { - [0] = { - .name = "wcd9378-sdw-rx", - .playback = { - .stream_name = "WCD AIF Playback", - .rates = WCD9378_RATES, - .formats = WCD9378_FORMATS, - .rate_min = 8000, - .rate_max = 192000, - .channels_min = 1, - .channels_max = 4, - }, - .ops = &wcd9378_sdw_dai_ops, - }, - [1] = { - .name = "wcd9378-sdw-tx", - .capture = { - .stream_name = "WCD AIF Capture", - .rates = WCD9378_RATES, - .formats = WCD9378_FORMATS, - .rate_min = 8000, - .rate_max = 192000, - .channels_min = 1, - .channels_max = 4, - }, - .ops = &wcd9378_sdw_dai_ops, - }, -}; - -static int wcd9378_bind(struct device *dev) -{ - struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev); - int ret; - - /* Give the SDW subdevices some more time to settle */ - usleep_range(5000, 5010); - - ret = component_bind_all(dev, wcd9378); - if (ret) { - dev_err(dev, "Slave bind failed, ret = %d\n", ret); - return ret; - } - - wcd9378->rxdev = of_sdw_find_device_by_node(wcd9378->rxnode); - if (!wcd9378->rxdev) { - dev_err(dev, "could not find rx slave with matching of node\n"); - ret = -EINVAL; - goto err_component_unbind; - } - - wcd9378->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd9378->rxdev); - wcd9378->sdw_priv[AIF1_PB]->wcd9378 = wcd9378; - - wcd9378->txdev = of_sdw_find_device_by_node(wcd9378->txnode); - if (!wcd9378->txdev) { - dev_err(dev, "could not find tx slave with matching of node\n"); - ret = -EINVAL; - goto err_put_rxdev; - } - - wcd9378->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd9378->txdev); - wcd9378->sdw_priv[AIF1_CAP]->wcd9378 = wcd9378; - wcd9378->tx_sdw_dev = dev_to_sdw_dev(wcd9378->txdev); - - /* - * As TX is the main CSR reg interface, it should not be suspended - * first. Explicitly add the dependency link. - */ - if (!device_link_add(wcd9378->rxdev, wcd9378->txdev, - DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { - dev_err(dev, "Could not devlink TX and RX\n"); - ret = -EINVAL; - goto err_put_txdev; - } - - if (!device_link_add(dev, wcd9378->txdev, - DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { - dev_err(dev, "Could not devlink WCD and TX\n"); - ret = -EINVAL; - goto err_remove_link1; - } - - if (!device_link_add(dev, wcd9378->rxdev, - DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME)) { - dev_err(dev, "Could not devlink WCD and RX\n"); - ret = -EINVAL; - goto err_remove_link2; - } - - wcd9378->regmap = wcd9378->sdw_priv[AIF1_CAP]->regmap; - if (!wcd9378->regmap) { - dev_err(dev, "could not get TX device regmap\n"); - ret = -EINVAL; - goto err_remove_link3; - } - - /* - * The SDCA function engine dies when the TX bus enters clock-stop - * and only a codec reset revives it — registers keep their values - * so a regcache sync or a FUNC_ACT re-toggle does not help. The - * downstream stack sidesteps the same problem by marking the TX - * SoundWire master "qcom,is-always-on"; do the equivalent and - * keep the TX slave (and thus its bus) runtime-active while the - * codec is bound. - */ - ret = pm_runtime_resume_and_get(wcd9378->txdev); - if (ret < 0) { - dev_err(dev, "could not resume TX device\n"); - goto err_remove_link3; - } - - ret = snd_soc_register_component(dev, &soc_codec_dev_wcd9378, - wcd9378_dais, ARRAY_SIZE(wcd9378_dais)); - if (ret) { - dev_err(dev, "Codec registration failed\n"); - pm_runtime_put(wcd9378->txdev); - goto err_remove_link3; - } - - return ret; - -err_remove_link3: - device_link_remove(dev, wcd9378->rxdev); -err_remove_link2: - device_link_remove(dev, wcd9378->txdev); -err_remove_link1: - device_link_remove(wcd9378->rxdev, wcd9378->txdev); -err_put_txdev: - put_device(wcd9378->txdev); -err_put_rxdev: - put_device(wcd9378->rxdev); -err_component_unbind: - component_unbind_all(dev, wcd9378); - return ret; -} - -static void wcd9378_unbind(struct device *dev) -{ - struct wcd9378_priv *wcd9378 = dev_get_drvdata(dev); - - snd_soc_unregister_component(dev); - pm_runtime_put(wcd9378->txdev); - device_link_remove(dev, wcd9378->txdev); - device_link_remove(dev, wcd9378->rxdev); - device_link_remove(wcd9378->rxdev, wcd9378->txdev); - component_unbind_all(dev, wcd9378); - mutex_destroy(&wcd9378->micb_lock); - put_device(wcd9378->txdev); - put_device(wcd9378->rxdev); -} - -static const struct component_master_ops wcd9378_comp_ops = { - .bind = wcd9378_bind, - .unbind = wcd9378_unbind, -}; - -static int wcd9378_add_slave_components(struct wcd9378_priv *wcd9378, - struct device *dev, - struct component_match **matchptr) -{ - struct device_node *np = dev->of_node; - - wcd9378->rxnode = of_parse_phandle(np, "qcom,rx-device", 0); - if (!wcd9378->rxnode) { - dev_err(dev, "Couldn't parse phandle to qcom,rx-device!\n"); - return -ENODEV; - } - - component_match_add_release(dev, matchptr, component_release_of, - component_compare_of, wcd9378->rxnode); - - wcd9378->txnode = of_parse_phandle(np, "qcom,tx-device", 0); - if (!wcd9378->txnode) { - dev_err(dev, "Couldn't parse phandle to qcom,tx-device\n"); - return -ENODEV; - } - - component_match_add_release(dev, matchptr, component_release_of, - component_compare_of, wcd9378->txnode); - - return 0; -} - -static int wcd9378_probe(struct platform_device *pdev) -{ - struct component_match *match = NULL; - struct device *dev = &pdev->dev; - struct wcd9378_priv *wcd9378; - int ret, i; - - wcd9378 = devm_kzalloc(dev, sizeof(*wcd9378), GFP_KERNEL); - if (!wcd9378) - return -ENOMEM; - - dev_set_drvdata(dev, wcd9378); - mutex_init(&wcd9378->micb_lock); - for (i = 0; i < ARRAY_SIZE(wcd9378->tx_sys_bit); i++) - wcd9378->tx_sys_bit[i] = -1; - wcd9378->common.dev = dev; - wcd9378->common.max_bias = WCD9378_MAX_MICBIAS; - - wcd9378->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(wcd9378->reset_gpio)) - return dev_err_probe(dev, PTR_ERR(wcd9378->reset_gpio), - "failed to get reset gpio\n"); - - ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(wcd9378_supplies), - wcd9378_supplies); - if (ret) - return dev_err_probe(dev, ret, - "Failed to get and enable supplies\n"); - - ret = wcd_dt_parse_micbias_info(&wcd9378->common); - if (ret) - return dev_err_probe(dev, ret, "Failed to get micbias\n"); - - ret = wcd9378_add_slave_components(wcd9378, dev, &match); - if (ret) - return ret; - - wcd9378_reset(wcd9378); - - ret = component_master_add_with_match(dev, &wcd9378_comp_ops, match); - if (ret) - return ret; - - pm_runtime_set_autosuspend_delay(dev, 1000); - pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_idle(dev); - - return 0; -} - -static void wcd9378_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - - component_master_del(dev, &wcd9378_comp_ops); - - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - pm_runtime_dont_use_autosuspend(dev); -} - -static const struct of_device_id wcd9378_of_match[] = { - { .compatible = "qcom,wcd9378-codec" }, - { } -}; -MODULE_DEVICE_TABLE(of, wcd9378_of_match); - -static struct platform_driver wcd9378_codec_driver = { - .probe = wcd9378_probe, - .remove = wcd9378_remove, - .driver = { - .name = "wcd9378_codec", - .of_match_table = wcd9378_of_match, - .suppress_bind_attrs = true, - }, -}; -module_platform_driver(wcd9378_codec_driver); - -MODULE_DESCRIPTION("WCD9378 Codec driver"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd9378.h b/sound/soc/codecs/wcd9378.h deleted file mode 100644 index fb9e7925968a..000000000000 --- a/sound/soc/codecs/wcd9378.h +++ /dev/null @@ -1,246 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2026, Jorijn van der Graaf - * - * Register map for the Qualcomm WCD9378 audio codec. - * - * The codec exposes its control registers in the SoundWire SDCA control - * address space (bit 30 set, SDCA function number in bits 25:22), accessed - * through the TX SoundWire slave. The analog core registers (function 0, - * implementation-defined region at +0x180000) are layout-compatible with - * the WCD937x family; on top of that the chip adds SDCA-style functions - * (SmartMIC0/1/2, SmartJACK, SmartAMP) whose sequencers drive the analog - * power-up autonomously. - */ - -#ifndef __WCD9378_H__ -#define __WCD9378_H__ - -#include -#include -#include -#include - -/* SDCA function 0 (extension unit): device identity */ -#define WCD9378_FUNC_EXT_ID_0 0x40000048 -#define WCD9378_FUNC_EXT_ID_1 0x40000049 -#define WCD9378_FUNC_EXT_VER 0x40000050 -#define WCD9378_FUNC_STAT 0x40080000 -#define WCD9378_DEV_MANU_ID_0 0x40100060 -#define WCD9378_DEV_MANU_ID_1 0x40100061 -#define WCD9378_DEV_PART_ID_0 0x40100068 -#define WCD9378_DEV_PART_ID_1 0x40100069 -#define WCD9378_DEV_VER 0x40100070 - -/* Analog core (WCD937x-compatible layout), function 0 + 0x180000 */ -#define WCD9378_ANA_PAGE 0x40180000 -#define WCD9378_ANA_BIAS 0x40180001 -#define WCD9378_ANA_BIAS_ANALOG_BIAS_EN BIT(7) -#define WCD9378_ANA_BIAS_PRECHRG_EN BIT(6) -#define WCD9378_ANA_RX_SUPPLIES 0x40180008 -#define WCD9378_ANA_TX_CH1 0x4018000e -#define WCD9378_ANA_TX_CH2 0x4018000f -#define WCD9378_ANA_TX_CH2_HPF1_INIT BIT(6) -#define WCD9378_ANA_TX_CH2_HPF2_INIT BIT(5) -#define WCD9378_ANA_TX_CH3 0x40180010 -#define WCD9378_ANA_TX_CH3_HPF 0x40180011 -#define WCD9378_ANA_TX_CH3_HPF3_INIT BIT(6) -#define WCD9378_ANA_TX_GAIN_MASK GENMASK(4, 0) -#define WCD9378_ANA_MICB1 0x40180022 -#define WCD9378_ANA_MICB2 0x40180023 -#define WCD9378_ANA_MICB2_RAMP 0x40180024 -#define WCD9378_ANA_MICB2_RAMP_SHIFT_CTL_MASK GENMASK(4, 2) -#define WCD9378_ANA_MICB2_RAMP_EN BIT(7) -#define WCD9378_ANA_MICB3 0x40180025 -#define WCD9378_BIAS_VBG_FINE_ADJ 0x40180029 -#define WCD9378_MBHC_CTL_SPARE_1 0x40180058 -#define WCD9378_MICB1_TEST_CTL_2 0x4018006c -#define WCD9378_MICB2_TEST_CTL_2 0x4018006f -#define WCD9378_MICB3_TEST_CTL_2 0x40180072 -#define WCD9378_TX_COM_TXFE_DIV_CTL 0x4018007b -#define WCD9378_TX_COM_TXFE_DIV_SEQ_BYPASS BIT(7) -#define WCD9378_SLEEP_CTL 0x40180103 -#define WCD9378_SLEEP_CTL_BG_CTL_MASK GENMASK(3, 1) -#define WCD9378_SLEEP_CTL_BG_EN BIT(7) -#define WCD9378_SLEEP_CTL_LDOL_BG_SEL BIT(6) -#define WCD9378_TX_NEW_CH12_MUX 0x4018012e -#define WCD9378_TX_NEW_CH12_MUX_CH1_SEL_MASK GENMASK(2, 0) -#define WCD9378_TX_NEW_CH12_MUX_CH2_SEL_MASK GENMASK(5, 3) -#define WCD9378_TX_NEW_CH34_MUX 0x4018012f -#define WCD9378_TX_NEW_CH34_MUX_CH3_SEL_MASK GENMASK(2, 0) -#define WCD9378_HPH_RDAC_GAIN_CTL 0x40180132 -#define WCD9378_HPH_RDAC_HD2_CTL_L 0x40180133 -#define WCD9378_HPH_RDAC_HD2_CTL_R 0x40180136 - -/* Digital page */ -#define WCD9378_TOP_CLK_CFG 0x40180407 -#define WCD9378_CDC_ANA_TX_CLK_CTL 0x40180417 -#define WCD9378_CDC_ANA_TXSCBIAS_CLK_EN BIT(0) -#define WCD9378_CDC_AMIC_CTL 0x4018045a -#define WCD9378_PDM_WD_CTL0 0x40180465 -#define WCD9378_PDM_WD_CTL1 0x40180466 -#define WCD9378_EFUSE_REG_16 0x401804c0 -#define WCD9378_EFUSE_REG_29 0x401804cd -#define WCD9378_PLATFORM_CTL 0x401804f0 - -/* Sequencer block (SEQR) */ -#define WCD9378_SYS_USAGE_CTRL 0x40180501 -#define WCD9378_SYS_USAGE_CTRL_MASK GENMASK(3, 0) -#define WCD9378_HPH_UP_T0 0x40180510 -#define WCD9378_HPH_UP_T9 0x40180519 -#define WCD9378_HPH_DN_T0 0x4018051b -#define WCD9378_SEQ_TX0_STAT 0x40180592 -#define WCD9378_SEQ_TX1_STAT 0x40180593 -#define WCD9378_SEQ_TX2_STAT 0x40180594 -#define WCD9378_MICB_REMAP_TABLE_VAL_3 0x401805a3 -#define WCD9378_MICB_REMAP_TABLE_VAL_4 0x401805a4 -#define WCD9378_MICB_REMAP_TABLE_VAL_5 0x401805a5 -#define WCD9378_SM0_MB_SEL 0x401805b0 -#define WCD9378_SM1_MB_SEL 0x401805b1 -#define WCD9378_SM2_MB_SEL 0x401805b2 -#define WCD9378_SM_MB_SEL_MASK GENMASK(1, 0) -#define WCD9378_MB_PULLUP_EN 0x401805b3 - -/* SmartAMP SDCA function */ -#define WCD9378_SMP_AMP_FUNC_STAT 0x40880000 -#define WCD9378_SMP_AMP_FUNC_ACT 0x40880008 - -/* SmartJACK SDCA function (hosts ADC2 when fed from AMIC2) */ -#define WCD9378_CMT_GRP_MASK 0x40c00008 -#define WCD9378_SMP_JACK_IT31_MICB 0x40c00798 -#define WCD9378_SMP_JACK_IT31_USAGE 0x40c007a0 -#define WCD9378_SMP_JACK_PDE34_REQ_PS 0x40c00808 -#define WCD9378_SMP_JACK_FUNC_STAT 0x40c80000 -#define WCD9378_SMP_JACK_FUNC_ACT 0x40c80008 -#define WCD9378_SMP_JACK_PDE34_ACT_PS 0x40c80800 - -/* SmartMIC0/1/2 SDCA functions (ADC1/ADC2/ADC3 sequencers) */ -#define WCD9378_SMP_MIC_BASE(n) (0x41000000 + (n) * 0x400000) -#define WCD9378_SMP_MIC_IT11_MICB(n) (WCD9378_SMP_MIC_BASE(n) + 0x98) -#define WCD9378_SMP_MIC_IT11_USAGE(n) (WCD9378_SMP_MIC_BASE(n) + 0xa0) -#define WCD9378_SMP_MIC_PDE11_REQ_PS(n) (WCD9378_SMP_MIC_BASE(n) + 0x108) -#define WCD9378_SMP_MIC_OT10_USAGE(n) (WCD9378_SMP_MIC_BASE(n) + 0x3a0) -#define WCD9378_SMP_MIC_FUNC_STAT(n) (WCD9378_SMP_MIC_BASE(n) + 0x80000) -#define WCD9378_SMP_MIC_FUNC_ACT(n) (WCD9378_SMP_MIC_BASE(n) + 0x80008) -#define WCD9378_SMP_MIC_PDE11_ACT_PS(n) (WCD9378_SMP_MIC_BASE(n) + 0x80100) - -#define WCD9378_MAX_REGISTER 0x41900070 - -/* - * Raw (16-bit, non-paged) Qualcomm slave SCP registers, written with - * sdw_write() directly. Bus clock indication towards the codec and - * SDCA interrupt type configuration. - */ -#define WCD9378_SWRS_SCP_BASE_CLK 0x4d -#define WCD9378_SWRS_SCP_BUSCLK_SCALE_BANK0 0x62 -#define WCD9378_SWRS_SCP_BUSCLK_SCALE_BANK1 0x72 -#define WCD9378_SWRS_SCP_SDCA_INTRTYPE_1 0xf4 -#define WCD9378_SWRS_SCP_SDCA_INTRTYPE_2 0xf8 -#define WCD9378_SWRS_SCP_SDCA_INTRTYPE_3 0xfc -#define WCD9378_SWRS_SCP_HOST_CLK_DIV2_CTL(m) (0xe0 + 0x10 * (m)) -#define WCD9378_SWRS_BASE_CLK_19P2MHZ 0x01 -#define WCD9378_SWRS_CLK_SCALE_DIV2 0x02 /* 9.6 MHz */ -#define WCD9378_SWRS_CLK_SCALE_DIV4 0x03 /* 4.8 MHz */ - -/* ITxx_USAGE ADC mode values */ -#define WCD9378_ADC_USAGE_HIFI 0x01 -#define WCD9378_ADC_USAGE_LO_HIF 0x02 -#define WCD9378_ADC_USAGE_NORMAL 0x03 -#define WCD9378_ADC_USAGE_LP 0x05 -#define WCD9378_ADC_USAGE_OFF 0x00 - -/* ITxx_MICB usage values */ -#define WCD9378_MICB_USAGE_OFF 0x00 -#define WCD9378_MICB_USAGE_PULL_DOWN 0x01 -#define WCD9378_MICB_USAGE_1P2V 0x02 -#define WCD9378_MICB_USAGE_1P8V_OR_PULLUP 0x03 -#define WCD9378_MICB_USAGE_2P5V 0x04 -#define WCD9378_MICB_USAGE_2P75V 0x05 -#define WCD9378_MICB_USAGE_2P2V 0xf0 -#define WCD9378_MICB_USAGE_2P7V 0xf1 -#define WCD9378_MICB_USAGE_2P8V 0xf2 -#define WCD9378_MICB_USAGE_REMAP_TABLE_3 0xf3 -#define WCD9378_MICB_USAGE_REMAP_TABLE_4 0xf4 -#define WCD9378_MICB_USAGE_REMAP_TABLE_5 0xf5 - -/* PDExx_REQ_PS power states */ -#define WCD9378_PDE_PS0_ON 0x00 -#define WCD9378_PDE_PS3_OFF 0x03 - -#define WCD9378_MAX_MICBIAS 3 -#define WCD9378_MAX_SWR_CH_IDS 15 -#define WCD9378_SWRM_CH_MASK(ch_idx) BIT((ch_idx) - 1) - -enum wcd9378_tx_sdw_ports { - WCD9378_ADC_1_PORT = 1, - WCD9378_ADC_2_PORT, - WCD9378_ADC_3_PORT, - WCD9378_DMIC_0_1_MBHC_PORT, - WCD9378_DMIC_2_5_PORT, - WCD9378_MAX_TX_SWR_PORTS = WCD9378_DMIC_2_5_PORT, -}; - -enum wcd9378_rx_sdw_ports { - WCD9378_HPH_PORT = 1, - WCD9378_CLSH_PORT, - WCD9378_COMP_PORT, - WCD9378_LO_PORT, - WCD9378_DSD_PORT, - WCD9378_MAX_SWR_PORTS = WCD9378_DSD_PORT, -}; - -enum wcd9378_tx_sdw_channels { - WCD9378_ADC1, - WCD9378_ADC2, - WCD9378_ADC3, - WCD9378_DMIC0, - WCD9378_DMIC1, - WCD9378_MBHC, - WCD9378_DMIC2, - WCD9378_DMIC3, - WCD9378_DMIC4, - WCD9378_DMIC5, -}; - -enum wcd9378_rx_sdw_channels { - WCD9378_HPH_L, - WCD9378_HPH_R, - WCD9378_CLSH, - WCD9378_COMP_L, - WCD9378_COMP_R, - WCD9378_LO, - WCD9378_DSD_L, - WCD9378_DSD_R, -}; - -struct wcd9378_priv; -struct wcd9378_sdw_priv { - struct sdw_slave *sdev; - struct sdw_stream_config sconfig; - struct sdw_stream_runtime *sruntime; - struct sdw_port_config port_config[WCD9378_MAX_SWR_PORTS]; - struct wcd_sdw_ch_info *ch_info; - bool port_enable[WCD9378_MAX_SWR_CH_IDS]; - unsigned int master_channel_map[SDW_MAX_PORTS]; - int active_ports; - bool is_tx; - struct wcd9378_priv *wcd9378; - struct regmap *regmap; -}; - -#if IS_ENABLED(CONFIG_SND_SOC_WCD9378_SDW) -int wcd9378_sdw_hw_params(struct wcd9378_sdw_priv *wcd, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai); -#else -static inline int wcd9378_sdw_hw_params(struct wcd9378_sdw_priv *wcd, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - return -EOPNOTSUPP; -} -#endif - -#endif /* __WCD9378_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index 06946add653a..006b283484d9 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -224,21 +224,6 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s dev_err(dai->dev, "Failed to prepare Graph %d\n", rc); goto err; } - - /* - * Start the port already at prepare, like q6afe does: this starts - * the interface clocks before the DAPM power-up sequence runs, so - * codecs that need a live BCLK at power-up (e.g. aw88261) can - * start synchronously. The trigger callback keeps its start as a - * no-op fallback via is_port_started. - */ - rc = q6apm_graph_start(dai_data->graph[dai->id]); - if (rc < 0) { - dev_err(dai->dev, "Failed to start APM port %d\n", dai->id); - goto err; - } - dai_data->is_port_started[dai->id] = true; - return 0; err: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index ce28bfac329a..a36666999ac1 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -34,7 +34,6 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) switch (cpu_dai->id) { case PRIMARY_MI2S_RX...QUATERNARY_MI2S_TX: case QUINARY_MI2S_RX...QUINARY_MI2S_TX: - case SENARY_MI2S_RX...SENARY_MI2S_TX: snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); break; case WSA_CODEC_DMA_RX_0: