--- /dev/null
+STA32X audio CODEC
+
+The driver for this device only supports I2C.
+
+Required properties:
+
+ - compatible: "st,sta32x"
+ - reg: the I2C address of the device for I2C
+ - reset-gpios: a GPIO spec for the reset pin. If specified, it will be
+ deasserted before communication to the codec starts.
+
+ - power-down-gpios: a GPIO spec for the power down pin. If specified,
+ it will be deasserted before communication to the codec
+ starts.
+
+ - Vdda-supply: regulator spec, providing 3.3V
+ - Vdd3-supply: regulator spec, providing 3.3V
+ - Vcc-supply: regulator spec, providing 5V - 26V
+
+Optional properties:
+
+ - st,output-conf: number, Selects the output configuration:
+ 0: 2-channel (full-bridge) power, 2-channel data-out
+ 1: 2 (half-bridge). 1 (full-bridge) on-board power
+ 2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
+ 3: 1 Channel Mono-Parallel
+ If parameter is missing, mode 0 will be enabled.
+ This property has to be specified as '/bits/ 8' value.
+
+ - st,ch1-output-mapping: Channel 1 output mapping
+ - st,ch2-output-mapping: Channel 2 output mapping
+ - st,ch3-output-mapping: Channel 3 output mapping
+ 0: Channel 1
+ 1: Channel 2
+ 2: Channel 3
+ If parameter is missing, channel 1 is chosen.
+ This properties have to be specified as '/bits/ 8' values.
+
+ - st,thermal-warning-recover:
+ If present, thermal warning recovery is enabled.
+
+ - st,thermal-warning-adjustment:
+ If present, thermal warning adjustment is enabled.
+
+ - st,fault-detect-recovery:
+ If present, then fault recovery will be enabled.
+
+ - st,drop-compensation-ns: number
+ Only required for "st,ffx-power-output-mode" ==
+ "variable-drop-compensation".
+ Specifies the drop compensation in nanoseconds.
+ The value must be in the range of 0..300, and only
+ multiples of 20 are allowed. Default is 140ns.
+
+ - st,max-power-use-mpcc:
+ If present, then MPCC bits are used for MPC coefficients,
+ otherwise standard MPC coefficients are used.
+
+ - st,max-power-corr:
+ If present, power bridge correction for THD reduction near maximum
+ power output is enabled.
+
+ - st,am-reduction-mode:
+ If present, FFX mode runs in AM reduction mode, otherwise normal
+ FFX mode is used.
+
+ - st,odd-pwm-speed-mode:
+ If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
+ channels. If not present, normal PWM spped mode (384 kHz) will be used.
+
+ - st,invalid-input-detect-mute:
+ If present, automatic invalid input detect mute is enabled.
+
+Example:
+
+codec: sta32x@38 {
+ compatible = "st,sta32x";
+ reg = <0x1c>;
+ reset-gpios = <&gpio1 19 0>;
+ power-down-gpios = <&gpio1 16 0>;
+ st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel
+ // (full-bridge) power,
+ // 2-channel data-out
+ st,ch1-output-mapping = /bits/ 8 <0>; // set channel 1 output ch 1
+ st,ch2-output-mapping = /bits/ 8 <0>; // set channel 2 output ch 1
+ st,ch3-output-mapping = /bits/ 8 <0>; // set channel 3 output ch 1
+ st,max-power-correction; // enables power bridge
+ // correction for THD reduction
+ // near maximum power output
+ st,invalid-input-detect-mute; // mute if no valid digital
+ // audio signal is provided.
+};
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
dev_err(codec->dev, "Failed to startup device\n");
return ret;
}
- /* set thermal warning adjustment and recovery */
+
+ /* CONFA */
if (!pdata->thermal_warning_recovery)
thermal |= STA32X_CONFA_TWAB;
if (!pdata->thermal_warning_adjustment)
thermal |= STA32X_CONFA_TWRB;
+ if (!pdata->fault_detect_recovery)
+ thermal |= STA32X_CONFA_FDRB;
regmap_update_bits(sta32x->regmap, STA32X_CONFA,
- STA32X_CONFA_TWAB | STA32X_CONFA_TWRB,
+ STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
+ STA32X_CONFA_FDRB,
thermal);
+ /* CONFC */
+ regmap_update_bits(sta32x->regmap, STA32X_CONFC,
+ STA32X_CONFC_CSZ_MASK,
+ pdata->drop_compensation_ns
+ << STA32X_CONFC_CSZ_SHIFT);
+
+ /* CONFE */
+ regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+ STA32X_CONFE_MPCV,
+ pdata->max_power_use_mpcc ?
+ STA32X_CONFE_MPCV : 0);
+ regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+ STA32X_CONFE_MPC,
+ pdata->max_power_correction ?
+ STA32X_CONFE_MPC : 0);
+ regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+ STA32X_CONFE_AME,
+ pdata->am_reduction_mode ?
+ STA32X_CONFE_AME : 0);
+ regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+ STA32X_CONFE_PWMS,
+ pdata->odd_pwm_speed_mode ?
+ STA32X_CONFE_PWMS : 0);
+
+ /* CONFF */
+ regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+ STA32X_CONFF_IDE,
+ pdata->invalid_input_detect_mute ?
+ STA32X_CONFF_IDE : 0);
+
/* select output configuration */
regmap_update_bits(sta32x->regmap, STA32X_CONFF,
STA32X_CONFF_OCFG_MASK,
.rd_table = &sta32x_read_regs,
.volatile_table = &sta32x_volatile_regs,
};
+
+#ifdef CONFIG_OF
+static const struct of_device_id st32x_dt_ids[] = {
+ { .compatible = "st,sta32x", },
+ { }
};
+MODULE_DEVICE_TABLE(of, st32x_dt_ids);
+
+static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
+{
+ struct device_node *np = dev->of_node;
+ struct sta32x_platform_data *pdata;
+ u16 tmp;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ of_property_read_u8(np, "st,output-conf",
+ &pdata->output_conf);
+ of_property_read_u8(np, "st,ch1-output-mapping",
+ &pdata->ch1_output_mapping);
+ of_property_read_u8(np, "st,ch2-output-mapping",
+ &pdata->ch2_output_mapping);
+ of_property_read_u8(np, "st,ch3-output-mapping",
+ &pdata->ch3_output_mapping);
+
+ if (of_get_property(np, "st,thermal-warning-recovery", NULL))
+ pdata->thermal_warning_recovery = 1;
+ if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
+ pdata->thermal_warning_adjustment = 1;
+ if (of_get_property(np, "st,needs_esd_watchdog", NULL))
+ pdata->needs_esd_watchdog = 1;
+
+ tmp = 140;
+ of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
+ pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+
+ /* CONFE */
+ if (of_get_property(np, "st,max-power-use-mpcc", NULL))
+ pdata->max_power_use_mpcc = 1;
+
+ if (of_get_property(np, "st,max-power-correction", NULL))
+ pdata->max_power_correction = 1;
+
+ if (of_get_property(np, "st,am-reduction-mode", NULL))
+ pdata->am_reduction_mode = 1;
+
+ if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
+ pdata->odd_pwm_speed_mode = 1;
+
+ /* CONFF */
+ if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
+ pdata->invalid_input_detect_mute = 1;
+
+ sta32x->pdata = pdata;
+
+ return 0;
+}
+#endif
static int sta32x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
mutex_init(&sta32x->coeff_lock);
sta32x->pdata = dev_get_platdata(dev);
+#ifdef CONFIG_OF
+ if (dev->of_node) {
+ ret = sta32x_probe_dt(dev, sta32x);
+ if (ret < 0)
+ return ret;
+ }
+#endif
+
/* GPIOs */
sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
if (IS_ERR(sta32x->gpiod_nreset)) {
.driver = {
.name = "sta32x",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(st32x_dt_ids),
},
.probe = sta32x_i2c_probe,
.remove = sta32x_i2c_remove,