mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
Immutable branch between MFD, Pinctrl and soundwire due for the v6.6 merge window
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAmTfkKAACgkQUa+KL4f8 d2FwzxAArqA6/pebr+19TNvv6hFuUxpbR57jr0XM4YzPNvBJs/iEk1wfdGTkOdFG NSWVGDIE4aY62mwehq0AEfYQVrTzKcAuMJZgOeg0lzReBYMhn6WuyCc192L7tgRA H3bm2oQcSVXiNGXvKoTr9fDckBf5Ta9OcoVmf48YFQXvwv+vuO/kS77JuVkLZxwH yycmLxD7PJlvikj8ITsg8pzj/xLhCpHziLsyMjQpgvr7hRPG+f5W0Dq9vNONI5IL YU810I2Dp+bU5YGAElGTrSwHnI2FrCUlrcR88ukGPN9rBn84TcmypWsetMR83juo zcn6AfUp6WuhaQxs06tTzsNc9cQpKjtjYojTZ1OYYsC7eOhlF3ifQLEiqVJbfY0W 8BN1e3QDf59ZwXAUJJKrV37yHc9/uuGVerc7dzkng0f2OHosNWzLNyy7LiOb80dD Hp/yGxXXyiASGjswSaxqbu67TuEPWKuoceW0wRS9/ExZx+cPvEzdTzdCWYej7cDH UmJup/J053htC1k/vos+0SRezqeuXvHXDRuwP9Lnhdct9eeDiGFn920S9d2DVjgR PImk+O9dTnOVehNY7+I9tqBK9dM3AolH/jbEQQ6VkIfm2clewBy+1M0SohWIBW/E 4iQbtPkVXwGHI9Lp+6pP4exhA58FQCDL4KoUkchWsokF9zTM/eM= =Sb7O -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmTfnlEACgkQJNaLcl1U h9BD2Af/au+JWxg2p6BOe2KLaqsVbWsijBMWaoAz3XRsiTow5MEfo0I4jSsw9wQw YYxJ++VFlydheP+VpPC7At6dqz5BGbk/5uG9Vh4AAwgnVL/OCNJqT54jJ5RV4lh6 zWh4xXa8enKfKGuWRbCbCpYIOEvzwFaHYe4V1axbiAJYunTaRcBvEyJXeaSQGKXr uI7kTef/h1j+HWgGVkm8ODTf/YfXpuH9myysDBYcIlb4I6Daphtk70M1IdbyepXo khTV9r3Weof2tUajRYUuiegaEW3UFU/tEP87/UVKZ5k6eef7O77evqdWRWcYhMfw E8oCacS26cGGGL7ynj+XxmV5po7dJw== =xI4n -----END PGP SIGNATURE----- mfd: Immutable branch between MFD, Pinctrl and soundwire due for the v6.6 merge window Merge tag 'ib-mfd-pinctrl-soundwire-v6.6' of https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd into tmp Immutable branch between MFD, Pinctrl and soundwire due for the v6.6 merge window
This commit is contained in:
commit
038e0da7ba
313
Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
Normal file
313
Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
Normal file
@ -0,0 +1,313 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/cirrus,cs42l43.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus Logic CS42L43 Audio CODEC
|
||||
|
||||
maintainers:
|
||||
- patches@opensource.cirrus.com
|
||||
|
||||
description: |
|
||||
The CS42L43 is an audio CODEC with integrated MIPI SoundWire interface
|
||||
(Version 1.2.1 compliant), I2C, SPI, and I2S/TDM interfaces designed
|
||||
for portable applications. It provides a high dynamic range, stereo
|
||||
DAC for headphone output, two integrated Class D amplifiers for
|
||||
loudspeakers, and two ADCs for wired headset microphone input or
|
||||
stereo line input. PDM inputs are provided for digital microphones.
|
||||
|
||||
allOf:
|
||||
- $ref: dai-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- cirrus,cs42l43
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vdd-p-supply:
|
||||
description:
|
||||
Power supply for the high voltage interface.
|
||||
|
||||
vdd-a-supply:
|
||||
description:
|
||||
Power supply for internal analog circuits.
|
||||
|
||||
vdd-d-supply:
|
||||
description:
|
||||
Power supply for internal digital circuits. Can be internally supplied.
|
||||
|
||||
vdd-io-supply:
|
||||
description:
|
||||
Power supply for external interface and internal digital logic.
|
||||
|
||||
vdd-cp-supply:
|
||||
description:
|
||||
Power supply for the amplifier 3 and 4 charge pump.
|
||||
|
||||
vdd-amp-supply:
|
||||
description:
|
||||
Power supply for amplifier 1 and 2.
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
"#sound-dai-cells":
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Synchronous audio clock provided on mclk_in.
|
||||
|
||||
clock-names:
|
||||
const: mclk
|
||||
|
||||
cirrus,bias-low:
|
||||
type: boolean
|
||||
description:
|
||||
Select a 1.8V headset micbias rather than 2.8V.
|
||||
|
||||
cirrus,bias-sense-microamp:
|
||||
description:
|
||||
Current at which the headset micbias sense clamp will engage, 0 to
|
||||
disable.
|
||||
enum: [ 0, 14, 23, 41, 50, 60, 68, 86, 95 ]
|
||||
default: 0
|
||||
|
||||
cirrus,bias-ramp-ms:
|
||||
description:
|
||||
Time in milliseconds the hardware allows for the headset micbias to
|
||||
ramp up.
|
||||
enum: [ 10, 40, 90, 170 ]
|
||||
default: 170
|
||||
|
||||
cirrus,detect-us:
|
||||
description:
|
||||
Time in microseconds the type detection will run for. Long values will
|
||||
cause more audible effects, but give more accurate detection.
|
||||
enum: [ 20, 100, 1000, 10000, 50000, 75000, 100000, 200000 ]
|
||||
default: 10000
|
||||
|
||||
cirrus,button-automute:
|
||||
type: boolean
|
||||
description:
|
||||
Enable the hardware automuting of decimator 1 when a headset button is
|
||||
pressed.
|
||||
|
||||
cirrus,buttons-ohms:
|
||||
description:
|
||||
Impedance in Ohms for each headset button, these should be listed in
|
||||
ascending order.
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
|
||||
cirrus,tip-debounce-ms:
|
||||
description:
|
||||
Software debounce on tip sense triggering in milliseconds.
|
||||
default: 0
|
||||
|
||||
cirrus,tip-invert:
|
||||
type: boolean
|
||||
description:
|
||||
Indicates tip detect polarity, inverted implies open-circuit whilst the
|
||||
jack is inserted.
|
||||
|
||||
cirrus,tip-disable-pullup:
|
||||
type: boolean
|
||||
description:
|
||||
Indicates if the internal pullup on the tip detect should be disabled.
|
||||
|
||||
cirrus,tip-fall-db-ms:
|
||||
description:
|
||||
Time in milliseconds a falling edge on the tip detect should be hardware
|
||||
debounced for. Note the falling edge is considered after the invert.
|
||||
enum: [ 0, 125, 250, 500, 750, 1000, 1250, 1500 ]
|
||||
default: 500
|
||||
|
||||
cirrus,tip-rise-db-ms:
|
||||
description:
|
||||
Time in milliseconds a rising edge on the tip detect should be hardware
|
||||
debounced for. Note the rising edge is considered after the invert.
|
||||
enum: [ 0, 125, 250, 500, 750, 1000, 1250, 1500 ]
|
||||
default: 500
|
||||
|
||||
cirrus,use-ring-sense:
|
||||
type: boolean
|
||||
description:
|
||||
Indicates if the ring sense should be used.
|
||||
|
||||
cirrus,ring-invert:
|
||||
type: boolean
|
||||
description:
|
||||
Indicates ring detect polarity, inverted implies open-circuit whilst the
|
||||
jack is inserted.
|
||||
|
||||
cirrus,ring-disable-pullup:
|
||||
type: boolean
|
||||
description:
|
||||
Indicates if the internal pullup on the ring detect should be disabled.
|
||||
|
||||
cirrus,ring-fall-db-ms:
|
||||
description:
|
||||
Time in milliseconds a falling edge on the ring detect should be hardware
|
||||
debounced for. Note the falling edge is considered after the invert.
|
||||
enum: [ 0, 125, 250, 500, 750, 1000, 1250, 1500 ]
|
||||
default: 500
|
||||
|
||||
cirrus,ring-rise-db-ms:
|
||||
description:
|
||||
Time in milliseconds a rising edge on the ring detect should be hardware
|
||||
debounced for. Note the rising edge is considered after the invert.
|
||||
enum: [ 0, 125, 250, 500, 750, 1000, 1250, 1500 ]
|
||||
default: 500
|
||||
|
||||
pinctrl:
|
||||
type: object
|
||||
$ref: /schemas/pinctrl/pinctrl.yaml#
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-ranges:
|
||||
items:
|
||||
- description: A phandle to the CODEC pinctrl node
|
||||
minimum: 0
|
||||
- const: 0
|
||||
- const: 0
|
||||
- const: 3
|
||||
|
||||
patternProperties:
|
||||
"-state$":
|
||||
oneOf:
|
||||
- $ref: "#/$defs/cirrus-cs42l43-state"
|
||||
- patternProperties:
|
||||
"-pins$":
|
||||
$ref: "#/$defs/cirrus-cs42l43-state"
|
||||
additionalProperties: false
|
||||
|
||||
spi:
|
||||
type: object
|
||||
$ref: /schemas/spi/spi-controller.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
$defs:
|
||||
cirrus-cs42l43-state:
|
||||
type: object
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/pinctrl/pincfg-node.yaml#
|
||||
- $ref: /schemas/pinctrl/pinmux-node.yaml#
|
||||
|
||||
oneOf:
|
||||
- required: [ groups ]
|
||||
- required: [ pins ]
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
groups:
|
||||
enum: [ gpio1, gpio2, gpio3, asp, pdmout2, pdmout1, i2c, spi ]
|
||||
|
||||
pins:
|
||||
enum: [ gpio1, gpio2, gpio3,
|
||||
asp_dout, asp_fsync, asp_bclk,
|
||||
pdmout2_clk, pdmout2_data, pdmout1_clk, pdmout1_data,
|
||||
i2c_sda, i2c_scl,
|
||||
spi_miso, spi_sck, spi_ssb ]
|
||||
|
||||
function:
|
||||
enum: [ gpio, spdif, irq, mic-shutter, spk-shutter ]
|
||||
|
||||
drive-strength:
|
||||
description: Set drive strength in mA
|
||||
enum: [ 1, 2, 4, 8, 9, 10, 12, 16 ]
|
||||
|
||||
input-debounce:
|
||||
description: Set input debounce in uS
|
||||
enum: [ 0, 85 ]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-p-supply
|
||||
- vdd-a-supply
|
||||
- vdd-io-supply
|
||||
- vdd-cp-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cs42l43: codec@1a {
|
||||
compatible = "cirrus,cs42l43";
|
||||
reg = <0x1a>;
|
||||
|
||||
vdd-p-supply = <&vdd5v0>;
|
||||
vdd-a-supply = <&vdd1v8>;
|
||||
vdd-io-supply = <&vdd1v8>;
|
||||
vdd-cp-supply = <&vdd1v8>;
|
||||
vdd-amp-supply = <&vdd5v0>;
|
||||
|
||||
reset-gpios = <&gpio 0>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <56 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
#sound-dai-cells = <1>;
|
||||
|
||||
clocks = <&clks 0>;
|
||||
clock-names = "mclk";
|
||||
|
||||
cs42l43_pins: pinctrl {
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-ranges = <&cs42l43_pins 0 0 3>;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinsettings>;
|
||||
|
||||
pinsettings: default-state {
|
||||
shutter-pins {
|
||||
groups = "gpio3";
|
||||
function = "mic-shutter";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cs-gpios = <&cs42l43_pins 1 0>;
|
||||
|
||||
sensor@0 {
|
||||
compatible = "bosch,bme680";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1400000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -4886,7 +4886,10 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
L: patches@opensource.cirrus.com
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/cirrus,cs*
|
||||
F: drivers/mfd/cs42l43*
|
||||
F: drivers/pinctrl/cirrus/pinctrl-cs42l43*
|
||||
F: include/dt-bindings/sound/cs*
|
||||
F: include/linux/mfd/cs42l43*
|
||||
F: include/sound/cs*
|
||||
F: sound/pci/hda/cs*
|
||||
F: sound/pci/hda/hda_cs_dsp_ctl.*
|
||||
|
@ -237,6 +237,29 @@ config MFD_CROS_EC_DEV
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called cros-ec-dev.
|
||||
|
||||
config MFD_CS42L43
|
||||
tristate
|
||||
select MFD_CORE
|
||||
select REGMAP
|
||||
|
||||
config MFD_CS42L43_I2C
|
||||
tristate "Cirrus Logic CS42L43 (I2C)"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select MFD_CS42L43
|
||||
help
|
||||
Select this to support the Cirrus Logic CS42L43 PC CODEC with
|
||||
headphone and class D speaker drivers over I2C.
|
||||
|
||||
config MFD_CS42L43_SDW
|
||||
tristate "Cirrus Logic CS42L43 (SoundWire)"
|
||||
depends on SOUNDWIRE
|
||||
select REGMAP_SOUNDWIRE
|
||||
select MFD_CS42L43
|
||||
help
|
||||
Select this to support the Cirrus Logic CS42L43 PC CODEC with
|
||||
headphone and class D speaker drivers over SoundWire.
|
||||
|
||||
config MFD_MADERA
|
||||
tristate "Cirrus Logic Madera codecs"
|
||||
select MFD_CORE
|
||||
|
@ -13,6 +13,9 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o
|
||||
obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
|
||||
obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o
|
||||
obj-$(CONFIG_MFD_CS42L43) += cs42l43.o
|
||||
obj-$(CONFIG_MFD_CS42L43_I2C) += cs42l43-i2c.o
|
||||
obj-$(CONFIG_MFD_CS42L43_SDW) += cs42l43-sdw.o
|
||||
obj-$(CONFIG_MFD_ENE_KB3930) += ene-kb3930.o
|
||||
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
|
||||
obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o
|
||||
|
98
drivers/mfd/cs42l43-i2c.c
Normal file
98
drivers/mfd/cs42l43-i2c.c
Normal file
@ -0,0 +1,98 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* CS42L43 I2C driver
|
||||
*
|
||||
* Copyright (C) 2022-2023 Cirrus Logic, Inc. and
|
||||
* Cirrus Logic International Semiconductor Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/cs42l43-regs.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "cs42l43.h"
|
||||
|
||||
static const struct regmap_config cs42l43_i2c_regmap = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.reg_format_endian = REGMAP_ENDIAN_BIG,
|
||||
.val_format_endian = REGMAP_ENDIAN_BIG,
|
||||
|
||||
.max_register = CS42L43_MCU_RAM_MAX,
|
||||
.readable_reg = cs42l43_readable_register,
|
||||
.volatile_reg = cs42l43_volatile_register,
|
||||
.precious_reg = cs42l43_precious_register,
|
||||
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.reg_defaults = cs42l43_reg_default,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs42l43_reg_default),
|
||||
};
|
||||
|
||||
static int cs42l43_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct cs42l43 *cs42l43;
|
||||
int ret;
|
||||
|
||||
cs42l43 = devm_kzalloc(&i2c->dev, sizeof(*cs42l43), GFP_KERNEL);
|
||||
if (!cs42l43)
|
||||
return -ENOMEM;
|
||||
|
||||
cs42l43->dev = &i2c->dev;
|
||||
cs42l43->irq = i2c->irq;
|
||||
/* A device on an I2C is always attached by definition. */
|
||||
cs42l43->attached = true;
|
||||
|
||||
cs42l43->regmap = devm_regmap_init_i2c(i2c, &cs42l43_i2c_regmap);
|
||||
if (IS_ERR(cs42l43->regmap)) {
|
||||
ret = PTR_ERR(cs42l43->regmap);
|
||||
dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return cs42l43_dev_probe(cs42l43);
|
||||
}
|
||||
|
||||
static void cs42l43_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(&i2c->dev);
|
||||
|
||||
cs42l43_dev_remove(cs42l43);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
static const struct of_device_id cs42l43_of_match[] = {
|
||||
{ .compatible = "cirrus,cs42l43", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cs42l43_of_match);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
static const struct acpi_device_id cs42l43_acpi_match[] = {
|
||||
{ "CSC4243", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cs42l43_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver cs42l43_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "cs42l43",
|
||||
.pm = pm_ptr(&cs42l43_pm_ops),
|
||||
.of_match_table = of_match_ptr(cs42l43_of_match),
|
||||
.acpi_match_table = ACPI_PTR(cs42l43_acpi_match),
|
||||
},
|
||||
|
||||
.probe = cs42l43_i2c_probe,
|
||||
.remove = cs42l43_i2c_remove,
|
||||
};
|
||||
module_i2c_driver(cs42l43_i2c_driver);
|
||||
|
||||
MODULE_IMPORT_NS(MFD_CS42L43);
|
||||
|
||||
MODULE_DESCRIPTION("CS42L43 I2C Driver");
|
||||
MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
|
||||
MODULE_LICENSE("GPL");
|
239
drivers/mfd/cs42l43-sdw.c
Normal file
239
drivers/mfd/cs42l43-sdw.c
Normal file
@ -0,0 +1,239 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* CS42L43 SoundWire driver
|
||||
*
|
||||
* Copyright (C) 2022-2023 Cirrus Logic, Inc. and
|
||||
* Cirrus Logic International Semiconductor Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mfd/cs42l43-regs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_registers.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
|
||||
#include "cs42l43.h"
|
||||
|
||||
enum cs42l43_sdw_ports {
|
||||
CS42L43_DMIC_DEC_ASP_PORT = 1,
|
||||
CS42L43_SPK_TX_PORT,
|
||||
CS42L43_SPDIF_HP_PORT,
|
||||
CS42L43_SPK_RX_PORT,
|
||||
CS42L43_ASP_PORT,
|
||||
};
|
||||
|
||||
static const struct regmap_config cs42l43_sdw_regmap = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
|
||||
.max_register = CS42L43_MCU_RAM_MAX,
|
||||
.readable_reg = cs42l43_readable_register,
|
||||
.volatile_reg = cs42l43_volatile_register,
|
||||
.precious_reg = cs42l43_precious_register,
|
||||
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.reg_defaults = cs42l43_reg_default,
|
||||
.num_reg_defaults = ARRAY_SIZE(cs42l43_reg_default),
|
||||
};
|
||||
|
||||
static int cs42l43_read_prop(struct sdw_slave *sdw)
|
||||
{
|
||||
struct sdw_slave_prop *prop = &sdw->prop;
|
||||
struct device *dev = &sdw->dev;
|
||||
struct sdw_dpn_prop *dpn;
|
||||
unsigned long addr;
|
||||
int nval;
|
||||
int i;
|
||||
u32 bit;
|
||||
|
||||
prop->use_domain_irq = true;
|
||||
prop->paging_support = true;
|
||||
prop->wake_capable = true;
|
||||
prop->source_ports = BIT(CS42L43_DMIC_DEC_ASP_PORT) | BIT(CS42L43_SPK_TX_PORT);
|
||||
prop->sink_ports = BIT(CS42L43_SPDIF_HP_PORT) |
|
||||
BIT(CS42L43_SPK_RX_PORT) | BIT(CS42L43_ASP_PORT);
|
||||
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
|
||||
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY |
|
||||
SDW_SCP_INT1_IMPL_DEF;
|
||||
|
||||
nval = hweight32(prop->source_ports);
|
||||
prop->src_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->src_dpn_prop),
|
||||
GFP_KERNEL);
|
||||
if (!prop->src_dpn_prop)
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
dpn = prop->src_dpn_prop;
|
||||
addr = prop->source_ports;
|
||||
for_each_set_bit(bit, &addr, 32) {
|
||||
dpn[i].num = bit;
|
||||
dpn[i].max_ch = 2;
|
||||
dpn[i].type = SDW_DPN_FULL;
|
||||
dpn[i].max_word = 24;
|
||||
i++;
|
||||
}
|
||||
/*
|
||||
* All ports are 2 channels max, except the first one,
|
||||
* CS42L43_DMIC_DEC_ASP_PORT.
|
||||
*/
|
||||
dpn[CS42L43_DMIC_DEC_ASP_PORT].max_ch = 4;
|
||||
|
||||
nval = hweight32(prop->sink_ports);
|
||||
prop->sink_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->sink_dpn_prop),
|
||||
GFP_KERNEL);
|
||||
if (!prop->sink_dpn_prop)
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
dpn = prop->sink_dpn_prop;
|
||||
addr = prop->sink_ports;
|
||||
for_each_set_bit(bit, &addr, 32) {
|
||||
dpn[i].num = bit;
|
||||
dpn[i].max_ch = 2;
|
||||
dpn[i].type = SDW_DPN_FULL;
|
||||
dpn[i].max_word = 24;
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_sdw_update_status(struct sdw_slave *sdw, enum sdw_slave_status status)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev);
|
||||
|
||||
switch (status) {
|
||||
case SDW_SLAVE_ATTACHED:
|
||||
dev_dbg(cs42l43->dev, "Device attach\n");
|
||||
|
||||
sdw_write_no_pm(sdw, CS42L43_GEN_INT_MASK_1,
|
||||
CS42L43_INT_STAT_GEN1_MASK);
|
||||
|
||||
cs42l43->attached = true;
|
||||
|
||||
complete(&cs42l43->device_attach);
|
||||
break;
|
||||
case SDW_SLAVE_UNATTACHED:
|
||||
dev_dbg(cs42l43->dev, "Device detach\n");
|
||||
|
||||
cs42l43->attached = false;
|
||||
|
||||
reinit_completion(&cs42l43->device_attach);
|
||||
complete(&cs42l43->device_detach);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_sdw_interrupt(struct sdw_slave *sdw,
|
||||
struct sdw_slave_intr_status *status)
|
||||
{
|
||||
/*
|
||||
* The IRQ itself was handled through the regmap_irq handler, this is
|
||||
* just clearing up the additional Cirrus SoundWire registers that are
|
||||
* not covered by the SoundWire framework or the IRQ handler itself.
|
||||
* There is only a single bit in GEN_INT_STAT_1 and it doesn't clear if
|
||||
* IRQs are still pending so doing a read/write here after handling the
|
||||
* IRQ is fine.
|
||||
*/
|
||||
sdw_read_no_pm(sdw, CS42L43_GEN_INT_STAT_1);
|
||||
sdw_write_no_pm(sdw, CS42L43_GEN_INT_STAT_1, CS42L43_INT_STAT_GEN1_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_sdw_bus_config(struct sdw_slave *sdw,
|
||||
struct sdw_bus_params *params)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&cs42l43->pll_lock);
|
||||
|
||||
if (cs42l43->sdw_freq != params->curr_dr_freq / 2) {
|
||||
if (cs42l43->sdw_pll_active) {
|
||||
dev_err(cs42l43->dev,
|
||||
"PLL active can't change SoundWire bus clock\n");
|
||||
ret = -EBUSY;
|
||||
} else {
|
||||
cs42l43->sdw_freq = params->curr_dr_freq / 2;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&cs42l43->pll_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct sdw_slave_ops cs42l43_sdw_ops = {
|
||||
.read_prop = cs42l43_read_prop,
|
||||
.update_status = cs42l43_sdw_update_status,
|
||||
.interrupt_callback = cs42l43_sdw_interrupt,
|
||||
.bus_config = cs42l43_sdw_bus_config,
|
||||
};
|
||||
|
||||
static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id)
|
||||
{
|
||||
struct cs42l43 *cs42l43;
|
||||
struct device *dev = &sdw->dev;
|
||||
int ret;
|
||||
|
||||
cs42l43 = devm_kzalloc(dev, sizeof(*cs42l43), GFP_KERNEL);
|
||||
if (!cs42l43)
|
||||
return -ENOMEM;
|
||||
|
||||
cs42l43->dev = dev;
|
||||
cs42l43->sdw = sdw;
|
||||
|
||||
cs42l43->regmap = devm_regmap_init_sdw(sdw, &cs42l43_sdw_regmap);
|
||||
if (IS_ERR(cs42l43->regmap)) {
|
||||
ret = PTR_ERR(cs42l43->regmap);
|
||||
dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return cs42l43_dev_probe(cs42l43);
|
||||
}
|
||||
|
||||
static int cs42l43_sdw_remove(struct sdw_slave *sdw)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev);
|
||||
|
||||
cs42l43_dev_remove(cs42l43);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sdw_device_id cs42l43_sdw_id[] = {
|
||||
SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0),
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(sdw, cs42l43_sdw_id);
|
||||
|
||||
static struct sdw_driver cs42l43_sdw_driver = {
|
||||
.driver = {
|
||||
.name = "cs42l43",
|
||||
.pm = pm_ptr(&cs42l43_pm_ops),
|
||||
},
|
||||
|
||||
.probe = cs42l43_sdw_probe,
|
||||
.remove = cs42l43_sdw_remove,
|
||||
.id_table = cs42l43_sdw_id,
|
||||
.ops = &cs42l43_sdw_ops,
|
||||
};
|
||||
module_sdw_driver(cs42l43_sdw_driver);
|
||||
|
||||
MODULE_IMPORT_NS(MFD_CS42L43);
|
||||
|
||||
MODULE_DESCRIPTION("CS42L43 SoundWire Driver");
|
||||
MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
|
||||
MODULE_LICENSE("GPL");
|
1188
drivers/mfd/cs42l43.c
Normal file
1188
drivers/mfd/cs42l43.c
Normal file
File diff suppressed because it is too large
Load Diff
28
drivers/mfd/cs42l43.h
Normal file
28
drivers/mfd/cs42l43.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* CS42L43 core driver internal data
|
||||
*
|
||||
* Copyright (C) 2022-2023 Cirrus Logic, Inc. and
|
||||
* Cirrus Logic International Semiconductor Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/mfd/cs42l43.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#ifndef CS42L43_CORE_INT_H
|
||||
#define CS42L43_CORE_INT_H
|
||||
|
||||
#define CS42L43_N_DEFAULTS 176
|
||||
|
||||
extern const struct dev_pm_ops cs42l43_pm_ops;
|
||||
extern const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS];
|
||||
|
||||
bool cs42l43_readable_register(struct device *dev, unsigned int reg);
|
||||
bool cs42l43_precious_register(struct device *dev, unsigned int reg);
|
||||
bool cs42l43_volatile_register(struct device *dev, unsigned int reg);
|
||||
|
||||
int cs42l43_dev_probe(struct cs42l43 *cs42l43);
|
||||
void cs42l43_dev_remove(struct cs42l43 *cs42l43);
|
||||
|
||||
#endif /* CS42L43_CORE_INT_H */
|
@ -1,4 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config PINCTRL_CS42L43
|
||||
tristate "Cirrus Logic CS42L43 Pinctrl Driver"
|
||||
depends on MFD_CS42L43
|
||||
select GPIOLIB
|
||||
select PINMUX
|
||||
select PINCONF
|
||||
select GENERIC_PINCONF
|
||||
help
|
||||
Select this to support the GPIO/Pinctrl functions of the Cirrus
|
||||
Logic CS42L43 PC CODEC.
|
||||
|
||||
config PINCTRL_LOCHNAGAR
|
||||
tristate "Cirrus Logic Lochnagar pinctrl driver"
|
||||
depends on MFD_LOCHNAGAR
|
||||
|
@ -1,5 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Cirrus Logic pinctrl drivers
|
||||
obj-$(CONFIG_PINCTRL_CS42L43) += pinctrl-cs42l43.o
|
||||
|
||||
obj-$(CONFIG_PINCTRL_LOCHNAGAR) += pinctrl-lochnagar.o
|
||||
|
||||
pinctrl-madera-objs := pinctrl-madera-core.o
|
||||
|
609
drivers/pinctrl/cirrus/pinctrl-cs42l43.c
Normal file
609
drivers/pinctrl/cirrus/pinctrl-cs42l43.c
Normal file
@ -0,0 +1,609 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// CS42L43 Pinctrl and GPIO driver
|
||||
//
|
||||
// Copyright (c) 2023 Cirrus Logic, Inc. and
|
||||
// Cirrus Logic International Semiconductor Ltd.
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/build_bug.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mfd/cs42l43.h>
|
||||
#include <linux/mfd/cs42l43-regs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/string_helpers.h>
|
||||
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
|
||||
#include "../pinctrl-utils.h"
|
||||
|
||||
#define CS42L43_NUM_GPIOS 3
|
||||
|
||||
struct cs42l43_pin {
|
||||
struct gpio_chip gpio_chip;
|
||||
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
bool shutters_locked;
|
||||
};
|
||||
|
||||
struct cs42l43_pin_data {
|
||||
unsigned int reg;
|
||||
unsigned int shift;
|
||||
unsigned int mask;
|
||||
};
|
||||
|
||||
#define CS42L43_PIN(_number, _name, _reg, _field) { \
|
||||
.number = _number, .name = _name, \
|
||||
.drv_data = &((struct cs42l43_pin_data){ \
|
||||
.reg = CS42L43_##_reg, \
|
||||
.shift = CS42L43_##_field##_DRV_SHIFT, \
|
||||
.mask = CS42L43_##_field##_DRV_MASK, \
|
||||
}), \
|
||||
}
|
||||
|
||||
static const struct pinctrl_pin_desc cs42l43_pin_pins[] = {
|
||||
CS42L43_PIN(0, "gpio1", DRV_CTRL4, GPIO1),
|
||||
CS42L43_PIN(1, "gpio2", DRV_CTRL4, GPIO2),
|
||||
CS42L43_PIN(2, "gpio3", DRV_CTRL4, GPIO3),
|
||||
CS42L43_PIN(3, "asp_dout", DRV_CTRL1, ASP_DOUT),
|
||||
CS42L43_PIN(4, "asp_fsync", DRV_CTRL1, ASP_FSYNC),
|
||||
CS42L43_PIN(5, "asp_bclk", DRV_CTRL1, ASP_BCLK),
|
||||
CS42L43_PIN(6, "pdmout2_clk", DRV_CTRL3, PDMOUT2_CLK),
|
||||
CS42L43_PIN(7, "pdmout2_data", DRV_CTRL3, PDMOUT2_DATA),
|
||||
CS42L43_PIN(8, "pdmout1_clk", DRV_CTRL3, PDMOUT1_CLK),
|
||||
CS42L43_PIN(9, "pdmout1_data", DRV_CTRL3, PDMOUT1_DATA),
|
||||
CS42L43_PIN(10, "i2c_sda", DRV_CTRL3, I2C_SDA),
|
||||
CS42L43_PIN(11, "i2c_scl", DRV_CTRL_5, I2C_SCL),
|
||||
CS42L43_PIN(12, "spi_miso", DRV_CTRL3, SPI_MISO),
|
||||
CS42L43_PIN(13, "spi_sck", DRV_CTRL_5, SPI_SCK),
|
||||
CS42L43_PIN(14, "spi_ssb", DRV_CTRL_5, SPI_SSB),
|
||||
};
|
||||
|
||||
static const unsigned int cs42l43_pin_gpio1_pins[] = { 0 };
|
||||
static const unsigned int cs42l43_pin_gpio2_pins[] = { 1 };
|
||||
static const unsigned int cs42l43_pin_gpio3_pins[] = { 2 };
|
||||
static const unsigned int cs42l43_pin_asp_pins[] = { 3, 4, 5 };
|
||||
static const unsigned int cs42l43_pin_pdmout2_pins[] = { 6, 7 };
|
||||
static const unsigned int cs42l43_pin_pdmout1_pins[] = { 8, 9 };
|
||||
static const unsigned int cs42l43_pin_i2c_pins[] = { 10, 11 };
|
||||
static const unsigned int cs42l43_pin_spi_pins[] = { 12, 13, 14 };
|
||||
|
||||
#define CS42L43_PINGROUP(_name) \
|
||||
PINCTRL_PINGROUP(#_name, cs42l43_pin_##_name##_pins, \
|
||||
ARRAY_SIZE(cs42l43_pin_##_name##_pins))
|
||||
|
||||
static const struct pingroup cs42l43_pin_groups[] = {
|
||||
CS42L43_PINGROUP(gpio1),
|
||||
CS42L43_PINGROUP(gpio2),
|
||||
CS42L43_PINGROUP(gpio3),
|
||||
CS42L43_PINGROUP(asp),
|
||||
CS42L43_PINGROUP(pdmout2),
|
||||
CS42L43_PINGROUP(pdmout1),
|
||||
CS42L43_PINGROUP(i2c),
|
||||
CS42L43_PINGROUP(spi),
|
||||
};
|
||||
|
||||
static int cs42l43_pin_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
return ARRAY_SIZE(cs42l43_pin_groups);
|
||||
}
|
||||
|
||||
static const char *cs42l43_pin_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned int group_idx)
|
||||
{
|
||||
return cs42l43_pin_groups[group_idx].name;
|
||||
}
|
||||
|
||||
static int cs42l43_pin_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
unsigned int group_idx,
|
||||
const unsigned int **pins,
|
||||
unsigned int *num_pins)
|
||||
{
|
||||
*pins = cs42l43_pin_groups[group_idx].pins;
|
||||
*num_pins = cs42l43_pin_groups[group_idx].npins;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pinctrl_ops cs42l43_pin_group_ops = {
|
||||
.get_groups_count = cs42l43_pin_get_groups_count,
|
||||
.get_group_name = cs42l43_pin_get_group_name,
|
||||
.get_group_pins = cs42l43_pin_get_group_pins,
|
||||
#if IS_ENABLED(CONFIG_OF)
|
||||
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
||||
.dt_free_map = pinconf_generic_dt_free_map,
|
||||
#endif
|
||||
};
|
||||
|
||||
enum cs42l43_pin_funcs {
|
||||
CS42L43_FUNC_GPIO,
|
||||
CS42L43_FUNC_SPDIF,
|
||||
CS42L43_FUNC_IRQ,
|
||||
CS42L43_FUNC_MIC_SHT,
|
||||
CS42L43_FUNC_SPK_SHT,
|
||||
CS42L43_FUNC_MAX
|
||||
};
|
||||
|
||||
static const char * const cs42l43_pin_funcs[] = {
|
||||
"gpio", "spdif", "irq", "mic-shutter", "spk-shutter",
|
||||
};
|
||||
|
||||
static const char * const cs42l43_pin_gpio_groups[] = { "gpio1", "gpio3" };
|
||||
static const char * const cs42l43_pin_spdif_groups[] = { "gpio3" };
|
||||
static const char * const cs42l43_pin_irq_groups[] = { "gpio1" };
|
||||
static const char * const cs42l43_pin_shutter_groups[] = { "gpio1", "gpio2", "gpio3" };
|
||||
|
||||
static const struct pinfunction cs42l43_pin_func_groups[] = {
|
||||
PINCTRL_PINFUNCTION("gpio", cs42l43_pin_gpio_groups,
|
||||
ARRAY_SIZE(cs42l43_pin_gpio_groups)),
|
||||
PINCTRL_PINFUNCTION("spdif", cs42l43_pin_spdif_groups,
|
||||
ARRAY_SIZE(cs42l43_pin_spdif_groups)),
|
||||
PINCTRL_PINFUNCTION("irq", cs42l43_pin_irq_groups,
|
||||
ARRAY_SIZE(cs42l43_pin_irq_groups)),
|
||||
PINCTRL_PINFUNCTION("mic-shutter", cs42l43_pin_shutter_groups,
|
||||
ARRAY_SIZE(cs42l43_pin_shutter_groups)),
|
||||
PINCTRL_PINFUNCTION("spk-shutter", cs42l43_pin_shutter_groups,
|
||||
ARRAY_SIZE(cs42l43_pin_shutter_groups)),
|
||||
};
|
||||
|
||||
static_assert(ARRAY_SIZE(cs42l43_pin_funcs) == CS42L43_FUNC_MAX);
|
||||
static_assert(ARRAY_SIZE(cs42l43_pin_func_groups) == CS42L43_FUNC_MAX);
|
||||
|
||||
static int cs42l43_pin_get_func_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
return ARRAY_SIZE(cs42l43_pin_funcs);
|
||||
}
|
||||
|
||||
static const char *cs42l43_pin_get_func_name(struct pinctrl_dev *pctldev,
|
||||
unsigned int func_idx)
|
||||
{
|
||||
return cs42l43_pin_funcs[func_idx];
|
||||
}
|
||||
|
||||
static int cs42l43_pin_get_func_groups(struct pinctrl_dev *pctldev,
|
||||
unsigned int func_idx,
|
||||
const char * const **groups,
|
||||
unsigned int * const num_groups)
|
||||
{
|
||||
*groups = cs42l43_pin_func_groups[func_idx].groups;
|
||||
*num_groups = cs42l43_pin_func_groups[func_idx].ngroups;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_pin_set_mux(struct pinctrl_dev *pctldev,
|
||||
unsigned int func_idx, unsigned int group_idx)
|
||||
{
|
||||
struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev);
|
||||
unsigned int reg, mask, val;
|
||||
|
||||
dev_dbg(priv->dev, "Setting %s to %s\n",
|
||||
cs42l43_pin_groups[group_idx].name, cs42l43_pin_funcs[func_idx]);
|
||||
|
||||
switch (func_idx) {
|
||||
case CS42L43_FUNC_MIC_SHT:
|
||||
reg = CS42L43_SHUTTER_CONTROL;
|
||||
mask = CS42L43_MIC_SHUTTER_CFG_MASK;
|
||||
val = 0x2 << (group_idx + CS42L43_MIC_SHUTTER_CFG_SHIFT);
|
||||
break;
|
||||
case CS42L43_FUNC_SPK_SHT:
|
||||
reg = CS42L43_SHUTTER_CONTROL;
|
||||
mask = CS42L43_SPK_SHUTTER_CFG_MASK;
|
||||
val = 0x2 << (group_idx + CS42L43_SPK_SHUTTER_CFG_SHIFT);
|
||||
break;
|
||||
default:
|
||||
reg = CS42L43_GPIO_FN_SEL;
|
||||
mask = BIT(group_idx + CS42L43_GPIO1_FN_SEL_SHIFT);
|
||||
val = (func_idx == CS42L43_FUNC_GPIO) ?
|
||||
(0x1 << (group_idx + CS42L43_GPIO1_FN_SEL_SHIFT)) : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (priv->shutters_locked && reg == CS42L43_SHUTTER_CONTROL) {
|
||||
dev_err(priv->dev, "Shutter configuration not available\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return regmap_update_bits(priv->regmap, reg, mask, val);
|
||||
}
|
||||
|
||||
static int cs42l43_gpio_set_direction(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range,
|
||||
unsigned int offset, bool input)
|
||||
{
|
||||
struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev);
|
||||
unsigned int shift = offset + CS42L43_GPIO1_DIR_SHIFT;
|
||||
int ret;
|
||||
|
||||
dev_dbg(priv->dev, "Setting gpio%d to %s\n",
|
||||
offset + 1, input ? "input" : "output");
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->dev);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Failed to resume for direction: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL1,
|
||||
BIT(shift), !!input << shift);
|
||||
if (ret)
|
||||
dev_err(priv->dev, "Failed to set gpio%d direction: %d\n",
|
||||
offset + 1, ret);
|
||||
|
||||
pm_runtime_put(priv->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs42l43_gpio_request_enable(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range,
|
||||
unsigned int offset)
|
||||
{
|
||||
return cs42l43_pin_set_mux(pctldev, 0, offset);
|
||||
}
|
||||
|
||||
static void cs42l43_gpio_disable_free(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_gpio_range *range,
|
||||
unsigned int offset)
|
||||
{
|
||||
cs42l43_gpio_set_direction(pctldev, range, offset, true);
|
||||
}
|
||||
|
||||
static const struct pinmux_ops cs42l43_pin_mux_ops = {
|
||||
.get_functions_count = cs42l43_pin_get_func_count,
|
||||
.get_function_name = cs42l43_pin_get_func_name,
|
||||
.get_function_groups = cs42l43_pin_get_func_groups,
|
||||
|
||||
.set_mux = cs42l43_pin_set_mux,
|
||||
|
||||
.gpio_request_enable = cs42l43_gpio_request_enable,
|
||||
.gpio_disable_free = cs42l43_gpio_disable_free,
|
||||
.gpio_set_direction = cs42l43_gpio_set_direction,
|
||||
|
||||
.strict = true,
|
||||
};
|
||||
|
||||
static const unsigned int cs42l43_pin_drv_str_ma[] = { 1, 2, 4, 8, 9, 10, 12, 16 };
|
||||
|
||||
static inline int cs42l43_pin_get_drv_str(struct cs42l43_pin *priv, unsigned int pin)
|
||||
{
|
||||
const struct cs42l43_pin_data *pdat = cs42l43_pin_pins[pin].drv_data;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(priv->regmap, pdat->reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return cs42l43_pin_drv_str_ma[(val & pdat->mask) >> pdat->shift];
|
||||
}
|
||||
|
||||
static inline int cs42l43_pin_set_drv_str(struct cs42l43_pin *priv, unsigned int pin,
|
||||
unsigned int ma)
|
||||
{
|
||||
const struct cs42l43_pin_data *pdat = cs42l43_pin_pins[pin].drv_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cs42l43_pin_drv_str_ma); i++) {
|
||||
if (ma == cs42l43_pin_drv_str_ma[i]) {
|
||||
if ((i << pdat->shift) > pdat->mask)
|
||||
goto err;
|
||||
|
||||
dev_dbg(priv->dev, "Set drive strength for %s to %d mA\n",
|
||||
cs42l43_pin_pins[pin].name, ma);
|
||||
|
||||
return regmap_update_bits(priv->regmap, pdat->reg,
|
||||
pdat->mask, i << pdat->shift);
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
dev_err(priv->dev, "Invalid drive strength for %s: %d mA\n",
|
||||
cs42l43_pin_pins[pin].name, ma);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int cs42l43_pin_get_db(struct cs42l43_pin *priv, unsigned int pin)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
if (pin >= CS42L43_NUM_GPIOS)
|
||||
return -ENOTSUPP;
|
||||
|
||||
ret = regmap_read(priv->regmap, CS42L43_GPIO_CTRL2, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val & (CS42L43_GPIO1_DEGLITCH_BYP_MASK << pin))
|
||||
return 0;
|
||||
|
||||
return 85; // Debounce is roughly 85uS
|
||||
}
|
||||
|
||||
static inline int cs42l43_pin_set_db(struct cs42l43_pin *priv, unsigned int pin,
|
||||
unsigned int us)
|
||||
{
|
||||
if (pin >= CS42L43_NUM_GPIOS)
|
||||
return -ENOTSUPP;
|
||||
|
||||
dev_dbg(priv->dev, "Set debounce %s for %s\n",
|
||||
str_on_off(us), cs42l43_pin_pins[pin].name);
|
||||
|
||||
return regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL2,
|
||||
CS42L43_GPIO1_DEGLITCH_BYP_MASK << pin,
|
||||
!!us << pin);
|
||||
}
|
||||
|
||||
static int cs42l43_pin_config_get(struct pinctrl_dev *pctldev,
|
||||
unsigned int pin, unsigned long *config)
|
||||
{
|
||||
struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev);
|
||||
unsigned int param = pinconf_to_config_param(*config);
|
||||
int ret;
|
||||
|
||||
switch (param) {
|
||||
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||
ret = cs42l43_pin_get_drv_str(priv, pin);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||
ret = cs42l43_pin_get_db(priv, pin);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
*config = pinconf_to_config_packed(param, ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
||||
unsigned long *configs, unsigned int num_configs)
|
||||
{
|
||||
struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
while (num_configs) {
|
||||
val = pinconf_to_config_argument(*configs);
|
||||
|
||||
switch (pinconf_to_config_param(*configs)) {
|
||||
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||
ret = cs42l43_pin_set_drv_str(priv, pin, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||
ret = cs42l43_pin_set_db(priv, pin, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
configs++;
|
||||
num_configs--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_pin_config_group_get(struct pinctrl_dev *pctldev,
|
||||
unsigned int selector, unsigned long *config)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < cs42l43_pin_groups[selector].npins; ++i) {
|
||||
ret = cs42l43_pin_config_get(pctldev,
|
||||
cs42l43_pin_groups[selector].pins[i],
|
||||
config);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l43_pin_config_group_set(struct pinctrl_dev *pctldev,
|
||||
unsigned int selector,
|
||||
unsigned long *configs,
|
||||
unsigned int num_configs)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < cs42l43_pin_groups[selector].npins; ++i) {
|
||||
ret = cs42l43_pin_config_set(pctldev,
|
||||
cs42l43_pin_groups[selector].pins[i],
|
||||
configs, num_configs);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pinconf_ops cs42l43_pin_conf_ops = {
|
||||
.is_generic = true,
|
||||
|
||||
.pin_config_get = cs42l43_pin_config_get,
|
||||
.pin_config_set = cs42l43_pin_config_set,
|
||||
.pin_config_group_get = cs42l43_pin_config_group_get,
|
||||
.pin_config_group_set = cs42l43_pin_config_group_set,
|
||||
};
|
||||
|
||||
static struct pinctrl_desc cs42l43_pin_desc = {
|
||||
.name = "cs42l43-pinctrl",
|
||||
.owner = THIS_MODULE,
|
||||
|
||||
.pins = cs42l43_pin_pins,
|
||||
.npins = ARRAY_SIZE(cs42l43_pin_pins),
|
||||
|
||||
.pctlops = &cs42l43_pin_group_ops,
|
||||
.pmxops = &cs42l43_pin_mux_ops,
|
||||
.confops = &cs42l43_pin_conf_ops,
|
||||
};
|
||||
|
||||
static int cs42l43_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct cs42l43_pin *priv = gpiochip_get_data(chip);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->dev);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Failed to resume for get: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(priv->regmap, CS42L43_GPIO_STS, &val);
|
||||
if (ret)
|
||||
dev_err(priv->dev, "Failed to get gpio%d: %d\n", offset + 1, ret);
|
||||
else
|
||||
ret = !!(val & BIT(offset + CS42L43_GPIO1_STS_SHIFT));
|
||||
|
||||
pm_runtime_put(priv->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cs42l43_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct cs42l43_pin *priv = gpiochip_get_data(chip);
|
||||
unsigned int shift = offset + CS42L43_GPIO1_LVL_SHIFT;
|
||||
int ret;
|
||||
|
||||
dev_dbg(priv->dev, "Setting gpio%d to %s\n",
|
||||
offset + 1, value ? "high" : "low");
|
||||
|
||||
ret = pm_runtime_resume_and_get(priv->dev);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Failed to resume for set: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL1,
|
||||
BIT(shift), value << shift);
|
||||
if (ret)
|
||||
dev_err(priv->dev, "Failed to set gpio%d: %d\n", offset + 1, ret);
|
||||
|
||||
pm_runtime_put(priv->dev);
|
||||
}
|
||||
|
||||
static int cs42l43_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return pinctrl_gpio_direction_input(chip->base + offset);
|
||||
}
|
||||
|
||||
static int cs42l43_gpio_direction_out(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
cs42l43_gpio_set(chip, offset, value);
|
||||
|
||||
return pinctrl_gpio_direction_output(chip->base + offset);
|
||||
}
|
||||
|
||||
static int cs42l43_gpio_add_pin_ranges(struct gpio_chip *chip)
|
||||
{
|
||||
struct cs42l43_pin *priv = gpiochip_get_data(chip);
|
||||
int ret;
|
||||
|
||||
ret = gpiochip_add_pin_range(&priv->gpio_chip, priv->gpio_chip.label,
|
||||
0, 0, CS42L43_NUM_GPIOS);
|
||||
if (ret)
|
||||
dev_err(priv->dev, "Failed to add GPIO pin range: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cs42l43_pin_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct cs42l43_pin *priv;
|
||||
struct pinctrl_dev *pctldev;
|
||||
struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev);
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
priv->regmap = cs42l43->regmap;
|
||||
|
||||
priv->shutters_locked = cs42l43->hw_lock;
|
||||
|
||||
priv->gpio_chip.request = gpiochip_generic_request;
|
||||
priv->gpio_chip.free = gpiochip_generic_free;
|
||||
priv->gpio_chip.direction_input = cs42l43_gpio_direction_in;
|
||||
priv->gpio_chip.direction_output = cs42l43_gpio_direction_out;
|
||||
priv->gpio_chip.add_pin_ranges = cs42l43_gpio_add_pin_ranges;
|
||||
priv->gpio_chip.get = cs42l43_gpio_get;
|
||||
priv->gpio_chip.set = cs42l43_gpio_set;
|
||||
priv->gpio_chip.label = dev_name(priv->dev);
|
||||
priv->gpio_chip.parent = priv->dev;
|
||||
priv->gpio_chip.can_sleep = true;
|
||||
priv->gpio_chip.base = -1;
|
||||
priv->gpio_chip.ngpio = CS42L43_NUM_GPIOS;
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
fwnode = fwnode_get_named_child_node(fwnode, "pinctrl");
|
||||
|
||||
if (fwnode && !fwnode->dev)
|
||||
fwnode->dev = priv->dev;
|
||||
}
|
||||
|
||||
priv->gpio_chip.fwnode = fwnode;
|
||||
|
||||
device_set_node(priv->dev, fwnode);
|
||||
|
||||
devm_pm_runtime_enable(priv->dev);
|
||||
pm_runtime_idle(priv->dev);
|
||||
|
||||
pctldev = devm_pinctrl_register(priv->dev, &cs42l43_pin_desc, priv);
|
||||
if (IS_ERR(pctldev))
|
||||
return dev_err_probe(priv->dev, PTR_ERR(pctldev),
|
||||
"Failed to register pinctrl\n");
|
||||
|
||||
ret = devm_gpiochip_add_data(priv->dev, &priv->gpio_chip, priv);
|
||||
if (ret)
|
||||
return dev_err_probe(priv->dev, ret,
|
||||
"Failed to register gpiochip\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id cs42l43_pin_id_table[] = {
|
||||
{ "cs42l43-pinctrl", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, cs42l43_pin_id_table);
|
||||
|
||||
static struct platform_driver cs42l43_pin_driver = {
|
||||
.driver = {
|
||||
.name = "cs42l43-pinctrl",
|
||||
},
|
||||
.probe = cs42l43_pin_probe,
|
||||
.id_table = cs42l43_pin_id_table,
|
||||
};
|
||||
module_platform_driver(cs42l43_pin_driver);
|
||||
|
||||
MODULE_DESCRIPTION("CS42L43 Pinctrl Driver");
|
||||
MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/soundwire/sdw_registers.h>
|
||||
@ -25,6 +26,23 @@ static int sdw_get_id(struct sdw_bus *bus)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdw_irq_map(struct irq_domain *h, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
struct sdw_bus *bus = h->host_data;
|
||||
|
||||
irq_set_chip_data(virq, bus);
|
||||
irq_set_chip(virq, &bus->irq_chip);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
irq_set_noprobe(virq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops sdw_domain_ops = {
|
||||
.map = sdw_irq_map,
|
||||
};
|
||||
|
||||
/**
|
||||
* sdw_bus_master_add() - add a bus Master instance
|
||||
* @bus: bus instance
|
||||
@ -151,6 +169,14 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
|
||||
bus->params.curr_bank = SDW_BANK0;
|
||||
bus->params.next_bank = SDW_BANK1;
|
||||
|
||||
bus->irq_chip.name = dev_name(bus->dev);
|
||||
bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES,
|
||||
&sdw_domain_ops, bus);
|
||||
if (!bus->domain) {
|
||||
dev_err(bus->dev, "Failed to add IRQ domain\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(sdw_bus_master_add);
|
||||
@ -187,6 +213,9 @@ static int sdw_delete_slave(struct device *dev, void *data)
|
||||
void sdw_bus_master_delete(struct sdw_bus *bus)
|
||||
{
|
||||
device_for_each_child(bus->dev, NULL, sdw_delete_slave);
|
||||
|
||||
irq_domain_remove(bus->domain);
|
||||
|
||||
sdw_master_device_del(bus);
|
||||
|
||||
sdw_bus_debugfs_exit(bus);
|
||||
@ -1725,6 +1754,9 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
|
||||
struct device *dev = &slave->dev;
|
||||
struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
|
||||
|
||||
if (slave->prop.use_domain_irq && slave->irq)
|
||||
handle_nested_irq(slave->irq);
|
||||
|
||||
if (drv->ops && drv->ops->interrupt_callback) {
|
||||
slave_intr.sdca_cascade = sdca_cascade;
|
||||
slave_intr.control_port = clear;
|
||||
|
@ -122,6 +122,12 @@ static int sdw_drv_probe(struct device *dev)
|
||||
if (drv->ops && drv->ops->read_prop)
|
||||
drv->ops->read_prop(slave);
|
||||
|
||||
if (slave->prop.use_domain_irq) {
|
||||
slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num);
|
||||
if (!slave->irq)
|
||||
dev_warn(dev, "Failed to map IRQ\n");
|
||||
}
|
||||
|
||||
/* init the sysfs as we have properties now */
|
||||
ret = sdw_slave_sysfs_init(slave);
|
||||
if (ret < 0)
|
||||
@ -166,7 +172,13 @@ static int sdw_drv_remove(struct device *dev)
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&slave->sdw_dev_lock);
|
||||
|
||||
slave->probed = false;
|
||||
|
||||
if (slave->prop.use_domain_irq)
|
||||
irq_dispose_mapping(irq_find_mapping(slave->bus->domain,
|
||||
slave->dev_num));
|
||||
|
||||
mutex_unlock(&slave->sdw_dev_lock);
|
||||
|
||||
if (drv->remove)
|
||||
|
1184
include/linux/mfd/cs42l43-regs.h
Normal file
1184
include/linux/mfd/cs42l43-regs.h
Normal file
File diff suppressed because it is too large
Load Diff
102
include/linux/mfd/cs42l43.h
Normal file
102
include/linux/mfd/cs42l43.h
Normal file
@ -0,0 +1,102 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* CS42L43 core driver external data
|
||||
*
|
||||
* Copyright (C) 2022-2023 Cirrus Logic, Inc. and
|
||||
* Cirrus Logic International Semiconductor Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#ifndef CS42L43_CORE_EXT_H
|
||||
#define CS42L43_CORE_EXT_H
|
||||
|
||||
#define CS42L43_N_SUPPLIES 3
|
||||
|
||||
enum cs42l43_irq_numbers {
|
||||
CS42L43_PLL_LOST_LOCK,
|
||||
CS42L43_PLL_READY,
|
||||
|
||||
CS42L43_HP_STARTUP_DONE,
|
||||
CS42L43_HP_SHUTDOWN_DONE,
|
||||
CS42L43_HSDET_DONE,
|
||||
CS42L43_TIPSENSE_UNPLUG_DB,
|
||||
CS42L43_TIPSENSE_PLUG_DB,
|
||||
CS42L43_RINGSENSE_UNPLUG_DB,
|
||||
CS42L43_RINGSENSE_PLUG_DB,
|
||||
CS42L43_TIPSENSE_UNPLUG_PDET,
|
||||
CS42L43_TIPSENSE_PLUG_PDET,
|
||||
CS42L43_RINGSENSE_UNPLUG_PDET,
|
||||
CS42L43_RINGSENSE_PLUG_PDET,
|
||||
|
||||
CS42L43_HS2_BIAS_SENSE,
|
||||
CS42L43_HS1_BIAS_SENSE,
|
||||
CS42L43_DC_DETECT1_FALSE,
|
||||
CS42L43_DC_DETECT1_TRUE,
|
||||
CS42L43_HSBIAS_CLAMPED,
|
||||
CS42L43_HS3_4_BIAS_SENSE,
|
||||
|
||||
CS42L43_AMP2_CLK_STOP_FAULT,
|
||||
CS42L43_AMP1_CLK_STOP_FAULT,
|
||||
CS42L43_AMP2_VDDSPK_FAULT,
|
||||
CS42L43_AMP1_VDDSPK_FAULT,
|
||||
CS42L43_AMP2_SHUTDOWN_DONE,
|
||||
CS42L43_AMP1_SHUTDOWN_DONE,
|
||||
CS42L43_AMP2_STARTUP_DONE,
|
||||
CS42L43_AMP1_STARTUP_DONE,
|
||||
CS42L43_AMP2_THERM_SHDN,
|
||||
CS42L43_AMP1_THERM_SHDN,
|
||||
CS42L43_AMP2_THERM_WARN,
|
||||
CS42L43_AMP1_THERM_WARN,
|
||||
CS42L43_AMP2_SCDET,
|
||||
CS42L43_AMP1_SCDET,
|
||||
|
||||
CS42L43_GPIO3_FALL,
|
||||
CS42L43_GPIO3_RISE,
|
||||
CS42L43_GPIO2_FALL,
|
||||
CS42L43_GPIO2_RISE,
|
||||
CS42L43_GPIO1_FALL,
|
||||
CS42L43_GPIO1_RISE,
|
||||
|
||||
CS42L43_HP_ILIMIT,
|
||||
CS42L43_HP_LOADDET_DONE,
|
||||
};
|
||||
|
||||
struct cs42l43 {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct sdw_slave *sdw;
|
||||
|
||||
struct regulator *vdd_p;
|
||||
struct regulator *vdd_d;
|
||||
struct regulator_bulk_data core_supplies[CS42L43_N_SUPPLIES];
|
||||
|
||||
struct gpio_desc *reset;
|
||||
|
||||
int irq;
|
||||
struct regmap_irq_chip irq_chip;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
|
||||
struct work_struct boot_work;
|
||||
struct completion device_attach;
|
||||
struct completion device_detach;
|
||||
struct completion firmware_download;
|
||||
int firmware_error;
|
||||
|
||||
unsigned int sdw_freq;
|
||||
/* Lock to gate control of the PLL and its sources. */
|
||||
struct mutex pll_lock;
|
||||
|
||||
bool sdw_pll_active;
|
||||
bool attached;
|
||||
bool hw_lock;
|
||||
};
|
||||
|
||||
#endif /* CS42L43_CORE_EXT_H */
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/lockdep_types.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
@ -370,6 +372,7 @@ struct sdw_dpn_prop {
|
||||
* @clock_reg_supported: the Peripheral implements the clock base and scale
|
||||
* registers introduced with the SoundWire 1.2 specification. SDCA devices
|
||||
* do not need to set this boolean property as the registers are required.
|
||||
* @use_domain_irq: call actual IRQ handler on slave, as well as callback
|
||||
*/
|
||||
struct sdw_slave_prop {
|
||||
u32 mipi_revision;
|
||||
@ -394,6 +397,7 @@ struct sdw_slave_prop {
|
||||
u8 scp_int1_mask;
|
||||
u32 quirks;
|
||||
bool clock_reg_supported;
|
||||
bool use_domain_irq;
|
||||
};
|
||||
|
||||
#define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0)
|
||||
@ -641,6 +645,7 @@ struct sdw_slave_ops {
|
||||
* struct sdw_slave - SoundWire Slave
|
||||
* @id: MIPI device ID
|
||||
* @dev: Linux device
|
||||
* @irq: IRQ number
|
||||
* @status: Status reported by the Slave
|
||||
* @bus: Bus handle
|
||||
* @prop: Slave properties
|
||||
@ -670,6 +675,7 @@ struct sdw_slave_ops {
|
||||
struct sdw_slave {
|
||||
struct sdw_slave_id id;
|
||||
struct device dev;
|
||||
int irq;
|
||||
enum sdw_slave_status status;
|
||||
struct sdw_bus *bus;
|
||||
struct sdw_slave_prop prop;
|
||||
@ -885,6 +891,7 @@ struct sdw_master_ops {
|
||||
* is used to compute and program bus bandwidth, clock, frame shape,
|
||||
* transport and port parameters
|
||||
* @debugfs: Bus debugfs
|
||||
* @domain: IRQ domain
|
||||
* @defer_msg: Defer message
|
||||
* @clk_stop_timeout: Clock stop timeout computed
|
||||
* @bank_switch_timeout: Bank switch timeout computed
|
||||
@ -920,6 +927,8 @@ struct sdw_bus {
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs;
|
||||
#endif
|
||||
struct irq_chip irq_chip;
|
||||
struct irq_domain *domain;
|
||||
struct sdw_defer defer_msg;
|
||||
unsigned int clk_stop_timeout;
|
||||
u32 bank_switch_timeout;
|
||||
|
Loading…
Reference in New Issue
Block a user