- interrupts : The interrupt line the /IRQ signal for the device is
connected to.
+ - pinctrl-names : Name of pinctrl configurations. Each of these is optional.
+ Legal names are:
+ "probe" - external pinctrl dependencies required to probe this codec,
+ typically these are for the reset GPIO and IRQ pin, though
+ could include clocks. Do NOT include configuration of this
+ codec's own GPIO pins because these can't be applied until
+ after the mfd probe has completed.
+
+ "active" - full set of external and local pinctrl configurations to
+ apply after probe including all the configuration of the GPIO
+ pins on this codec (bindings/pinctrl/cirrus,madera-pinctrl.txt).
+ This must include the external dependencies in the "probe"
+ configuration, since they will still be required after probe.
+
+ Do not use "default" since it is applied too early before the mfd has
+ fully probed the codec.
+
+ - pinctrl-0, pinctrl-1 : handle to pinctrl configurations matching the
+ entries in pinctrl-names
+
Optional properties:
- MICVDD-supply : Power supply, only need to be specified if
gpio-controller;
#gpio-cells = <2>;
+ pinctrl-names = "probe", "active";
+ pinctrl-0 = <&gpio_0_enable_state>;
+ pinctrl-1 = <&gpio_0_enable_state &cs47l85_gpio_config>;
+
+ cs47l85_gpio_config: cs47l85-gpio-config {
+ aif1 {
+ groups = "aif1";
+ function = "aif1";
+ bias-bus-hold;
+ };
+ };
+
MICBIAS1 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <3300000>;
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
{ .name = "madera-ldo1" },
};
+static const struct mfd_cell madera_pinctrl_dev[] = {
+ { .name = "madera-pinctrl", },
+};
+
static const char * const cs47l15_supplies[] = {
"MICVDD",
"CPVDD1",
};
static const struct mfd_cell cs47l15_devs[] = {
- { .name = "madera-pinctrl", },
{ .name = "madera-irq" },
{ .name = "madera-gpio" },
{
};
static const struct mfd_cell cs47l35_devs[] = {
- { .name = "madera-pinctrl", },
{ .name = "madera-irq", },
{ .name = "madera-micsupp" },
{ .name = "madera-gpio", },
};
static const struct mfd_cell cs47l85_devs[] = {
- { .name = "madera-pinctrl", },
{ .name = "madera-irq", },
{ .name = "madera-micsupp", },
{ .name = "madera-gpio", },
};
static const struct mfd_cell cs47l90_devs[] = {
- { .name = "madera-pinctrl", },
{ .name = "madera-irq", },
{ .name = "madera-micsupp", },
{ .name = "madera-gpio", },
};
static const struct mfd_cell cs47l92_devs[] = {
- { .name = "madera-pinctrl" },
{ .name = "madera-irq", },
{ .name = "madera-micsupp", },
{ .name = "madera-gpio" },
}
}
+static int madera_dev_select_pinctrl(struct madera *madera,
+ struct pinctrl *pinctrl,
+ const char *name)
+{
+ struct pinctrl_state *pinctrl_state;
+ int ret;
+
+ pinctrl_state = pinctrl_lookup_state(pinctrl, name);
+
+ /* it's ok if it doesn't exist */
+ if (!IS_ERR(pinctrl_state)) {
+ dev_dbg(madera->dev, "Applying pinctrl %s state\n", name);
+ ret = pinctrl_select_state(pinctrl, pinctrl_state);
+ if (ret) {
+ dev_err(madera->dev,
+ "Failed to select pinctrl %s state: %d\n",
+ name, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int madera_dev_init(struct madera *madera)
{
struct device *dev = madera->dev;
unsigned int hwid;
int (*patch_fn)(struct madera *) = NULL;
const struct mfd_cell *mfd_devs;
+ struct pinctrl *pinctrl;
int n_devs = 0;
int i, ret;
dev_set_drvdata(madera->dev, madera);
+
+ /*
+ * Pinctrl subsystem only configures pinctrls if all referenced pins
+ * are registered. Create our pinctrl child now so that its pins exist
+ * otherwise external pinctrl dependencies will fail
+ * Note: Can't devm_ because it is cleaned up after children are already
+ * destroyed
+ */
+ ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE,
+ madera_pinctrl_dev, 1, NULL, 0, NULL);
+ if (ret) {
+ dev_err(madera->dev, "Failed to add pinctrl child: %d\n", ret);
+ return ret;
+ }
+
+ pinctrl = pinctrl_get(dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ dev_err(madera->dev, "Failed to get pinctrl: %d\n", ret);
+ goto err_devs;
+ }
+
+ /* Use (optional) minimal config with only external pin bindings */
+ ret = madera_dev_select_pinctrl(madera, pinctrl, "probe");
+ if (ret)
+ goto err_pinctrl;
+
BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier);
if (dev_get_platdata(madera->dev)) {
ret = madera_get_reset_gpio(madera);
if (ret)
- return ret;
+ goto err_pinctrl;
madera_prop_get_micbias(madera);
NULL, 0, NULL);
if (ret) {
dev_err(dev, "Failed to add LDO1 child: %d\n", ret);
- return ret;
+ goto err_pinctrl;
}
break;
default:
dev_err(madera->dev, "Unknown device type %d\n", madera->type);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_pinctrl;
}
ret = devm_regulator_bulk_get(dev, madera->num_core_supplies,
madera->core_supplies);
if (ret) {
dev_err(dev, "Failed to request core supplies: %d\n", ret);
- goto err_devs;
+ goto err_pinctrl;
}
/*
if (IS_ERR(madera->dcvdd)) {
ret = PTR_ERR(madera->dcvdd);
dev_err(dev, "Failed to request DCVDD: %d\n", ret);
- goto err_devs;
+ goto err_pinctrl;
}
ret = regulator_bulk_enable(madera->num_core_supplies,
}
}
+ /* Apply (optional) main pinctrl config, this will configure our pins */
+ ret = madera_dev_select_pinctrl(madera, pinctrl, "active");
+ if (ret)
+ goto err_reset;
+
/* Init 32k clock sourced from MCLK2 */
ret = regmap_update_bits(madera->regmap,
MADERA_CLOCK_32K_1,
goto err_pm_runtime;
}
+ pinctrl_put(pinctrl);
+
return 0;
err_pm_runtime:
madera->core_supplies);
err_dcvdd:
regulator_put(madera->dcvdd);
+err_pinctrl:
+ pinctrl_put(pinctrl);
err_devs:
mfd_remove_devices(dev);