* [PATCH V5 5/8] regulator: da9061: BUCK and LDO regulator driver
From: Steve Twiss @ 2016-12-15 19:08 UTC (permalink / raw)
To: LINUX-KERNEL, Liam Girdwood, Mark Brown
Cc: DEVICETREE, Dmitry Torokhov, Eduardo Valentin, Guenter Roeck,
LINUX-INPUT, LINUX-PM, LINUX-WATCHDOG, Lee Jones, Mark Rutland,
Rob Herring, Support Opensource, Wim Van Sebroeck, Zhang Rui
In-Reply-To: <cover.1481828921.git.stwiss.opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
From: Steve Twiss <stwiss.opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
Regulator support for the DA9061 is added into the DA9062 regulator driver.
The regulators for DA9061 differ from those of DA9062.
A new DA9061 enumeration list for the LDOs and Bucks supported by this
device is added. Regulator information added: the old regulator
information for DA9062 is renamed from local_regulator_info[] to
local_da9062_regulator_info[] and a new array is added to support
local_da9061_regulator_info[].
The probe() function switches on the da9062_compatible_types enumeration
and configures the correct da9062_regulator_info array and number of
regulator entries.
Kconfig is updated to reflect support for DA9061 and DA9062 regulators.
Acked-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Steve Twiss <stwiss.opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
---
This patch applies against linux-next and v4.9
v4 -> v5
- Rebased from v4.8 to v4.9
- NO CODE CHANGE
v3 -> v4
- NO CODE CHANGE
- Patch renamed from [PATCH V3 6/9] to [PATCH V4 5/8]
v2 -> v3
- NO CODE CHANGE
- Patch renamed from [PATCH V2 06/10] to [PATCH V3 6/9]
- Added Ack from Mark Brown
v1 -> v2
- Patch renamed from [PATCH V1 02/10] to [PATCH V2 06/10] -- these
changes were made to fix checkpatch warnings caused by the patch
set dependency order
- Updated header to use DA9061 and DA9062
Hi,
No code changes for this version PATCH V5.
As previously:
These changes depend on a header file provided as part of an earlier
patch [PATCH V5 4/8] from this set. The regulator probe() switches on
the chip_type which uses enum da9062_compatible_types in core.h from this
patch.
Regards,
Steve Twiss, Dialog Semiconductor Ltd.
drivers/regulator/Kconfig | 4 +-
drivers/regulator/da9062-regulator.c | 301 +++++++++++++++++++++++++++++++++--
2 files changed, 292 insertions(+), 13 deletions(-)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 936f7cc..bbb4be6 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -188,11 +188,11 @@ config REGULATOR_DA9055
will be called da9055-regulator.
config REGULATOR_DA9062
- tristate "Dialog Semiconductor DA9062 regulators"
+ tristate "Dialog Semiconductor DA9061/62 regulators"
depends on MFD_DA9062
help
Say y here to support the BUCKs and LDOs regulators found on
- DA9062 PMICs.
+ DA9061 and DA9062 PMICs.
This driver can also be built as a module. If so, the module
will be called da9062-regulator.
diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c
index 0638c8b..931be68 100644
--- a/drivers/regulator/da9062-regulator.c
+++ b/drivers/regulator/da9062-regulator.c
@@ -1,5 +1,5 @@
/*
- * da9062-regulator.c - REGULATOR device driver for DA9062
+ * Regulator device driver for DA9061 and DA9062.
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
@@ -28,6 +28,17 @@
/* Regulator IDs */
enum {
+ DA9061_ID_BUCK1,
+ DA9061_ID_BUCK2,
+ DA9061_ID_BUCK3,
+ DA9061_ID_LDO1,
+ DA9061_ID_LDO2,
+ DA9061_ID_LDO3,
+ DA9061_ID_LDO4,
+ DA9061_MAX_REGULATORS,
+};
+
+enum {
DA9062_ID_BUCK1,
DA9062_ID_BUCK2,
DA9062_ID_BUCK3,
@@ -88,15 +99,21 @@ enum {
/* Regulator operations */
-/* Current limits array (in uA) BUCK1 and BUCK3.
- Entry indexes corresponds to register values. */
+/* Current limits array (in uA)
+ * - DA9061_ID_[BUCK1|BUCK3]
+ * - DA9062_ID_[BUCK1|BUCK2|BUCK4]
+ * Entry indexes corresponds to register values.
+ */
static const int da9062_buck_a_limits[] = {
500000, 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000,
1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000
};
-/* Current limits array (in uA) for BUCK2.
- Entry indexes corresponds to register values. */
+/* Current limits array (in uA)
+ * - DA9061_ID_BUCK2
+ * - DA9062_ID_BUCK3
+ * Entry indexes corresponds to register values.
+ */
static const int da9062_buck_b_limits[] = {
1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000,
2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000
@@ -405,8 +422,254 @@ static int da9062_ldo_set_suspend_mode(struct regulator_dev *rdev,
.set_suspend_mode = da9062_ldo_set_suspend_mode,
};
-/* Regulator information */
-static const struct da9062_regulator_info local_regulator_info[] = {
+/* DA9061 Regulator information */
+static const struct da9062_regulator_info local_da9061_regulator_info[] = {
+ {
+ .desc.id = DA9061_ID_BUCK1,
+ .desc.name = "DA9061 BUCK1",
+ .desc.of_match = of_match_ptr("buck1"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_buck_ops,
+ .desc.min_uV = (300) * 1000,
+ .desc.uV_step = (10) * 1000,
+ .desc.n_voltages = ((1570) - (300))/(10) + 1,
+ .current_limits = da9062_buck_a_limits,
+ .n_current_limits = ARRAY_SIZE(da9062_buck_a_limits),
+ .desc.enable_reg = DA9062AA_BUCK1_CONT,
+ .desc.enable_mask = DA9062AA_BUCK1_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VBUCK1_A,
+ .desc.vsel_mask = DA9062AA_VBUCK1_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VBUCK1_A,
+ __builtin_ffs((int)DA9062AA_BUCK1_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK1_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VBUCK1_B,
+ __builtin_ffs((int)DA9062AA_BUCK1_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK1_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VBUCK1_B,
+ .mode = REG_FIELD(DA9062AA_BUCK1_CFG,
+ __builtin_ffs((int)DA9062AA_BUCK1_MODE_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK1_MODE_MASK)) - 1),
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VBUCK1_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VBUCK1_SEL_MASK)) - 1),
+ .ilimit = REG_FIELD(DA9062AA_BUCK_ILIM_C,
+ __builtin_ffs((int)DA9062AA_BUCK1_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK1_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_BUCK2,
+ .desc.name = "DA9061 BUCK2",
+ .desc.of_match = of_match_ptr("buck2"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_buck_ops,
+ .desc.min_uV = (800) * 1000,
+ .desc.uV_step = (20) * 1000,
+ .desc.n_voltages = ((3340) - (800))/(20) + 1,
+ .current_limits = da9062_buck_b_limits,
+ .n_current_limits = ARRAY_SIZE(da9062_buck_b_limits),
+ .desc.enable_reg = DA9062AA_BUCK3_CONT,
+ .desc.enable_mask = DA9062AA_BUCK3_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VBUCK3_A,
+ .desc.vsel_mask = DA9062AA_VBUCK3_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VBUCK3_A,
+ __builtin_ffs((int)DA9062AA_BUCK3_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK3_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VBUCK3_B,
+ __builtin_ffs((int)DA9062AA_BUCK3_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK3_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VBUCK3_B,
+ .mode = REG_FIELD(DA9062AA_BUCK3_CFG,
+ __builtin_ffs((int)DA9062AA_BUCK3_MODE_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK3_MODE_MASK)) - 1),
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VBUCK3_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VBUCK3_SEL_MASK)) - 1),
+ .ilimit = REG_FIELD(DA9062AA_BUCK_ILIM_A,
+ __builtin_ffs((int)DA9062AA_BUCK3_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK3_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_BUCK3,
+ .desc.name = "DA9061 BUCK3",
+ .desc.of_match = of_match_ptr("buck3"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_buck_ops,
+ .desc.min_uV = (530) * 1000,
+ .desc.uV_step = (10) * 1000,
+ .desc.n_voltages = ((1800) - (530))/(10) + 1,
+ .current_limits = da9062_buck_a_limits,
+ .n_current_limits = ARRAY_SIZE(da9062_buck_a_limits),
+ .desc.enable_reg = DA9062AA_BUCK4_CONT,
+ .desc.enable_mask = DA9062AA_BUCK4_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VBUCK4_A,
+ .desc.vsel_mask = DA9062AA_VBUCK4_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VBUCK4_A,
+ __builtin_ffs((int)DA9062AA_BUCK4_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK4_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VBUCK4_B,
+ __builtin_ffs((int)DA9062AA_BUCK4_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK4_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VBUCK4_B,
+ .mode = REG_FIELD(DA9062AA_BUCK4_CFG,
+ __builtin_ffs((int)DA9062AA_BUCK4_MODE_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK4_MODE_MASK)) - 1),
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VBUCK4_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VBUCK4_SEL_MASK)) - 1),
+ .ilimit = REG_FIELD(DA9062AA_BUCK_ILIM_B,
+ __builtin_ffs((int)DA9062AA_BUCK4_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_BUCK4_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_LDO1,
+ .desc.name = "DA9061 LDO1",
+ .desc.of_match = of_match_ptr("ldo1"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_ldo_ops,
+ .desc.min_uV = (900) * 1000,
+ .desc.uV_step = (50) * 1000,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.enable_reg = DA9062AA_LDO1_CONT,
+ .desc.enable_mask = DA9062AA_LDO1_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VLDO1_A,
+ .desc.vsel_mask = DA9062AA_VLDO1_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VLDO1_A,
+ __builtin_ffs((int)DA9062AA_LDO1_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO1_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VLDO1_B,
+ __builtin_ffs((int)DA9062AA_LDO1_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO1_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VLDO1_B,
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VLDO1_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VLDO1_SEL_MASK)) - 1),
+ .oc_event = REG_FIELD(DA9062AA_STATUS_D,
+ __builtin_ffs((int)DA9062AA_LDO1_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO1_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_LDO2,
+ .desc.name = "DA9061 LDO2",
+ .desc.of_match = of_match_ptr("ldo2"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_ldo_ops,
+ .desc.min_uV = (900) * 1000,
+ .desc.uV_step = (50) * 1000,
+ .desc.n_voltages = ((3600) - (600))/(50) + 1,
+ .desc.enable_reg = DA9062AA_LDO2_CONT,
+ .desc.enable_mask = DA9062AA_LDO2_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VLDO2_A,
+ .desc.vsel_mask = DA9062AA_VLDO2_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VLDO2_A,
+ __builtin_ffs((int)DA9062AA_LDO2_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO2_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VLDO2_B,
+ __builtin_ffs((int)DA9062AA_LDO2_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO2_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VLDO2_B,
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VLDO2_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VLDO2_SEL_MASK)) - 1),
+ .oc_event = REG_FIELD(DA9062AA_STATUS_D,
+ __builtin_ffs((int)DA9062AA_LDO2_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO2_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_LDO3,
+ .desc.name = "DA9061 LDO3",
+ .desc.of_match = of_match_ptr("ldo3"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_ldo_ops,
+ .desc.min_uV = (900) * 1000,
+ .desc.uV_step = (50) * 1000,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.enable_reg = DA9062AA_LDO3_CONT,
+ .desc.enable_mask = DA9062AA_LDO3_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VLDO3_A,
+ .desc.vsel_mask = DA9062AA_VLDO3_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VLDO3_A,
+ __builtin_ffs((int)DA9062AA_LDO3_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO3_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VLDO3_B,
+ __builtin_ffs((int)DA9062AA_LDO3_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO3_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VLDO3_B,
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VLDO3_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VLDO3_SEL_MASK)) - 1),
+ .oc_event = REG_FIELD(DA9062AA_STATUS_D,
+ __builtin_ffs((int)DA9062AA_LDO3_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO3_ILIM_MASK)) - 1),
+ },
+ {
+ .desc.id = DA9061_ID_LDO4,
+ .desc.name = "DA9061 LDO4",
+ .desc.of_match = of_match_ptr("ldo4"),
+ .desc.regulators_node = of_match_ptr("regulators"),
+ .desc.ops = &da9062_ldo_ops,
+ .desc.min_uV = (900) * 1000,
+ .desc.uV_step = (50) * 1000,
+ .desc.n_voltages = ((3600) - (900))/(50) + 1,
+ .desc.enable_reg = DA9062AA_LDO4_CONT,
+ .desc.enable_mask = DA9062AA_LDO4_EN_MASK,
+ .desc.vsel_reg = DA9062AA_VLDO4_A,
+ .desc.vsel_mask = DA9062AA_VLDO4_A_MASK,
+ .desc.linear_min_sel = 0,
+ .sleep = REG_FIELD(DA9062AA_VLDO4_A,
+ __builtin_ffs((int)DA9062AA_LDO4_SL_A_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO4_SL_A_MASK)) - 1),
+ .suspend_sleep = REG_FIELD(DA9062AA_VLDO4_B,
+ __builtin_ffs((int)DA9062AA_LDO4_SL_B_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO4_SL_B_MASK)) - 1),
+ .suspend_vsel_reg = DA9062AA_VLDO4_B,
+ .suspend = REG_FIELD(DA9062AA_DVC_1,
+ __builtin_ffs((int)DA9062AA_VLDO4_SEL_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_VLDO4_SEL_MASK)) - 1),
+ .oc_event = REG_FIELD(DA9062AA_STATUS_D,
+ __builtin_ffs((int)DA9062AA_LDO4_ILIM_MASK) - 1,
+ sizeof(unsigned int) * 8 -
+ __builtin_clz((DA9062AA_LDO4_ILIM_MASK)) - 1),
+ },
+};
+
+/* DA9062 Regulator information */
+static const struct da9062_regulator_info local_da9062_regulator_info[] = {
{
.desc.id = DA9062_ID_BUCK1,
.desc.name = "DA9062 BUCK1",
@@ -727,17 +990,33 @@ static int da9062_regulator_probe(struct platform_device *pdev)
struct da9062_regulators *regulators;
struct da9062_regulator *regl;
struct regulator_config config = { };
+ const struct da9062_regulator_info *rinfo;
int irq, n, ret;
size_t size;
+ int max_regulators;
+
+ switch (chip->chip_type) {
+ case COMPAT_TYPE_DA9061:
+ max_regulators = DA9061_MAX_REGULATORS;
+ rinfo = local_da9061_regulator_info;
+ break;
+ case COMPAT_TYPE_DA9062:
+ max_regulators = DA9062_MAX_REGULATORS;
+ rinfo = local_da9062_regulator_info;
+ break;
+ default:
+ dev_err(chip->dev, "Unrecognised chip type\n");
+ return -ENODEV;
+ }
/* Allocate memory required by usable regulators */
size = sizeof(struct da9062_regulators) +
- DA9062_MAX_REGULATORS * sizeof(struct da9062_regulator);
+ max_regulators * sizeof(struct da9062_regulator);
regulators = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!regulators)
return -ENOMEM;
- regulators->n_regulators = DA9062_MAX_REGULATORS;
+ regulators->n_regulators = max_regulators;
platform_set_drvdata(pdev, regulators);
n = 0;
@@ -745,7 +1024,7 @@ static int da9062_regulator_probe(struct platform_device *pdev)
/* Initialise regulator structure */
regl = ®ulators->regulator[n];
regl->hw = chip;
- regl->info = &local_regulator_info[n];
+ regl->info = &rinfo[n];
regl->desc = regl->info->desc;
regl->desc.type = REGULATOR_VOLTAGE;
regl->desc.owner = THIS_MODULE;
@@ -836,6 +1115,6 @@ static void __exit da9062_regulator_cleanup(void)
/* Module information */
MODULE_AUTHOR("S Twiss <stwiss.opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>");
-MODULE_DESCRIPTION("REGULATOR device driver for Dialog DA9062");
+MODULE_DESCRIPTION("REGULATOR device driver for Dialog DA9062 and DA9061");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:da9062-regulators");
--
end-of-patch for PATCH V5
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH V5 4/8] mfd: da9061: MFD core support
From: Steve Twiss @ 2016-12-15 19:08 UTC (permalink / raw)
To: LINUX-KERNEL, Lee Jones
Cc: DEVICETREE, Dmitry Torokhov, Eduardo Valentin, Guenter Roeck,
LINUX-INPUT, LINUX-PM, LINUX-WATCHDOG, Liam Girdwood, Mark Brown,
Mark Rutland, Rob Herring, Support Opensource, Wim Van Sebroeck,
Zhang Rui
In-Reply-To: <cover.1481828921.git.stwiss.opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
From: Steve Twiss <stwiss.opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
MFD support for DA9061 is provided as part of the DA9062 device driver.
The registers header file adds two new chip variant IDs defined in DA9061
and DA9062 hardware. The core header file adds new software enumerations
for listing the valid DA9061 IRQs and a da9062_compatible_types enumeration
for distinguishing between DA9061/62 devices in software.
The core source code adds a new .compatible of_device_id entry. This is
extended from DA9062 to support both "dlg,da9061" and "dlg,da9062". The
.data entry now holds a reference to the enumerated device type.
A new regmap_irq_chip model is added for DA9061 and this supports the new
list of regmap_irq entries. A new mfd_cell da9061_devs[] array lists the
new sub system components for DA9061. Support is added for a new DA9061
regmap_config which lists the correct readable, writable and volatile
ranges for this chip.
The probe function uses the device tree compatible string to switch on the
da9062_compatible_types and configure the correct mfd cells, irq chip and
regmap config.
Kconfig is updated to reflect support for DA9061 and DA9062 PMICs.
Signed-off-by: Steve Twiss <stwiss.opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
---
This patch applies against linux-next and v4.9
v4 -> v5
- NO CODE CHANGE
- Rebased from v4.8 to v4.9
v3 -> v4
- Patch renamed from [PATCH V3 5/9] to [PATCH V4 4/8]
- Removed DEFINE_RES_NAMED() macros for DA9061 resources and replaced
them with DEFINE_RES_IRQ_NAMED().
- Removed whitespace
- Reverted change for badly defined mfd_cell da9062_devs of_compatible
string from "dlg,da9062-watchdog" back to "dlg,da9062-wdt"
v2 -> v3
- NO CODE CHANGE
- Patch renamed from [PATCH V2 05/10] to [PATCH V3 5/9]
v1 -> v2
- Patch renamed from [PATCH V1 01/10] to [PATCH V2 05/10] -- these
changes were made to fix checkpatch warnings caused by the patch
set dependency order
- Fixed typo in the commit message "readble" to "readable"
- Removed the explicit cross-check to decide if there is a conflict
between the device tree compatible string and the hardware definition.
This patch assumes the device tree is correctly written and therefore
removes the need for a hardware/DT sanity check.
- Removed extra semicolon in drivers/mfd/da9062-core.c:877
- Re-write compatible entries into numerical order
Lee,
Changes as described in the version history above.
As previously:
This patch adds support for the DA9061 PMIC. This is done as part of the
existing DA9062 device driver by extending the of_device_id match table.
This in turn allows new MFD cells, irq chip and regmap definitions to
support DA9061.
Regards,
Steve Twiss, Dialog Semiconductor Ltd.
drivers/mfd/Kconfig | 5 +-
drivers/mfd/da9062-core.c | 424 +++++++++++++++++++++++++++++++++--
include/linux/mfd/da9062/core.h | 27 ++-
include/linux/mfd/da9062/registers.h | 2 +
4 files changed, 439 insertions(+), 19 deletions(-)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c6df644..a1a780c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -246,13 +246,14 @@ config MFD_DA9055
called "da9055"
config MFD_DA9062
- tristate "Dialog Semiconductor DA9062 PMIC Support"
+ tristate "Dialog Semiconductor DA9062/61 PMIC Support"
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
depends on I2C
help
- Say yes here for support for the Dialog Semiconductor DA9062 PMIC.
+ Say yes here for support for the Dialog Semiconductor DA9061 and
+ DA9062 PMICs.
This includes the I2C driver and core APIs.
Additional drivers must be enabled in order to use the functionality
of the device.
diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 8f873866..4b5f70f 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -1,5 +1,5 @@
/*
- * Core, IRQ and I2C device driver for DA9062 PMIC
+ * Core, IRQ and I2C device driver for DA9061 and DA9062 PMICs
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*
* This program is free software; you can redistribute it and/or
@@ -30,6 +30,70 @@
#define DA9062_REG_EVENT_B_OFFSET 1
#define DA9062_REG_EVENT_C_OFFSET 2
+static struct regmap_irq da9061_irqs[] = {
+ /* EVENT A */
+ [DA9061_IRQ_ONKEY] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_NONKEY_MASK,
+ },
+ [DA9061_IRQ_WDG_WARN] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_WDG_WARN_MASK,
+ },
+ [DA9061_IRQ_SEQ_RDY] = {
+ .reg_offset = DA9062_REG_EVENT_A_OFFSET,
+ .mask = DA9062AA_M_SEQ_RDY_MASK,
+ },
+ /* EVENT B */
+ [DA9061_IRQ_TEMP] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_TEMP_MASK,
+ },
+ [DA9061_IRQ_LDO_LIM] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_LDO_LIM_MASK,
+ },
+ [DA9061_IRQ_DVC_RDY] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_DVC_RDY_MASK,
+ },
+ [DA9061_IRQ_VDD_WARN] = {
+ .reg_offset = DA9062_REG_EVENT_B_OFFSET,
+ .mask = DA9062AA_M_VDD_WARN_MASK,
+ },
+ /* EVENT C */
+ [DA9061_IRQ_GPI0] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI0_MASK,
+ },
+ [DA9061_IRQ_GPI1] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI1_MASK,
+ },
+ [DA9061_IRQ_GPI2] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI2_MASK,
+ },
+ [DA9061_IRQ_GPI3] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI3_MASK,
+ },
+ [DA9061_IRQ_GPI4] = {
+ .reg_offset = DA9062_REG_EVENT_C_OFFSET,
+ .mask = DA9062AA_M_GPI4_MASK,
+ },
+};
+
+static struct regmap_irq_chip da9061_irq_chip = {
+ .name = "da9061-irq",
+ .irqs = da9061_irqs,
+ .num_irqs = DA9061_NUM_IRQ,
+ .num_regs = 3,
+ .status_base = DA9062AA_EVENT_A,
+ .mask_base = DA9062AA_IRQ_MASK_A,
+ .ack_base = DA9062AA_EVENT_A,
+};
+
static struct regmap_irq da9062_irqs[] = {
/* EVENT A */
[DA9062_IRQ_ONKEY] = {
@@ -102,6 +166,57 @@
.ack_base = DA9062AA_EVENT_A,
};
+static struct resource da9061_core_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_VDD_WARN, "VDD_WARN"),
+};
+
+static struct resource da9061_regulators_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_LDO_LIM, "LDO_LIM"),
+};
+
+static struct resource da9061_thermal_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_TEMP, "THERMAL"),
+};
+
+static struct resource da9061_wdt_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_WDG_WARN, "WD_WARN"),
+};
+
+static struct resource da9061_onkey_resources[] = {
+ DEFINE_RES_IRQ_NAMED(DA9061_IRQ_ONKEY, "ONKEY"),
+};
+
+static const struct mfd_cell da9061_devs[] = {
+ {
+ .name = "da9061-core",
+ .num_resources = ARRAY_SIZE(da9061_core_resources),
+ .resources = da9061_core_resources,
+ },
+ {
+ .name = "da9062-regulators",
+ .num_resources = ARRAY_SIZE(da9061_regulators_resources),
+ .resources = da9061_regulators_resources,
+ },
+ {
+ .name = "da9061-watchdog",
+ .num_resources = ARRAY_SIZE(da9061_wdt_resources),
+ .resources = da9061_wdt_resources,
+ .of_compatible = "dlg,da9061-watchdog",
+ },
+ {
+ .name = "da9061-thermal",
+ .num_resources = ARRAY_SIZE(da9061_thermal_resources),
+ .resources = da9061_thermal_resources,
+ .of_compatible = "dlg,da9061-thermal",
+ },
+ {
+ .name = "da9061-onkey",
+ .num_resources = ARRAY_SIZE(da9061_onkey_resources),
+ .resources = da9061_onkey_resources,
+ .of_compatible = "dlg,da9061-onkey",
+ },
+};
+
static struct resource da9062_core_resources[] = {
DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
};
@@ -200,7 +315,8 @@ static int da9062_clear_fault_log(struct da9062 *chip)
static int da9062_get_device_type(struct da9062 *chip)
{
- int device_id, variant_id, variant_mrc;
+ int device_id, variant_id, variant_mrc, variant_vrc;
+ char *type;
int ret;
ret = regmap_read(chip->regmap, DA9062AA_DEVICE_ID, &device_id);
@@ -219,9 +335,23 @@ static int da9062_get_device_type(struct da9062 *chip)
return -EIO;
}
+ variant_vrc = (variant_id & DA9062AA_VRC_MASK) >> DA9062AA_VRC_SHIFT;
+
+ switch (variant_vrc) {
+ case DA9062_PMIC_VARIANT_VRC_DA9061:
+ type = "DA9061";
+ break;
+ case DA9062_PMIC_VARIANT_VRC_DA9062:
+ type = "DA9062";
+ break;
+ default:
+ type = "Unknown";
+ break;
+ }
+
dev_info(chip->dev,
- "Device detected (device-ID: 0x%02X, var-ID: 0x%02X)\n",
- device_id, variant_id);
+ "Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s)\n",
+ device_id, variant_id, type);
variant_mrc = (variant_id & DA9062AA_MRC_MASK) >> DA9062AA_MRC_SHIFT;
@@ -234,6 +364,234 @@ static int da9062_get_device_type(struct da9062 *chip)
return ret;
}
+static const struct regmap_range da9061_aa_readable_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_STATUS_B,
+ }, {
+ .range_min = DA9062AA_STATUS_D,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_IRQ_MASK_A,
+ .range_max = DA9062AA_IRQ_MASK_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_GPIO_4,
+ }, {
+ .range_min = DA9062AA_GPIO_WKUP_MODE,
+ .range_max = DA9062AA_GPIO_OUT3_4,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_ID_4_3,
+ }, {
+ .range_min = DA9062AA_ID_12_11,
+ .range_max = DA9062AA_ID_16_15,
+ }, {
+ .range_min = DA9062AA_ID_22_21,
+ .range_max = DA9062AA_ID_32_31,
+ }, {
+ .range_min = DA9062AA_SEQ_A,
+ .range_max = DA9062AA_WAIT,
+ }, {
+ .range_min = DA9062AA_RESET,
+ .range_max = DA9062AA_BUCK_ILIM_C,
+ }, {
+ .range_min = DA9062AA_BUCK1_CFG,
+ .range_max = DA9062AA_BUCK3_CFG,
+ }, {
+ .range_min = DA9062AA_VBUCK1_A,
+ .range_max = DA9062AA_VBUCK4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK3_A,
+ .range_max = DA9062AA_VBUCK3_A,
+ }, {
+ .range_min = DA9062AA_VLDO1_A,
+ .range_max = DA9062AA_VLDO4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK1_B,
+ .range_max = DA9062AA_VBUCK4_B,
+ }, {
+ .range_min = DA9062AA_VBUCK3_B,
+ .range_max = DA9062AA_VBUCK3_B,
+ }, {
+ .range_min = DA9062AA_VLDO1_B,
+ .range_max = DA9062AA_VLDO4_B,
+ }, {
+ .range_min = DA9062AA_BBAT_CONT,
+ .range_max = DA9062AA_BBAT_CONT,
+ }, {
+ .range_min = DA9062AA_INTERFACE,
+ .range_max = DA9062AA_CONFIG_E,
+ }, {
+ .range_min = DA9062AA_CONFIG_G,
+ .range_max = DA9062AA_CONFIG_K,
+ }, {
+ .range_min = DA9062AA_CONFIG_M,
+ .range_max = DA9062AA_CONFIG_M,
+ }, {
+ .range_min = DA9062AA_GP_ID_0,
+ .range_max = DA9062AA_GP_ID_19,
+ }, {
+ .range_min = DA9062AA_DEVICE_ID,
+ .range_max = DA9062AA_CONFIG_ID,
+ },
+};
+
+static const struct regmap_range da9061_aa_writeable_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_PAGE_CON,
+ }, {
+ .range_min = DA9062AA_FAULT_LOG,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_IRQ_MASK_A,
+ .range_max = DA9062AA_IRQ_MASK_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_GPIO_4,
+ }, {
+ .range_min = DA9062AA_GPIO_WKUP_MODE,
+ .range_max = DA9062AA_GPIO_OUT3_4,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_ID_4_3,
+ }, {
+ .range_min = DA9062AA_ID_12_11,
+ .range_max = DA9062AA_ID_16_15,
+ }, {
+ .range_min = DA9062AA_ID_22_21,
+ .range_max = DA9062AA_ID_32_31,
+ }, {
+ .range_min = DA9062AA_SEQ_A,
+ .range_max = DA9062AA_WAIT,
+ }, {
+ .range_min = DA9062AA_RESET,
+ .range_max = DA9062AA_BUCK_ILIM_C,
+ }, {
+ .range_min = DA9062AA_BUCK1_CFG,
+ .range_max = DA9062AA_BUCK3_CFG,
+ }, {
+ .range_min = DA9062AA_VBUCK1_A,
+ .range_max = DA9062AA_VBUCK4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK3_A,
+ .range_max = DA9062AA_VBUCK3_A,
+ }, {
+ .range_min = DA9062AA_VLDO1_A,
+ .range_max = DA9062AA_VLDO4_A,
+ }, {
+ .range_min = DA9062AA_VBUCK1_B,
+ .range_max = DA9062AA_VBUCK4_B,
+ }, {
+ .range_min = DA9062AA_VBUCK3_B,
+ .range_max = DA9062AA_VBUCK3_B,
+ }, {
+ .range_min = DA9062AA_VLDO1_B,
+ .range_max = DA9062AA_VLDO4_B,
+ }, {
+ .range_min = DA9062AA_BBAT_CONT,
+ .range_max = DA9062AA_BBAT_CONT,
+ }, {
+ .range_min = DA9062AA_GP_ID_0,
+ .range_max = DA9062AA_GP_ID_19,
+ },
+};
+
+static const struct regmap_range da9061_aa_volatile_ranges[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_STATUS_B,
+ }, {
+ .range_min = DA9062AA_STATUS_D,
+ .range_max = DA9062AA_EVENT_C,
+ }, {
+ .range_min = DA9062AA_CONTROL_A,
+ .range_max = DA9062AA_CONTROL_B,
+ }, {
+ .range_min = DA9062AA_CONTROL_E,
+ .range_max = DA9062AA_CONTROL_F,
+ }, {
+ .range_min = DA9062AA_BUCK1_CONT,
+ .range_max = DA9062AA_BUCK4_CONT,
+ }, {
+ .range_min = DA9062AA_BUCK3_CONT,
+ .range_max = DA9062AA_BUCK3_CONT,
+ }, {
+ .range_min = DA9062AA_LDO1_CONT,
+ .range_max = DA9062AA_LDO4_CONT,
+ }, {
+ .range_min = DA9062AA_DVC_1,
+ .range_max = DA9062AA_DVC_1,
+ }, {
+ .range_min = DA9062AA_SEQ,
+ .range_max = DA9062AA_SEQ,
+ },
+};
+
+static const struct regmap_access_table da9061_aa_readable_table = {
+ .yes_ranges = da9061_aa_readable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_readable_ranges),
+};
+
+static const struct regmap_access_table da9061_aa_writeable_table = {
+ .yes_ranges = da9061_aa_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_writeable_ranges),
+};
+
+static const struct regmap_access_table da9061_aa_volatile_table = {
+ .yes_ranges = da9061_aa_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(da9061_aa_volatile_ranges),
+};
+
+static const struct regmap_range_cfg da9061_range_cfg[] = {
+ {
+ .range_min = DA9062AA_PAGE_CON,
+ .range_max = DA9062AA_CONFIG_ID,
+ .selector_reg = DA9062AA_PAGE_CON,
+ .selector_mask = 1 << DA9062_I2C_PAGE_SEL_SHIFT,
+ .selector_shift = DA9062_I2C_PAGE_SEL_SHIFT,
+ .window_start = 0,
+ .window_len = 256,
+ }
+};
+
+static struct regmap_config da9061_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .ranges = da9061_range_cfg,
+ .num_ranges = ARRAY_SIZE(da9061_range_cfg),
+ .max_register = DA9062AA_CONFIG_ID,
+ .cache_type = REGCACHE_RBTREE,
+ .rd_table = &da9061_aa_readable_table,
+ .wr_table = &da9061_aa_writeable_table,
+ .volatile_table = &da9061_aa_volatile_table,
+};
+
static const struct regmap_range da9062_aa_readable_ranges[] = {
{
.range_min = DA9062AA_PAGE_CON,
@@ -456,17 +814,38 @@ static int da9062_get_device_type(struct da9062 *chip)
.volatile_table = &da9062_aa_volatile_table,
};
+static const struct of_device_id da9062_dt_ids[] = {
+ { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061, },
+ { .compatible = "dlg,da9062", .data = (void *)COMPAT_TYPE_DA9062, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9062_dt_ids);
+
static int da9062_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct da9062 *chip;
+ const struct of_device_id *match;
unsigned int irq_base;
+ const struct mfd_cell *cell;
+ const struct regmap_irq_chip *irq_chip;
+ const struct regmap_config *config;
+ int cell_num;
int ret;
chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
+ if (i2c->dev.of_node) {
+ match = of_match_node(da9062_dt_ids, i2c->dev.of_node);
+ if (!match)
+ return -EINVAL;
+
+ chip->chip_type = (int)match->data;
+ } else
+ chip->chip_type = id->driver_data;
+
i2c_set_clientdata(i2c, chip);
chip->dev = &i2c->dev;
@@ -475,7 +854,25 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
return -EINVAL;
}
- chip->regmap = devm_regmap_init_i2c(i2c, &da9062_regmap_config);
+ switch (chip->chip_type) {
+ case(COMPAT_TYPE_DA9061):
+ cell = da9061_devs;
+ cell_num = ARRAY_SIZE(da9061_devs);
+ irq_chip = &da9061_irq_chip;
+ config = &da9061_regmap_config;
+ break;
+ case(COMPAT_TYPE_DA9062):
+ cell = da9062_devs;
+ cell_num = ARRAY_SIZE(da9062_devs);
+ irq_chip = &da9062_irq_chip;
+ config = &da9062_regmap_config;
+ break;
+ default:
+ dev_err(chip->dev, "Unrecognised chip type\n");
+ return -ENODEV;
+ }
+
+ chip->regmap = devm_regmap_init_i2c(i2c, config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(chip->dev, "Failed to allocate register map: %d\n",
@@ -493,7 +890,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
- -1, &da9062_irq_chip,
+ -1, irq_chip,
&chip->regmap_irq);
if (ret) {
dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
@@ -503,8 +900,8 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
irq_base = regmap_irq_chip_get_base(chip->regmap_irq);
- ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, da9062_devs,
- ARRAY_SIZE(da9062_devs), NULL, irq_base,
+ ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, cell,
+ cell_num, NULL, irq_base,
NULL);
if (ret) {
dev_err(chip->dev, "Cannot register child devices\n");
@@ -526,17 +923,12 @@ static int da9062_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id da9062_i2c_id[] = {
- { "da9062", 0 },
+ { "da9061", COMPAT_TYPE_DA9061 },
+ { "da9062", COMPAT_TYPE_DA9062 },
{ },
};
MODULE_DEVICE_TABLE(i2c, da9062_i2c_id);
-static const struct of_device_id da9062_dt_ids[] = {
- { .compatible = "dlg,da9062", },
- { }
-};
-MODULE_DEVICE_TABLE(of, da9062_dt_ids);
-
static struct i2c_driver da9062_i2c_driver = {
.driver = {
.name = "da9062",
@@ -549,6 +941,6 @@ static int da9062_i2c_remove(struct i2c_client *i2c)
module_i2c_driver(da9062_i2c_driver);
-MODULE_DESCRIPTION("Core device driver for Dialog DA9062");
+MODULE_DESCRIPTION("Core device driver for Dialog DA9061 and DA9062");
MODULE_AUTHOR("Steve Twiss <stwiss.opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>");
MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/da9062/core.h b/include/linux/mfd/da9062/core.h
index 376ba84..199c524 100644
--- a/include/linux/mfd/da9062/core.h
+++ b/include/linux/mfd/da9062/core.h
@@ -18,7 +18,31 @@
#include <linux/interrupt.h>
#include <linux/mfd/da9062/registers.h>
-/* Interrupts */
+enum da9062_compatible_types {
+ COMPAT_TYPE_DA9061 = 1,
+ COMPAT_TYPE_DA9062,
+};
+
+enum da9061_irqs {
+ /* IRQ A */
+ DA9061_IRQ_ONKEY,
+ DA9061_IRQ_WDG_WARN,
+ DA9061_IRQ_SEQ_RDY,
+ /* IRQ B*/
+ DA9061_IRQ_TEMP,
+ DA9061_IRQ_LDO_LIM,
+ DA9061_IRQ_DVC_RDY,
+ DA9061_IRQ_VDD_WARN,
+ /* IRQ C */
+ DA9061_IRQ_GPI0,
+ DA9061_IRQ_GPI1,
+ DA9061_IRQ_GPI2,
+ DA9061_IRQ_GPI3,
+ DA9061_IRQ_GPI4,
+
+ DA9061_NUM_IRQ,
+};
+
enum da9062_irqs {
/* IRQ A */
DA9062_IRQ_ONKEY,
@@ -45,6 +69,7 @@ struct da9062 {
struct device *dev;
struct regmap *regmap;
struct regmap_irq_chip_data *regmap_irq;
+ enum da9062_compatible_types chip_type;
};
#endif /* __MFD_DA9062_CORE_H__ */
diff --git a/include/linux/mfd/da9062/registers.h b/include/linux/mfd/da9062/registers.h
index 97790d1..4457fdc 100644
--- a/include/linux/mfd/da9062/registers.h
+++ b/include/linux/mfd/da9062/registers.h
@@ -18,6 +18,8 @@
#define DA9062_PMIC_DEVICE_ID 0x62
#define DA9062_PMIC_VARIANT_MRC_AA 0x01
+#define DA9062_PMIC_VARIANT_VRC_DA9061 0x01
+#define DA9062_PMIC_VARIANT_VRC_DA9062 0x02
#define DA9062_I2C_PAGE_SEL_SHIFT 1
--
end-of-patch for PATCH V5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH V5 2/8] Documentation: devicetree: thermal: da9062/61 TJUNC temperature binding
From: Steve Twiss @ 2016-12-15 19:08 UTC (permalink / raw)
To: DEVICETREE, Eduardo Valentin, LINUX-KERNEL, LINUX-PM,
Mark Rutland, Rob Herring, Zhang Rui
Cc: Dmitry Torokhov, Guenter Roeck, LINUX-INPUT, LINUX-WATCHDOG,
Lee Jones, Liam Girdwood, Lukasz Luba, Mark Brown,
Support Opensource, Wim Van Sebroeck
In-Reply-To: <cover.1481828921.git.stwiss.opensource@diasemi.com>
From: Steve Twiss <stwiss.opensource@diasemi.com>
Device tree binding information for DA9062 and DA9061 thermal junction
temperature monitor.
Binding descriptions for the DA9061 and DA9062 thermal TJUNC supervisor
device driver, using a single THERMAL_TRIP_HOT trip-wire and allowing for
a configurable polling period for over-temperature polling.
This patch also adds two examples, one for DA9062 and one for DA9061. The
DA9061 example uses a fall-back compatible string for the DA9062.
Signed-off-by: Steve Twiss <stwiss.opensource@diasemi.com>
---
This patch applies against linux-next and v4.9
v4 -> v5
- Rebased from v4.8 to v4.9
- Updates from comments by Eduardo Valentin
- Replace vendor defined dlg,tjunc-temp-polling-period-ms with standard
thermal core polling-delay-passive as part of the device tree
initialisation
- Remove Acked-by Rob Herring
v3 -> v4
- NO CODE CHANGE
- Patch renamed from [PATCH V3 3/9] to [PATCH V4 2/8]
- Added Acked-by Rob Herring
v2 -> v3
- Patch renamed from [PATCH V2 03/10] to [PATCH V3 3/9]
- Changes suggested from other component reviews by Rob Herring:
- Each compatible line should be a valid combination of compatible
strings: alter DA9061 line to include the fall back compatible string
and update the commit message accordingly
- Add e-mail information about associated patches from this set without
describing them as being explicitly dependent on this binding
v1 -> v2
- Patch renamed from [PATCH V1 08/10] to [PATCH V2 03/10] -- these
changes were made to fix checkpatch warnings caused by the patch
set dependency order
- A second example for DA9061 is provided to highlight the use of a
fall-back compatible option for the DA9062
Hi,
Updates for PATCH V5: the binding has been altered to remove the proposed
dlg,tjunc-temp-polling-period-ms and replaced with the standard thermal
core polling-delay-passive instead. This was in response to a request
from Eduardo Valentin as part of a driver change.
I have also removed a previous Ack by Rob Herring which was valid for
PATCH V3
As previously:
The device driver from this patch set (associated with this binding) is:
[PATCH V5 7/8] thermal: da9061: TJUNC temperature driver
Regards,
Steve Twiss, Dialog Semiconductor Ltd.
.../devicetree/bindings/thermal/da9062-thermal.txt | 37 ++++++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 Documentation/devicetree/bindings/thermal/da9062-thermal.txt
diff --git a/Documentation/devicetree/bindings/thermal/da9062-thermal.txt b/Documentation/devicetree/bindings/thermal/da9062-thermal.txt
new file mode 100644
index 0000000..08cc72e
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/da9062-thermal.txt
@@ -0,0 +1,37 @@
+* Dialog DA9062/61 TJUNC Thermal Module
+
+This module is part of the DA9061/DA9062. For more details about entire
+DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
+
+Junction temperature thermal module uses an interrupt signal to identify
+high THERMAL_TRIP_HOT temperatures for the PMIC device.
+
+Required properties:
+
+- compatible: should be one of the following valid compatible string lines:
+ "dlg,da9061-thermal", "dlg,da9062-thermal"
+ "dlg,da9062-thermal"
+
+Optional properties:
+
+- polling-delay-passive : Specify the polling period, measured in
+ milliseconds, between thermal zone device update checks.
+
+Example: DA9062
+
+ pmic0: da9062@58 {
+ thermal {
+ compatible = "dlg,da9062-thermal";
+ polling-delay-passive = <3000>;
+ };
+ };
+
+Example: DA9061 using a fall-back compatible for the DA9062 onkey driver
+
+ pmic0: da9061@58 {
+ thermal {
+ compatible = "dlg,da9061-thermal", "dlg,da9062-thermal";
+ polling-delay-passive = <3000>;
+ };
+ };
+
--
end-of-patch for PATCH V5
^ permalink raw reply related
* [PATCH V5 1/8] Documentation: devicetree: watchdog: da9062/61 watchdog timer binding
From: Steve Twiss @ 2016-12-15 19:08 UTC (permalink / raw)
To: DEVICETREE, Guenter Roeck, LINUX-KERNEL, LINUX-WATCHDOG,
Mark Rutland, Rob Herring, Wim Van Sebroeck
Cc: Dmitry Torokhov, Eduardo Valentin, LINUX-INPUT, LINUX-PM,
Lee Jones, Liam Girdwood, Mark Brown, Support Opensource,
Zhang Rui
In-Reply-To: <cover.1481828921.git.stwiss.opensource@diasemi.com>
From: Steve Twiss <stwiss.opensource@diasemi.com>
Add binding information for DA9062 and DA9061 watchdog.
Example bindings for both DA9062 and DA9061 devices are added. For
the DA9061 device, a fallback compatible line is added as a valid
combination of compatible strings.
The original binding for DA9062 (only) used to reside inside the
Documentation/devicetree/bindings/mfd/da9062.txt MFD document.
The da9062-watchdog section was deleted in that file and replaced
with a link to the new DA9061/62 binding information stored in this
patch.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Steve Twiss <stwiss.opensource@diasemi.com>
---
This patch applies against linux-next and v4.9
v4 -> v5
- NO CODE CHANGE
- Rebased from v4.8 to v4.9
v3 -> v4
- NO CODE CHANGE
- Patch renamed from [PATCH V3 2/9] to [PATCH V4 1/8]
- Added Acked-by Rob Herring
v2 -> v3
- Patch renamed from [PATCH V1 02/10] to [PATCH V3 2/9]
- Each compatible line should be a valid combination of compatible
strings, alter DA9061 line to include the fall back compatible string
- Update the commit message to describe this change
- Add information about associated patches from this set without
describing them as being explicitly dependent on this binding
v1 -> v2
- Patch renamed from [PATCH V1 07/10] to [PATCH V2 02/10] -- these
changes were made to fix checkpatch warnings caused by the patch
set dependency order
- Updated the patch description to be explicit about where parts of
this binding had originally been stored
- A second example for DA9061 is provided to highlight the use of a
fall-back compatible option for the DA9062 watchdog driver
Hi,
No code changes for this version PATCH V5.
As previously:
For the watchdog case: the DA9062 device driver is compatible with the
DA9061 and for this reason there is minimal change required to the DA9062
watchdog device driver. The example for the DA9061 watchdog shows the
use of a fall-back compatible string.
Other information:
The device driver from this patch set (associated with this binding) is
[PATCH V5 6/8] watchdog: da9061: watchdog driver
Regards,
Steve Twiss, Dialog Semiconductor Ltd.
.../devicetree/bindings/watchdog/da9062-wdt.txt | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 Documentation/devicetree/bindings/watchdog/da9062-wdt.txt
diff --git a/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt b/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt
new file mode 100644
index 0000000..b935b52
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt
@@ -0,0 +1,23 @@
+* Dialog Semiconductor DA9062/61 Watchdog Timer
+
+Required properties:
+
+- compatible: should be one of the following valid compatible string lines:
+ "dlg,da9061-watchdog", "dlg,da9062-watchdog"
+ "dlg,da9062-watchdog"
+
+Example: DA9062
+
+ pmic0: da9062@58 {
+ watchdog {
+ compatible = "dlg,da9062-watchdog";
+ };
+ };
+
+Example: DA9061 using a fall-back compatible for the DA9062 watchdog driver
+
+ pmic0: da9061@58 {
+ watchdog {
+ compatible = "dlg,da9061-watchdog", "dlg,da9062-watchdog";
+ };
+ };
--
end-of-patch for PATCH V5
^ permalink raw reply related
* [PATCH V5 3/8] Documentation: devicetree: mfd: da9062/61 MFD binding
From: Steve Twiss @ 2016-12-15 19:08 UTC (permalink / raw)
To: DEVICETREE, LINUX-KERNEL, Mark Rutland, Rob Herring
Cc: Dmitry Torokhov, Eduardo Valentin, Guenter Roeck, LINUX-INPUT,
LINUX-PM, LINUX-WATCHDOG, Lee Jones, Liam Girdwood, Mark Brown,
Support Opensource, Wim Van Sebroeck, Zhang Rui
In-Reply-To: <cover.1481828921.git.stwiss.opensource@diasemi.com>
From: Steve Twiss <stwiss.opensource@diasemi.com>
Extend existing DA9062 binding information to include the DA9061 PMIC for
MFD core and regulators.
Add a da9062-onkey link to the existing onkey binding file.
Add a da9062-thermal link to the new temperature monitoring binding file.
Delete the da9062-watchdog section and replace it with a link to the new
DA9061/62 binding information file.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Steve Twiss <stwiss.opensource@diasemi.com>
---
This patch applies against linux-next and v4.9
v4 -> v5
- NO CODE CHANGE
- Rebased from v4.8 to v4.9
v3 -> v4
- Patch renamed from [PATCH V3 4/9] to [PATCH V4 3/8]
- Remove double newline spacing in text file
- Added Acked-by Rob Herring
v2 -> v3
- Patch renamed from [PATCH V2 04/10] to [PATCH V3 4/9]
- Ensure binding description concentrates on the device not the
device driver
- Separate the DA9061 and DA9062 sub-device tables to distinguish
the difference between the two devices
- Update the commit message to describe this change
- Add e-mail information about associated patches from this set
without describing them as being explicitly dependent on this
binding
v1 -> v2
- Patch renamed from [PATCH V1 09/10] to [PATCH V2 04/10] -- these
changes were made to fix checkpatch warnings caused by the patch
set dependency order
Hi,
Added an Ack from Rob Herring for the PATCH V3 version.
As previously:
Other information:
The device driver from this patch set (associated with this binding) is
- [PATCH V5 4/8] mfd: da9061: MFD core support
and also the following binding file changes:
- Binding for onkey (already applied by Dmitry Torokhov)
- [PATCH V5 1/8] Binding for watchdog
- [PATCH V5 2/8] Binding for thermal
Regards,
Steve Twiss, Dialog Semiconductor Ltd.
Documentation/devicetree/bindings/mfd/da9062.txt | 49 +++++++++++++++++-------
1 file changed, 36 insertions(+), 13 deletions(-)
diff --git a/Documentation/devicetree/bindings/mfd/da9062.txt b/Documentation/devicetree/bindings/mfd/da9062.txt
index 38802b5..c0a418c 100644
--- a/Documentation/devicetree/bindings/mfd/da9062.txt
+++ b/Documentation/devicetree/bindings/mfd/da9062.txt
@@ -1,22 +1,39 @@
* Dialog DA9062 Power Management Integrated Circuit (PMIC)
-DA9062 consists of a large and varied group of sub-devices:
+Product information for the DA9062 and DA9061 devices can be found here:
+- http://www.dialog-semiconductor.com/products/da9062
+- http://www.dialog-semiconductor.com/products/da9061
+
+The DA9062 PMIC consists of:
Device Supply Names Description
------ ------------ -----------
da9062-regulator : : LDOs & BUCKs
da9062-rtc : : Real-Time Clock
+da9062-onkey : : On Key
+da9062-watchdog : : Watchdog Timer
+da9062-thermal : : Thermal
+
+The DA9061 PMIC consists of:
+
+Device Supply Names Description
+------ ------------ -----------
+da9062-regulator : : LDOs & BUCKs
+da9062-onkey : : On Key
da9062-watchdog : : Watchdog Timer
+da9062-thermal : : Thermal
======
Required properties:
-- compatible : Should be "dlg,da9062".
+- compatible : Should be
+ "dlg,da9062" for DA9062
+ "dlg,da9061" for DA9061
- reg : Specifies the I2C slave address (this defaults to 0x58 but it can be
modified to match the chip's OTP settings).
- interrupt-parent : Specifies the reference to the interrupt controller for
- the DA9062.
+ the DA9062 or DA9061.
- interrupts : IRQ line information.
- interrupt-controller
@@ -25,8 +42,8 @@ further information on IRQ bindings.
Sub-nodes:
-- regulators : This node defines the settings for the LDOs and BUCKs. The
- DA9062 regulators are bound using their names listed below:
+- regulators : This node defines the settings for the LDOs and BUCKs.
+ The DA9062 regulators are bound using their names listed below:
buck1 : BUCK_1
buck2 : BUCK_2
@@ -37,19 +54,29 @@ Sub-nodes:
ldo3 : LDO_3
ldo4 : LDO_4
+ The DA9061 regulators are bound using their names listed below:
+
+ buck1 : BUCK_1
+ buck2 : BUCK_2
+ buck3 : BUCK_3
+ ldo1 : LDO_1
+ ldo2 : LDO_2
+ ldo3 : LDO_3
+ ldo4 : LDO_4
+
The component follows the standard regulator framework and the bindings
details of individual regulator device can be found in:
Documentation/devicetree/bindings/regulator/regulator.txt
-
- rtc : This node defines settings required for the Real-Time Clock associated
with the DA9062. There are currently no entries in this binding, however
compatible = "dlg,da9062-rtc" should be added if a node is created.
-- watchdog: This node defines the settings for the watchdog driver associated
- with the DA9062 PMIC. The compatible = "dlg,da9062-watchdog" should be added
- if a node is created.
+- onkey : See ../input/da9062-onkey.txt
+
+- watchdog: See ../watchdog/da9062-watchdog.txt
+- thermal : See ../thermal/da9062-thermal.txt
Example:
@@ -64,10 +91,6 @@ Example:
compatible = "dlg,da9062-rtc";
};
- watchdog {
- compatible = "dlg,da9062-watchdog";
- };
-
regulators {
DA9062_BUCK1: buck1 {
regulator-name = "BUCK1";
--
end-of-patch for PATCH V5
^ permalink raw reply related
* RE: [PATCH V2 09/10] thermal: da9062/61: Thermal junction temperature monitoring driver
From: Steve Twiss @ 2016-12-15 19:06 UTC (permalink / raw)
To: Eduardo Valentin
Cc: LINUX-KERNEL, LINUX-PM, Zhang Rui, DEVICETREE, Dmitry Torokhov,
Guenter Roeck, LINUX-INPUT, LINUX-WATCHDOG, Lee Jones,
Liam Girdwood, Mark Brown, Mark Rutland, Rob Herring,
Support Opensource, Wim Van Sebroeck
In-Reply-To: <20161130060956.GA28175@localhost.localdomain>
Hi Eduardo,
Thank you for your review comments,
On 30 November 2016 06:10, Eduardo Valentin wrote,
> On Tue, Nov 29, 2016 at 11:11:59AM +0000, Steve Twiss wrote:
> > On 29 November 2016 01:24, Eduardo Valentin, wrote:
> > > On Wed, Oct 26, 2016 at 05:56:39PM +0100, Steve Twiss wrote:
[...]
> > > > +static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
> > > > +{
> > > > + struct da9062_thermal *thermal = data;
> > > > +
> > > > + disable_irq_nosync(thermal->irq);
> > > > + schedule_delayed_work(&thermal->work, 0);
[...]
> >
> > Over-temperature triggering is event based: an interrupt happens when the
> > temperature rises above 125 degC. However, this event based system changes into
> > a polling operation to detect when the temperature falls below the threshold
> > level again. This asymmetry in the chip's behaviour is the reasoning behind
> > why I am not using the thermal core's built-in polling functionality.
> >
> > When over-temperature is reached, the interrupt from the DA9061/2 will be
> > repeatedly triggered. The IRQ is disabled when the first over-temperature event
> > happens and the status bit is polled using the work-queue until it becomes false.
> > After that, the IRQ is re-enabled again so a new critical temperature event can
> > be detected.
> >
> > After the interrupt has happened, event bit for the interrupt switches into a status
> > bit and is used for polling and detecting when the temperature drops below the
> > threshold.
>
> OK. got it. Then, I am assuming your strategy here is to keep periodically issuing uevents
> (HOT trip point) to userland, hoping that something would change the
> system power consumption, then, relying on the hardware shutdown protection
> if nothing happens.
>
> I would say, your above explanation, and the uevent based strategy,
> deserves to be at least in the commit message, preferably in the driver
> documentation, so people know what to expect from the driver.
Ah, yes. I did not discuss that part in the design. Looking at this objectively, it is not
immediately obvious -- although you did describe my intentions exactly. I will add
those two changes into the next PATCH V5 submission so the meaning is explicit.
> The data sheet does not mention anything, but does one have any silicon
> lifetime implication if one leaves the PMIC running for very long time
> in a temperature between Twarn and Tcrit?
As of writing this reply, the latest available datasheet for DA9062 contains
sections on "Absolute Maximum Ratings" and "Recommended Operating Conditions"
for the junction temperature.
Regarding the warning temperature the datasheet says, "Operating the device in
conditions exceeding [this level] [...] for extended periods of time may
affect device reliability".
Reference to the documentation in the Linux kernel would also be useful on
the warning threshold. The driver defines this trip-point as,
Documentation/devicetree/bindings/thermal/thermal.txt
"hot": A trip point to notify emergency
I chose this trip point to indicate a strong recommendation that the
temperature warning is treated as an emergency, and should be brought under
control as fast as possible. This will stop any potential reliability problems before
the hardware enforces "a shutdown sequence to RESET mode" in the PMIC.
> Now, if my understand is correct, would it make sense to have still a
> failsafe mechanism in the driver? Maybe having a max number of polling?
I'm not certain what failsafe capability the general driver "should" have.
I am not implementing a notify function for instance. I expect the general
driver to be modified by the designers of the final integrated system. They
will also have access to the PMIC product datasheet and the information on
over-temperature and would be best placed to make a decision for their
system.
> > > > + thermal->zone = thermal_zone_device_register(thermal->config->name,
> > > > + 1, 0, thermal,
> > > > + &da9062_thermal_ops, NULL, 0,
> > > > + 0);
> > >
> > > Did you try using of-thermal?
> > >
> > > So you would avoid having specific DT properties for something that
> > > there is already a defined property?
[...]
> using the of-thermal DT support to get the polling value, instead of
> you having a manufacturer specific property:
> Documentation/devicetree/bindings/thermal/thermal.txt
>
> But given that your case is more specific, I start to see why you
> avoided using it. But still, you could probably get the polling
> values from of-thermal, populated in the tz struct, then using them from
> the tz, when handling the IRQ event.
>
> Probably your regular polling should always be set to 0, and the passive
> polling to the value you want.
Thank you for your additional explanation.
I will implement this as part of the next PATCH V5 submission.
> then again, this comment is more from a DT perspective than from the
> driver code itself. Just trying to avoid specific properties that may
> get described by what is already defined.
I agree. If I can possibly avoid creating device specific properties that are not
required and instead re-use existing core ones, I should do that.
[...]
Regards,
Steve
^ permalink raw reply
* Applied "spi: core: Extract of_spi_parse_dt()" to the spi tree
From: Mark Brown @ 2016-12-15 18:28 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: Mark Brown
In-Reply-To: <1473713446-30366-3-git-send-email-geert+renesas@glider.be>
The patch
spi: core: Extract of_spi_parse_dt()
has been applied to the spi tree at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
>From c2e51ac3d0542440d5b2b8b52ff2ad00751af4da Mon Sep 17 00:00:00 2001
From: Geert Uytterhoeven <geert+renesas@glider.be>
Date: Mon, 12 Sep 2016 22:50:41 +0200
Subject: [PATCH] spi: core: Extract of_spi_parse_dt()
Extract the parsing of SPI slave-specific properties into its own
function, so it can be reused later for SPI slave controllers.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
drivers/spi/spi.c | 60 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 36 insertions(+), 24 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 656dd3e3220c..1861255866d7 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1502,37 +1502,18 @@ static int spi_master_initialize_queue(struct spi_master *master)
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_OF)
-static struct spi_device *
-of_register_spi_device(struct spi_master *master, struct device_node *nc)
+static int of_spi_parse_dt(struct spi_master *master, struct spi_device *spi,
+ struct device_node *nc)
{
- struct spi_device *spi;
- int rc;
u32 value;
-
- /* Alloc an spi_device */
- spi = spi_alloc_device(master);
- if (!spi) {
- dev_err(&master->dev, "spi_device alloc error for %s\n",
- nc->full_name);
- rc = -ENOMEM;
- goto err_out;
- }
-
- /* Select device driver */
- rc = of_modalias_node(nc, spi->modalias,
- sizeof(spi->modalias));
- if (rc < 0) {
- dev_err(&master->dev, "cannot find modalias for %s\n",
- nc->full_name);
- goto err_out;
- }
+ int rc;
/* Device address */
rc = of_property_read_u32(nc, "reg", &value);
if (rc) {
dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
nc->full_name, rc);
- goto err_out;
+ return rc;
}
spi->chip_select = value;
@@ -1590,10 +1571,41 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc)
if (rc) {
dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
nc->full_name, rc);
- goto err_out;
+ return rc;
}
spi->max_speed_hz = value;
+ return 0;
+}
+
+static struct spi_device *
+of_register_spi_device(struct spi_master *master, struct device_node *nc)
+{
+ struct spi_device *spi;
+ int rc;
+
+ /* Alloc an spi_device */
+ spi = spi_alloc_device(master);
+ if (!spi) {
+ dev_err(&master->dev, "spi_device alloc error for %s\n",
+ nc->full_name);
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ /* Select device driver */
+ rc = of_modalias_node(nc, spi->modalias,
+ sizeof(spi->modalias));
+ if (rc < 0) {
+ dev_err(&master->dev, "cannot find modalias for %s\n",
+ nc->full_name);
+ goto err_out;
+ }
+
+ rc = of_spi_parse_dt(master, spi, nc);
+ if (rc)
+ goto err_out;
+
/* Store a pointer to the node in the device structure */
of_node_get(nc);
spi->dev.of_node = nc;
--
2.11.0
^ permalink raw reply related
* [PATCH v2] ARM: dts: sun8i: add opp-v2 table for A33
From: Icenowy Zheng @ 2016-12-15 18:27 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Hans de Goede, Quentin Schulz
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Icenowy Zheng
An operating point table is needed for the cpu frequency adjusting to
work.
The operating point table is converted from the common value in
extracted script.fex from many A33 board/tablets.
Signed-off-by: Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>
---
Changes since v1:
- Fix format problem (blank lines).
- Removed the 1.344GHz operating point, as it's overvoltage and overclocked.
This patch depends on the following patchset:
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-December/473962.html
It's the v2 of the [PATCH 4/6] in this patchset.
I think this operating point table may also apply to A23, as there's no
difference except the points over 1.2GHz between A23 and A33's stock dvfs table.
But as A23 CCU may not have the necessary fixes, I won't add the table to A23
now.
Chen-Yu, could you test the CCU fixes I described in the patchset above on A23,
then test this operating points table?
If it's necessary, you can send out the CCU fixes and add one more patch that
moves this opp-v2 table to sun8i-a23-a33.dtsi .
arch/arm/boot/dts/sun8i-a33.dtsi | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 504996cbee29..0f5b2af72981 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -46,7 +46,42 @@
#include <dt-bindings/dma/sun4i-a10.h>
/ {
+ cpu0_opp_table: opp_table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp@648000000 {
+ opp-hz = /bits/ 64 <648000000>;
+ opp-microvolt = <1040000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@816000000 {
+ opp-hz = /bits/ 64 <816000000>;
+ opp-microvolt = <1100000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@1008000000 {
+ opp-hz = /bits/ 64 <1008000000>;
+ opp-microvolt = <1200000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@1200000000 {
+ opp-hz = /bits/ 64 <1200000000>;
+ opp-microvolt = <1320000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+ };
+
cpus {
+ cpu0: cpu@0 {
+ clocks = <&ccu CLK_CPUX>;
+ clock-names = "cpu";
+ operating-points-v2 = <&cpu0_opp_table>;
+ };
+
cpu@2 {
compatible = "arm,cortex-a7";
device_type = "cpu";
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 3/3] arm64: dts: rockchip: add clk-480m for ehci and ohci of rk3399
From: Heiko Stuebner @ 2016-12-15 18:18 UTC (permalink / raw)
To: Doug Anderson
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Elaine Zhang, Tao Huang, Xing Zheng, Frank Wang, Catalin Marinas,
Brian Norris, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, daniel.meng,
Kever Yang, open list:ARM/Rockchip SoC..., Rob Herring,
William wu, Dmitry Torokhov, Jianqun Xu,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Caesar Wang
In-Reply-To: <CAD=FV=XKQaqRS4jUM7NpN2KEV8USj_cVWbh7q4274n3jBtwORg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Am Donnerstag, 15. Dezember 2016, 08:34:09 CET schrieb Doug Anderson:
> Hi,
>
> On Wed, Dec 14, 2016 at 10:41 PM, Frank Wang <frank.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
wrote:
> > Hi Brain, Doug and Heiko,
> >
> > I would like to summarize why this story was constructed.
> >
> > The ehci/ohci-platform suspend process are blocked due to UTMI clock which
> > directly output from usb-phy has been disabled, and why the UTMI clock was
> > disabled?
> >
> > UTMI clock and 480m clock all output from the same internal PLL of
> > usb-phy,
> > and there is only one bit can use to control this PLL on or off, which we
> > named "otg_commononn"(GRF, offset 0x0e450/0x0e460 bit4 ) in RK3399 TRM.
> >
> > When system boot up, ehci/ohci-platform probe function invoke
> > phy_power_on(), further invoke rockchip_usb2phy_power_on() to enable 480m
> > clock, actually, it sets the otg_commononn bit on, and then usb-phy will
> > go
> > to (auto)suspend if there is no devices plug-in after 1 minute, the
> > rockchip_usb2phy_power_off() will be invoked and the 480m clock may be
> > disabled in the (auto)suspend process. As a result, the otg_commononn bit
> > may be turned off, and all output clock of usb-phy will be disabled.
> > However, ehci/ohci-platform PM suspend operation (read/write controller
> > register) are based on the UTMI clock.
> >
> > So we introduced "clk_usbphy0_480m_src"/"clk_usbphy1_480m_src" as one
> > input
> > clock for ehci/ohci-platform, in this way, the otg_commononn bit is not
> > turned off until ehci/ohci-platform go to PM suspend.
>
> I still need to digest all of the things that were added to this
> thread overnight, but nothing I've seen so far indicates that you need
> the post-gated clock. AKA I still think you need to redo your patch
> to replace:
>
> clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
> <&cru SCLK_USBPHY0_480M_SRC>;
>
> with:
>
> clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
> <&u2phy0>;
>
> Can you please comment on that?
Also, with the change, the ehci will keep the clock (and thus the phy) always
on. Does the phy-autosuspend even save anything now?
In any case, could we make the clock-names entry sound nicer than usbphy0_480m
please? bindings/usb/atmel-usb.txt calls its UTMI clock simply "usb_clk", but
something like "utmi" should also work.
While at it you could also fix up the other clock names to something like
"host" and "arbiter" or so?.
Heiko
^ permalink raw reply
* Re: [PATCH 3/3] Bluetooth: btusb: Configure Marvel to use one of the pins for oob wakeup
From: Rajat Jain @ 2016-12-15 18:04 UTC (permalink / raw)
To: Gregory CLEMENT
Cc: Rob Herring, Mark Rutland, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Amitkumar Karwar, Wei-Ning Huang, Xinming Hu,
netdev, devicetree, linux-bluetooth, Brian Norris, Rajat Jain
In-Reply-To: <87shppk32a.fsf@free-electrons.com>
[-- Attachment #1: Type: text/plain, Size: 6813 bytes --]
On Thu, Dec 15, 2016 at 12:29 AM, Gregory CLEMENT <
gregory.clement@free-electrons.com> wrote:
> Hi Rajat,
>
> On mer., déc. 14 2016, Rajat Jain <rajatja@google.com> wrote:
>
> In your title unless you speak about the comic books you should do a
> s/Marvel/Marvell/ :)
>
Oops :-) Will do, thanks!
>
> Gregory
>
> > The Marvell devices may have many gpio pins, and hence for wakeup
> > on these out-of-band pins, the chip needs to be told which pin is
> > to be used for wakeup, using an hci command.
> >
> > Thus, we read the pin number etc from the device tree node and send
> > a command to the chip.
> >
> > Signed-off-by: Rajat Jain <rajatja@google.com>
> > ---
> > Note that while I would have liked to name the compatible string as more
> > like "marvell, usb8997-bt", the devicetrees/bindings/usb/usb-device.txt
> > requires the compatible property to be of the form "usbVID,PID".
> >
> > .../{marvell-bt-sd8xxx.txt => marvell-bt-8xxx.txt} | 25 ++++++++-
> > drivers/bluetooth/btusb.c | 59
> ++++++++++++++++++++++
> > 2 files changed, 82 insertions(+), 2 deletions(-)
> > rename Documentation/devicetree/bindings/net/{marvell-bt-sd8xxx.txt =>
> marvell-bt-8xxx.txt} (76%)
> >
> > diff --git a/Documentation/devicetree/bindings/net/marvell-bt-sd8xxx.txt
> b/Documentation/devicetree/bindings/net/marvell-bt-8xxx.txt
> > similarity index 76%
> > rename from Documentation/devicetree/bindings/net/marvell-bt-sd8xxx.txt
> > rename to Documentation/devicetree/bindings/net/marvell-bt-8xxx.txt
> > index 6a9a63c..471bef8 100644
> > --- a/Documentation/devicetree/bindings/net/marvell-bt-sd8xxx.txt
> > +++ b/Documentation/devicetree/bindings/net/marvell-bt-8xxx.txt
> > @@ -1,4 +1,4 @@
> > -Marvell 8897/8997 (sd8897/sd8997) bluetooth SDIO devices
> > +Marvell 8897/8997 (sd8897/sd8997) bluetooth devices (SDIO or USB based)
> > ------
> >
> > Required properties:
> > @@ -6,11 +6,13 @@ Required properties:
> > - compatible : should be one of the following:
> > * "marvell,sd8897-bt"
> > * "marvell,sd8997-bt"
> > + * "usb1286,204e"
> >
> > Optional properties:
> >
> > - marvell,cal-data: Calibration data downloaded to the device during
> > initialization. This is an array of 28 values(u8).
> > + This is only applicable to SDIO devices.
> >
> > - marvell,wakeup-pin: It represents wakeup pin number of the
> bluetooth chip.
> > firmware will use the pin to wakeup host system
> (u16).
> > @@ -29,7 +31,9 @@ Example:
> > IRQ pin 119 is used as system wakeup source interrupt.
> > wakeup pin 13 and gap 100ms are configured so that firmware can wakeup
> host
> > using this device side pin and wakeup latency.
> > -calibration data is also available in below example.
> > +
> > +Example for SDIO device follows (calibration data is also available in
> > +below example).
> >
> > &mmc3 {
> > status = "okay";
> > @@ -54,3 +58,20 @@ calibration data is also available in below example.
> > marvell,wakeup-gap-ms = /bits/ 16 <0x64>;
> > };
> > };
> > +
> > +Example for USB device:
> > +
> > +&usb_host1_ohci {
> > + status = "okay";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + mvl_bt1: bt@1 {
> > + compatible = "usb1286,204e";
> > + reg = <1>;
> > + interrupt-parent = <&gpio0>;
> > + interrupts = <119 IRQ_TYPE_LEVEL_LOW>;
> > + marvell,wakeup-pin = /bits/ 16 <0x0d>;
> > + marvell,wakeup-gap-ms = /bits/ 16 <0x64>;
> > + };
> > +};
> > diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> > index 32a6f22..99d7f6d 100644
> > --- a/drivers/bluetooth/btusb.c
> > +++ b/drivers/bluetooth/btusb.c
> > @@ -2343,6 +2343,58 @@ static int btusb_shutdown_intel(struct hci_dev
> *hdev)
> > return 0;
> > }
> >
> > +#ifdef CONFIG_PM
> > +static const struct of_device_id mvl_oob_wake_match_table[] = {
> > + { .compatible = "usb1286,204e" },
> > + { }
> > +};
> > +MODULE_DEVICE_TABLE(of, mvl_oob_wake_match_table);
> > +
> > +/* Configure an out-of-band gpio as wake-up pin, if specified in device
> tree */
> > +static int marvell_config_oob_wake(struct hci_dev *hdev)
> > +{
> > + struct sk_buff *skb;
> > + struct btusb_data *data = hci_get_drvdata(hdev);
> > + struct device *dev = &data->udev->dev;
> > + u16 pin, gap, opcode;
> > + int ret;
> > + u8 cmd[5];
> > +
> > + if (!of_match_device(mvl_oob_wake_match_table, dev))
> > + return 0;
> > +
> > + if (of_property_read_u16(dev->of_node, "marvell,wakeup-pin",
> &pin) ||
> > + of_property_read_u16(dev->of_node, "marvell,wakeup-gap-ms",
> &gap))
> > + return -EINVAL;
> > +
> > + /* Vendor specific command to configure a GPIO as wake-up pin */
> > + opcode = hci_opcode_pack(0x3F, 0x59);
> > + cmd[0] = opcode & 0xFF;
> > + cmd[1] = opcode >> 8;
> > + cmd[2] = 2; /* length of parameters that follow */
> > + cmd[3] = pin;
> > + cmd[4] = gap; /* time in ms, for which wakeup pin should be
> asserted */
> > +
> > + skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
> > + if (!skb) {
> > + bt_dev_err(hdev, "%s: No memory\n", __func__);
> > + return -ENOMEM;
> > + }
> > +
> > + memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
> > + hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
> > +
> > + ret = btusb_send_frame(hdev, skb);
> > + if (ret) {
> > + bt_dev_err(hdev, "%s: configuration failed\n", __func__);
> > + kfree_skb(skb);
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +#endif
> > +
> > static int btusb_set_bdaddr_marvell(struct hci_dev *hdev,
> > const bdaddr_t *bdaddr)
> > {
> > @@ -2917,6 +2969,13 @@ static int btusb_probe(struct usb_interface *intf,
> > err = btusb_config_oob_wake(hdev);
> > if (err)
> > goto out_free_dev;
> > +
> > + /* Marvel devices may need a specific chip configuration */
> > + if (id->driver_info & BTUSB_MARVELL && data->oob_wake_irq) {
> > + err = marvell_config_oob_wake(hdev);
> > + if (err)
> > + goto out_free_dev;
> > + }
> > #endif
> > if (id->driver_info & BTUSB_CW6622)
> > set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
> > --
> > 2.8.0.rc3.226.g39d4020
> >
>
> --
> Gregory Clement, Free Electrons
> Kernel, drivers, real-time and embedded Linux
> development, consulting, training and support.
> http://free-electrons.com
>
[-- Attachment #2: Type: text/html, Size: 9023 bytes --]
^ permalink raw reply
* Re: [PATCH/RFC v2 3/7] spi: core: Add support for registering SPI slave controllers
From: Mark Brown @ 2016-12-15 17:53 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Rob Herring, Mark Rutland, Magnus Damm, Wolfram Sang,
Hisashi Nakamura, Hiromitsu Yamasaki, linux-spi, devicetree,
linux-renesas-soc, linux-kernel
In-Reply-To: <1473713446-30366-4-git-send-email-geert+renesas@glider.be>
[-- Attachment #1: Type: text/plain, Size: 509 bytes --]
On Mon, Sep 12, 2016 at 10:50:42PM +0200, Geert Uytterhoeven wrote:
> TBD:
> - s/spi_master/spi_controller/ where appropriate,
> - Provide wrappers (e.g. "#define spi_master spi_controller" until all
> SPI drivers have been converted),
> - Do we want a separate spi_register_slave() instead?
This basically looks fine to me - there's these TBDs so I might be
missing things and we probably need some GPIO chip select handling but
that's a separate thing. Sorry it took me so long to review this.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v3] dt-bindings: power: supply: bq24735: reverse the polarity of ac-detect
From: Peter Rosin @ 2016-12-15 17:50 UTC (permalink / raw)
To: Stephen Warren
Cc: linux-kernel, Sebastian Reichel, Rob Herring, Mark Rutland,
linux-pm, devicetree, linux-tegra, Jon Hunter
In-Reply-To: <5f5fe01a-7c7a-58f7-2171-5f6879392ea7@wwwdotorg.org>
On 2016-12-15 18:32, Stephen Warren wrote:
> On 12/15/2016 05:21 AM, Peter Rosin wrote:
>> The ACOK pin on the bq24735 is active-high, of course meaning that when
>> AC is OK the pin is high. However, all Tegra dts files have incorrectly
>> specified active-high even though the signal is inverted on the Tegra
>> boards. This has worked since the Linux driver has also inverted the
>> meaning of the GPIO. Fix this situation by simply specifying in the
>> bindings what everybody else agrees on; that the ti,ac-detect-gpios is
>> active on AC adapter absence.
>>
>> Signed-off-by: Peter Rosin <peda@axentia.se>
>> ---
>>
>> Hi!
>>
>> This patch is the result of this discussion:
>> http://marc.info/?t=148152531800002
>>
>> I don't like how it changes the one thing that is seems correct, but
>> what to do?
>
> I haven't followed this thread so hopefully what I say is relevant. My
> take is:
>
> If the DT binding is correct or reasonable, keep it.
>
> If the Tegra DTs contain incorrect content, and never worked correctly
> in this aspect, then fix them. We do need to maintain DT
> ABI/compatibility, but I believe only with stuff that actually worked
> correctly. If the DT has a bug, just fix it.
>
> That said, if ti,ac-detect-gpios is describing a host GPIO, then it's
> entirely arbitrary which polarity it should have, i.e. the polarity is
> not something specified by the bq24735 HW. In that case, feel free to
> change either the binding to match the DT or the DT to match the
> binding. Changing the DT to match the binding might still be better
> since there could be other users you're not aware of, and they might
> have written their DT correctly, and you don't want to break them.
The bindings are fine.
The Tegra dts files are buggy, but the driver is also buggy, so those
two bugs cancel each other. So, the option is to either introduce
regressions by fixing the two bugs thus creating a flag day where
the kernel and dt needs to match. Or, just document what is going on
and change the bindings even if they are not wrong.
I suggest you read the discussion. We covered all this already, and it
is also in the commit message.
Cheers,
peda
^ permalink raw reply
* Re: [PATCH/RFC v2 3/7] spi: core: Add support for registering SPI slave controllers
From: Mark Brown @ 2016-12-15 17:46 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Geert Uytterhoeven, Rob Herring, Mark Rutland, Magnus Damm,
Wolfram Sang, Hiromitsu Yamasaki, linux-spi,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux-Renesas,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Fengguang Wu
In-Reply-To: <CAMuHMdWhuqSg+qUnDUqad-SBJOY5rOuRGuG7oUfTXiQA_rUtoA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 299 bytes --]
On Sun, Sep 18, 2016 at 11:04:18AM +0200, Geert Uytterhoeven wrote:
> This is caused by moving the setup of master->dev.class.
> To fix this, I can
> 1) Introduce a separate spi_alloc_slave() function, which sets up
> spi_slave_class instead of spi_master class,
This seems more idiomatic.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v3] dt-bindings: power: supply: bq24735: reverse the polarity of ac-detect
From: Stephen Warren @ 2016-12-15 17:32 UTC (permalink / raw)
To: Peter Rosin
Cc: linux-kernel, Sebastian Reichel, Rob Herring, Mark Rutland,
linux-pm, devicetree, linux-tegra, Jon Hunter
In-Reply-To: <1481804479-8711-1-git-send-email-peda@axentia.se>
On 12/15/2016 05:21 AM, Peter Rosin wrote:
> The ACOK pin on the bq24735 is active-high, of course meaning that when
> AC is OK the pin is high. However, all Tegra dts files have incorrectly
> specified active-high even though the signal is inverted on the Tegra
> boards. This has worked since the Linux driver has also inverted the
> meaning of the GPIO. Fix this situation by simply specifying in the
> bindings what everybody else agrees on; that the ti,ac-detect-gpios is
> active on AC adapter absence.
>
> Signed-off-by: Peter Rosin <peda@axentia.se>
> ---
>
> Hi!
>
> This patch is the result of this discussion:
> http://marc.info/?t=148152531800002
>
> I don't like how it changes the one thing that is seems correct, but
> what to do?
I haven't followed this thread so hopefully what I say is relevant. My
take is:
If the DT binding is correct or reasonable, keep it.
If the Tegra DTs contain incorrect content, and never worked correctly
in this aspect, then fix them. We do need to maintain DT
ABI/compatibility, but I believe only with stuff that actually worked
correctly. If the DT has a bug, just fix it.
That said, if ti,ac-detect-gpios is describing a host GPIO, then it's
entirely arbitrary which polarity it should have, i.e. the polarity is
not something specified by the bq24735 HW. In that case, feel free to
change either the binding to match the DT or the DT to match the
binding. Changing the DT to match the binding might still be better
since there could be other users you're not aware of, and they might
have written their DT correctly, and you don't want to break them.
^ permalink raw reply
* [PATCH v5 2/9] doc: DT: venus: binding document for Qualcomm video driver
From: Stanimir Varbanov @ 2016-12-15 17:22 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Hans Verkuil
Cc: Andy Gross, Bjorn Andersson, Stephen Boyd, Srinivas Kandagatla,
linux-media, linux-kernel, linux-arm-msm, Stanimir Varbanov,
Rob Herring, Mark Rutland, devicetree
In-Reply-To: <1481822544-29900-1-git-send-email-stanimir.varbanov@linaro.org>
Add binding document for Venus video encoder/decoder driver
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
---
.../devicetree/bindings/media/qcom,venus.txt | 68 ++++++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/qcom,venus.txt
diff --git a/Documentation/devicetree/bindings/media/qcom,venus.txt b/Documentation/devicetree/bindings/media/qcom,venus.txt
new file mode 100644
index 000000000000..7b77dff52b0f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/qcom,venus.txt
@@ -0,0 +1,68 @@
+* Qualcomm Venus video encode/decode accelerator
+
+- compatible:
+ Usage: required
+ Value type: <stringlist>
+ Definition: Value should contain one of:
+ - "qcom,msm8916-venus"
+ - "qcom,msm8996-venus"
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Register base address and length of the register map.
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Should contain interrupt line number.
+- clocks:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A List of phandle and clock specifier pairs as listed
+ in clock-names property.
+- clock-names:
+ Usage: required for msm8916
+ Value type: <stringlist>
+ Definition: Should contain the following entries:
+ - "core" Core video accelerator clock
+ - "iface" Video accelerator AHB clock
+ - "bus" Video accelerator AXI clock
+- clock-names:
+ Usage: required for msm8996
+ Value type: <stringlist>
+ Definition: Should contain the following entries:
+ - "core" Core video accelerator clock
+ - "iface" Video accelerator AHB clock
+ - "bus" Video accelerator AXI clock
+ - "subcore0" Subcore0 (decoder) video accelerator clock
+ - "subcore1" Subcore1 (encoder) video accelerator clock
+ - "mbus" Video MAXI clock
+- power-domains:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A phandle and power domain specifier pairs to the
+ power domain which is responsible for collapsing
+ and restoring power to the peripheral.
+- rproc:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A phandle to remote processor responsible for
+ firmware loading and processor booting.
+
+- iommus:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A list of phandle and IOMMU specifier pairs.
+
+* An Example
+ video-codec@1d00000 {
+ compatible = "qcom,msm8916-venus";
+ reg = <0x01d00000 0xff000>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>,
+ <&gcc GCC_VENUS0_AHB_CLK>,
+ <&gcc GCC_VENUS0_AXI_CLK>;
+ clock-names = "core", "iface", "bus";
+ power-domains = <&gcc VENUS_GDSC>;
+ rproc = <&venus_rproc>;
+ iommus = <&apps_iommu 5>;
+ };
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 3/3] arm64: dts: rockchip: add clk-480m for ehci and ohci of rk3399
From: Doug Anderson @ 2016-12-15 16:34 UTC (permalink / raw)
To: Frank Wang
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Elaine Zhang, Tao Huang, Heiko Stübner, Xing Zheng,
Catalin Marinas, Brian Norris, Will Deacon,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, daniel.meng,
Kever Yang, open list:ARM/Rockchip SoC..., Rob Herring,
William wu, Dmitry Torokhov, Jianqun Xu,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Caesar Wang
In-Reply-To: <991221a4-3962-1bcb-7863-72f5553eba40-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Hi,
On Wed, Dec 14, 2016 at 10:41 PM, Frank Wang <frank.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org> wrote:
> Hi Brain, Doug and Heiko,
>
> I would like to summarize why this story was constructed.
>
> The ehci/ohci-platform suspend process are blocked due to UTMI clock which
> directly output from usb-phy has been disabled, and why the UTMI clock was
> disabled?
>
> UTMI clock and 480m clock all output from the same internal PLL of usb-phy,
> and there is only one bit can use to control this PLL on or off, which we
> named "otg_commononn"(GRF, offset 0x0e450/0x0e460 bit4 ) in RK3399 TRM.
>
> When system boot up, ehci/ohci-platform probe function invoke
> phy_power_on(), further invoke rockchip_usb2phy_power_on() to enable 480m
> clock, actually, it sets the otg_commononn bit on, and then usb-phy will go
> to (auto)suspend if there is no devices plug-in after 1 minute, the
> rockchip_usb2phy_power_off() will be invoked and the 480m clock may be
> disabled in the (auto)suspend process. As a result, the otg_commononn bit
> may be turned off, and all output clock of usb-phy will be disabled.
> However, ehci/ohci-platform PM suspend operation (read/write controller
> register) are based on the UTMI clock.
>
> So we introduced "clk_usbphy0_480m_src"/"clk_usbphy1_480m_src" as one input
> clock for ehci/ohci-platform, in this way, the otg_commononn bit is not
> turned off until ehci/ohci-platform go to PM suspend.
I still need to digest all of the things that were added to this
thread overnight, but nothing I've seen so far indicates that you need
the post-gated clock. AKA I still think you need to redo your patch
to replace:
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
<&cru SCLK_USBPHY0_480M_SRC>;
with:
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
<&u2phy0>;
Can you please comment on that?
-Doug
^ permalink raw reply
* [PATCHv4 1/2] regulator: fixed: dt: Allow an optional over current pin
From: Axel Haslam @ 2016-12-15 16:29 UTC (permalink / raw)
To: broonie-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
khilman-rdvid1DuHRBWk0Htik3J/w, nsekhar-l0cyMroinI0,
david-nq/r/kbU++upp/zk7JDF2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Axel Haslam,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161215162955.3940-1-ahaslam-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Add support for an optional over current input pin which
can be used to send an over current event to the regulator
consumer.
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Axel Haslam <ahaslam-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
Documentation/devicetree/bindings/regulator/fixed-regulator.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
index 4fae41d..b145abb 100644
--- a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt
@@ -11,6 +11,7 @@ If this property is missing, the default assumed is Active low.
- gpio-open-drain: GPIO is open drain type.
If this property is missing then default assumption is false.
-vin-supply: Input supply name.
+- over-current-gpios: Input gpio that signal an over current condition.
Any property defined as part of the core regulator
binding, defined in regulator.txt, can also be used.
@@ -26,6 +27,7 @@ Example:
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
gpio = <&gpio1 16 0>;
+ over-current-gpios = <&gpio1 18 0>;
startup-delay-us = <70000>;
enable-active-high;
regulator-boot-on;
--
2.9.3
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v4 2/6] [media] rc-main: split setup and unregister functions
From: Andi Shyti @ 2016-12-15 16:01 UTC (permalink / raw)
To: Sean Young
Cc: Andi Shyti, Mauro Carvalho Chehab, Rob Herring, Mark Rutland,
Richard Purdie, Jacek Anaszewski, Heiner Kallweit, linux-media,
devicetree, linux-leds, linux-kernel, Andi Shyti
In-Reply-To: <20161215155049.GA23320@gofer.mess.org>
> > + /* rc_open will be called here */
> > + rc = input_register_device(dev->input_dev);
> > + if (rc)
> > + goto out_table;
> > +
> > + dev->input_dev->dev.parent = &dev->dev;
> > + memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
> > + dev->input_dev->phys = dev->input_phys;
> > + dev->input_dev->name = dev->input_name;
>
> I was testing your changes, and with this patch none of my rc devices
> have input devices associated with them. The problem is that you've changed
> the order: input_register_device() should happen AFTER the preceding
> 4 lines.
This must have been a copy paste error and I don't have
transmitters to test it. Thanks for testing it. I will send it
again.
Andi
^ permalink raw reply
* [PATCH 2/2] Documentation: ehci-omap: remove the unnecessary newline
From: yegorslists @ 2016-12-15 15:56 UTC (permalink / raw)
To: linux-kernel; +Cc: devicetree, robh+dt, mark.rutland, Yegor Yefremov
In-Reply-To: <1481817370-28242-1-git-send-email-yegorslists@googlemail.com>
From: Yegor Yefremov <yegorslists@googlemail.com>
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
---
Documentation/devicetree/bindings/usb/ehci-omap.txt | 1 -
1 file changed, 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/usb/ehci-omap.txt b/Documentation/devicetree/bindings/usb/ehci-omap.txt
index 3dc231c..d77e11a 100644
--- a/Documentation/devicetree/bindings/usb/ehci-omap.txt
+++ b/Documentation/devicetree/bindings/usb/ehci-omap.txt
@@ -29,4 +29,3 @@ usbhsehci: ehci@4a064c00 {
&usbhsehci {
phys = <&hsusb1_phy 0 &hsusb3_phy>;
};
-
--
2.1.4
^ permalink raw reply related
* [PATCH 1/2] Documentation: omap-usb-host: fix OMAP OHCI/EHCI file names
From: yegorslists-gM/Ye1E23mwN+BqQ9rBEUg @ 2016-12-15 15:56 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, Yegor Yefremov
From: Yegor Yefremov <yegorslists-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
OMAP related files are actually named ehci-omap.txt and ohci-omap3.txt.
Also add full path to ohci-omap3.txt.
Signed-off-by: Yegor Yefremov <yegorslists-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
---
Documentation/devicetree/bindings/mfd/omap-usb-host.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/mfd/omap-usb-host.txt b/Documentation/devicetree/bindings/mfd/omap-usb-host.txt
index 4721b2d..aa1eaa5 100644
--- a/Documentation/devicetree/bindings/mfd/omap-usb-host.txt
+++ b/Documentation/devicetree/bindings/mfd/omap-usb-host.txt
@@ -64,8 +64,8 @@ Required properties if child node exists:
Properties for children:
The OMAP HS USB Host subsystem contains EHCI and OHCI controllers.
-See Documentation/devicetree/bindings/usb/omap-ehci.txt and
-omap3-ohci.txt
+See Documentation/devicetree/bindings/usb/ehci-omap.txt and
+Documentation/devicetree/bindings/usb/ohci-omap3.txt.
Example for OMAP4:
--
2.1.4
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v2] i2c: designware: Cleaning and comment style fixes.
From: Luis Oliveira @ 2016-12-15 15:53 UTC (permalink / raw)
To: Peter Rosin, Luis Oliveira, wsa-z923LK4zBo2bacvFa/9K2g,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <f11794ec-439b-5fcd-65f4-c14c319cd627-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
On 15-Dec-16 15:17, Peter Rosin wrote:
> On 2016-12-15 15:38, Luis Oliveira wrote:
>> diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
>> index 26250b425e2f..3cb81fca7738 100644
>> --- a/drivers/i2c/busses/i2c-designware-core.h
>> +++ b/drivers/i2c/busses/i2c-designware-core.h
>> @@ -36,7 +36,7 @@
>> #define DW_IC_CON_SPEED_FAST 0x4
>> #define DW_IC_CON_SPEED_HIGH 0x6
>> #define DW_IC_CON_SPEED_MASK 0x6
>> -#define DW_IC_CON_10BITADDR_MASTER 0x10
>> +#define DW_IC_CON_10BITADDR_MASTER 0x10
>
> How is this an improvement?
It is not, I will fix it.
Thanks,
Luis
>
> Cheers,
> peda
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 2/6] [media] rc-main: split setup and unregister functions
From: Sean Young @ 2016-12-15 15:50 UTC (permalink / raw)
To: Andi Shyti
Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Richard Purdie,
Jacek Anaszewski, Heiner Kallweit, linux-media, devicetree,
linux-leds, linux-kernel, Andi Shyti
In-Reply-To: <20161214140030.28537-3-andi.shyti@samsung.com>
Hi Andi,
This patch breaks all rc devices, none of them have input devices any
more (see below).
On Wed, Dec 14, 2016 at 11:00:26PM +0900, Andi Shyti wrote:
> Move the input device allocation, map and protocol handling to
> different functions.
>
> Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
> Reviewed-by: Sean Young <sean@mess.org>
> ---
> drivers/media/rc/rc-main.c | 143 +++++++++++++++++++++++++--------------------
> 1 file changed, 81 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
> index a6bbceb..59fac96 100644
> --- a/drivers/media/rc/rc-main.c
> +++ b/drivers/media/rc/rc-main.c
> @@ -1436,16 +1436,12 @@ struct rc_dev *devm_rc_allocate_device(struct device *dev,
> }
> EXPORT_SYMBOL_GPL(devm_rc_allocate_device);
>
> -int rc_register_device(struct rc_dev *dev)
> +static int rc_setup_rx_device(struct rc_dev *dev)
> {
> - static bool raw_init = false; /* raw decoders loaded? */
> - struct rc_map *rc_map;
> - const char *path;
> - int attr = 0;
> - int minor;
> int rc;
> + struct rc_map *rc_map;
>
> - if (!dev || !dev->map_name)
> + if (!dev->map_name)
> return -EINVAL;
>
> rc_map = rc_map_get(dev->map_name);
> @@ -1454,6 +1450,19 @@ int rc_register_device(struct rc_dev *dev)
> if (!rc_map || !rc_map->scan || rc_map->size == 0)
> return -EINVAL;
>
> + rc = ir_setkeytable(dev, rc_map);
> + if (rc)
> + return rc;
> +
> + if (dev->change_protocol) {
> + u64 rc_type = (1ll << rc_map->rc_type);
> +
> + rc = dev->change_protocol(dev, &rc_type);
> + if (rc < 0)
> + goto out_table;
> + dev->enabled_protocols = rc_type;
> + }
> +
> set_bit(EV_KEY, dev->input_dev->evbit);
> set_bit(EV_REP, dev->input_dev->evbit);
> set_bit(EV_MSC, dev->input_dev->evbit);
> @@ -1463,6 +1472,61 @@ int rc_register_device(struct rc_dev *dev)
> if (dev->close)
> dev->input_dev->close = ir_close;
>
> + /*
> + * Default delay of 250ms is too short for some protocols, especially
> + * since the timeout is currently set to 250ms. Increase it to 500ms,
> + * to avoid wrong repetition of the keycodes. Note that this must be
> + * set after the call to input_register_device().
> + */
> + dev->input_dev->rep[REP_DELAY] = 500;
> +
> + /*
> + * As a repeat event on protocols like RC-5 and NEC take as long as
> + * 110/114ms, using 33ms as a repeat period is not the right thing
> + * to do.
> + */
> + dev->input_dev->rep[REP_PERIOD] = 125;
> +
> + /* rc_open will be called here */
> + rc = input_register_device(dev->input_dev);
> + if (rc)
> + goto out_table;
> +
> + dev->input_dev->dev.parent = &dev->dev;
> + memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
> + dev->input_dev->phys = dev->input_phys;
> + dev->input_dev->name = dev->input_name;
I was testing your changes, and with this patch none of my rc devices
have input devices associated with them. The problem is that you've changed
the order: input_register_device() should happen AFTER the preceding
4 lines.
> +
> + return 0;
> +
> +out_table:
> + ir_free_table(&dev->rc_map);
> +
> + return rc;
> +}
> +
> +static void rc_free_rx_device(struct rc_dev *dev)
> +{
> + if (!dev)
> + return;
> +
> + ir_free_table(&dev->rc_map);
> +
> + input_unregister_device(dev->input_dev);
> + dev->input_dev = NULL;
> +}
> +
> +int rc_register_device(struct rc_dev *dev)
> +{
> + static bool raw_init = false; /* raw decoders loaded? */
> + const char *path;
> + int attr = 0;
> + int minor;
> + int rc;
> +
> + if (!dev)
> + return -EINVAL;
> +
> minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
> if (minor < 0)
> return minor;
> @@ -1486,39 +1550,15 @@ int rc_register_device(struct rc_dev *dev)
> if (rc)
> goto out_unlock;
>
> - rc = ir_setkeytable(dev, rc_map);
> - if (rc)
> - goto out_dev;
See the original order here.
> -
> - dev->input_dev->dev.parent = &dev->dev;
> - memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
> - dev->input_dev->phys = dev->input_phys;
> - dev->input_dev->name = dev->input_name;
> -
> - rc = input_register_device(dev->input_dev);
> - if (rc)
> - goto out_table;
> -
> - /*
> - * Default delay of 250ms is too short for some protocols, especially
> - * since the timeout is currently set to 250ms. Increase it to 500ms,
> - * to avoid wrong repetition of the keycodes. Note that this must be
> - * set after the call to input_register_device().
> - */
> - dev->input_dev->rep[REP_DELAY] = 500;
> -
> - /*
> - * As a repeat event on protocols like RC-5 and NEC take as long as
> - * 110/114ms, using 33ms as a repeat period is not the right thing
> - * to do.
> - */
> - dev->input_dev->rep[REP_PERIOD] = 125;
> -
> path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
> dev_info(&dev->dev, "%s as %s\n",
> dev->input_name ?: "Unspecified device", path ?: "N/A");
> kfree(path);
>
> + rc = rc_setup_rx_device(dev);
> + if (rc)
> + goto out_dev;
> +
> if (dev->driver_type == RC_DRIVER_IR_RAW) {
> if (!raw_init) {
> request_module_nowait("ir-lirc-codec");
> @@ -1526,36 +1566,20 @@ int rc_register_device(struct rc_dev *dev)
> }
> rc = ir_raw_event_register(dev);
> if (rc < 0)
> - goto out_input;
> - }
> -
> - if (dev->change_protocol) {
> - u64 rc_type = (1ll << rc_map->rc_type);
> - rc = dev->change_protocol(dev, &rc_type);
> - if (rc < 0)
> - goto out_raw;
> - dev->enabled_protocols = rc_type;
> + goto out_rx;
> }
>
> /* Allow the RC sysfs nodes to be accessible */
> atomic_set(&dev->initialized, 1);
>
> - IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n",
> + IR_dprintk(1, "Registered rc%u (driver: %s)\n",
> dev->minor,
> - dev->driver_name ? dev->driver_name : "unknown",
> - rc_map->name ? rc_map->name : "unknown",
> - dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
> + dev->driver_name ? dev->driver_name : "unknown");
>
> return 0;
>
> -out_raw:
> - if (dev->driver_type == RC_DRIVER_IR_RAW)
> - ir_raw_event_unregister(dev);
> -out_input:
> - input_unregister_device(dev->input_dev);
> - dev->input_dev = NULL;
> -out_table:
> - ir_free_table(&dev->rc_map);
> +out_rx:
> + rc_free_rx_device(dev);
> out_dev:
> device_del(&dev->dev);
> out_unlock:
> @@ -1601,12 +1625,7 @@ void rc_unregister_device(struct rc_dev *dev)
> if (dev->driver_type == RC_DRIVER_IR_RAW)
> ir_raw_event_unregister(dev);
>
> - /* Freeing the table should also call the stop callback */
> - ir_free_table(&dev->rc_map);
> - IR_dprintk(1, "Freed keycode table\n");
> -
> - input_unregister_device(dev->input_dev);
> - dev->input_dev = NULL;
> + rc_free_rx_device(dev);
>
> device_del(&dev->dev);
>
> --
> 2.10.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v6 2/5] i2c: Add STM32F4 I2C driver
From: M'boumba Cedric Madianga @ 2016-12-15 15:26 UTC (permalink / raw)
To: Uwe Kleine-König
Cc: devicetree, Alexandre Torgue, Wolfram Sang, linux-kernel,
Linus Walleij, Patrice Chotard, linux, Rob Herring, linux-i2c,
Maxime Coquelin, linux-arm-kernel
In-Reply-To: <20161213092031.d2ax2pnpzzicriel@pengutronix.de>
Hello,
Thanks for this review, it will help.
2016-12-13 10:20 GMT+01:00 Uwe Kleine-König <u.kleine-koenig@pengutronix.de>:
> Hello,
>
> On Mon, Dec 12, 2016 at 05:15:39PM +0100, M'boumba Cedric Madianga wrote:
>> This patch adds support for the STM32F4 I2C controller.
>>
>> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
>> ---
>> drivers/i2c/busses/Kconfig | 10 +
>> drivers/i2c/busses/Makefile | 1 +
>> drivers/i2c/busses/i2c-stm32f4.c | 849 +++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 860 insertions(+)
>> create mode 100644 drivers/i2c/busses/i2c-stm32f4.c
>>
>> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
>> index 0cdc844..2719208 100644
>> --- a/drivers/i2c/busses/Kconfig
>> +++ b/drivers/i2c/busses/Kconfig
>> @@ -886,6 +886,16 @@ config I2C_ST
>> This driver can also be built as module. If so, the module
>> will be called i2c-st.
>>
>> +config I2C_STM32F4
>> + tristate "STMicroelectronics STM32F4 I2C support"
>> + depends on ARCH_STM32 || COMPILE_TEST
>> + help
>> + Enable this option to add support for STM32 I2C controller embedded
>> + in STM32F4 SoCs.
>> +
>> + This driver can also be built as module. If so, the module
>> + will be called i2c-stm32f4.
>> +
>> config I2C_STU300
>> tristate "ST Microelectronics DDC I2C interface"
>> depends on MACH_U300
>> diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
>> index 1c1bac8..a2c6ff5 100644
>> --- a/drivers/i2c/busses/Makefile
>> +++ b/drivers/i2c/busses/Makefile
>> @@ -85,6 +85,7 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
>> obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
>> obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
>> obj-$(CONFIG_I2C_ST) += i2c-st.o
>> +obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o
>> obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
>> obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
>> obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
>> diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c
>> new file mode 100644
>> index 0000000..89ad579
>> --- /dev/null
>> +++ b/drivers/i2c/busses/i2c-stm32f4.c
>> @@ -0,0 +1,849 @@
>> +/*
>> + * Driver for STMicroelectronics STM32 I2C controller
>> + *
>> + * Copyright (C) M'boumba Cedric Madianga 2015
>> + * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
>> + *
>> + * This driver is based on i2c-st.c
>> + *
>> + * License terms: GNU General Public License (GPL), version 2
>> + */
>
> If there is a public description available for the device, a link here
> would be great.
The device is described in the reference manual of the STM32F429/439 SoC.
As this reference manual is public, I will add it at the beginning of
the driver as requested.
>
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/iopoll.h>
>> +#include <linux/module.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset.h>
>> +
>> +/* STM32F4 I2C offset registers */
>> +#define STM32F4_I2C_CR1 0x00
>> +#define STM32F4_I2C_CR2 0x04
>> +#define STM32F4_I2C_DR 0x10
>> +#define STM32F4_I2C_SR1 0x14
>> +#define STM32F4_I2C_SR2 0x18
>> +#define STM32F4_I2C_CCR 0x1C
>> +#define STM32F4_I2C_TRISE 0x20
>> +#define STM32F4_I2C_FLTR 0x24
>> +
>> +/* STM32F4 I2C control 1*/
>> +#define STM32F4_I2C_CR1_SWRST BIT(15)
>> +#define STM32F4_I2C_CR1_POS BIT(11)
>> +#define STM32F4_I2C_CR1_ACK BIT(10)
>> +#define STM32F4_I2C_CR1_STOP BIT(9)
>> +#define STM32F4_I2C_CR1_START BIT(8)
>> +#define STM32F4_I2C_CR1_PE BIT(0)
>> +
>> +/* STM32F4 I2C control 2 */
>> +#define STM32F4_I2C_CR2_FREQ_MASK GENMASK(5, 0)
>> +#define STM32F4_I2C_CR2_FREQ(n) ((n & STM32F4_I2C_CR2_FREQ_MASK))
>
> This should better be ((n) & STM32F4_I2C_CR2_FREQ_MASK). There a few
> more constants that need the same fix.
OK I will fix it in the V7. Thanks.
>
>> +#define STM32F4_I2C_CR2_ITBUFEN BIT(10)
>> +#define STM32F4_I2C_CR2_ITEVTEN BIT(9)
>> +#define STM32F4_I2C_CR2_ITERREN BIT(8)
>> +#define STM32F4_I2C_CR2_IRQ_MASK (STM32F4_I2C_CR2_ITBUFEN \
>> + | STM32F4_I2C_CR2_ITEVTEN \
>> + | STM32F4_I2C_CR2_ITERREN)
>
> I'd layout this like:
>
> #define STM32F4_I2C_CR2_IRQ_MASK (STM32F4_I2C_CR2_ITBUFEN | \
> STM32F4_I2C_CR2_ITEVTEN | \
> STM32F4_I2C_CR2_ITERREN)
>
> which is more usual I think.
OK I will fix it in the V7. Thanks.
>
>> +/* STM32F4 I2C Status 1 */
>> +#define STM32F4_I2C_SR1_AF BIT(10)
>> +#define STM32F4_I2C_SR1_ARLO BIT(9)
>> +#define STM32F4_I2C_SR1_BERR BIT(8)
>> +#define STM32F4_I2C_SR1_TXE BIT(7)
>> +#define STM32F4_I2C_SR1_RXNE BIT(6)
>> +#define STM32F4_I2C_SR1_BTF BIT(2)
>> +#define STM32F4_I2C_SR1_ADDR BIT(1)
>> +#define STM32F4_I2C_SR1_SB BIT(0)
>> +#define STM32F4_I2C_SR1_ITEVTEN_MASK (STM32F4_I2C_SR1_BTF \
>> + | STM32F4_I2C_SR1_ADDR \
>> + | STM32F4_I2C_SR1_SB)
>> +#define STM32F4_I2C_SR1_ITBUFEN_MASK (STM32F4_I2C_SR1_TXE \
>> + | STM32F4_I2C_SR1_RXNE)
>> +#define STM32F4_I2C_SR1_ITERREN_MASK (STM32F4_I2C_SR1_AF \
>> + | STM32F4_I2C_SR1_ARLO \
>> + | STM32F4_I2C_SR1_BERR)
>> +
>> +/* STM32F4 I2C Status 2 */
>> +#define STM32F4_I2C_SR2_BUSY BIT(1)
>> +
>> +/* STM32F4 I2C Control Clock */
>> +#define STM32F4_I2C_CCR_CCR_MASK GENMASK(11, 0)
>> +#define STM32F4_I2C_CCR_CCR(n) ((n & STM32F4_I2C_CCR_CCR_MASK))
>> +#define STM32F4_I2C_CCR_FS BIT(15)
>> +#define STM32F4_I2C_CCR_DUTY BIT(14)
>> +
>> +/* STM32F4 I2C Trise */
>> +#define STM32F4_I2C_TRISE_VALUE_MASK GENMASK(5, 0)
>> +#define STM32F4_I2C_TRISE_VALUE(n) ((n & STM32F4_I2C_TRISE_VALUE_MASK))
>> +
>> +/* STM32F4 I2C Filter */
>> +#define STM32F4_I2C_FLTR_DNF_MASK GENMASK(3, 0)
>> +#define STM32F4_I2C_FLTR_DNF(n) ((n & STM32F4_I2C_FLTR_DNF_MASK))
>> +#define STM32F4_I2C_FLTR_ANOFF BIT(4)
>> +
>> +#define STM32F4_I2C_MIN_FREQ 2U
>> +#define STM32F4_I2C_MAX_FREQ 42U
>> +#define FAST_MODE_MAX_RISE_TIME 1000
>> +#define STD_MODE_MAX_RISE_TIME 300
>
> Are these supposed to be the values "rise time of both SDA and SCL
> signals" from the i2c specification? If so, you got it wrong, fast mode
> has the smaller value.
Yes you are right. My mistake. Thanks
> Maybe these constants could get a home in a more central place?
Yes we probably could add these constants in a include file like i2c.h
or someting like that.
Wolfram, what is your opinion regarding this proposal ?
> Also I'd add /* ns */ to the definition.
Ok
>
>> +#define MHZ_TO_HZ 1000000
>> +
>> +enum stm32f4_i2c_speed {
>> + STM32F4_I2C_SPEED_STANDARD, /* 100 kHz */
>> + STM32F4_I2C_SPEED_FAST, /* 400 kHz */
>> + STM32F4_I2C_SPEED_END,
>> +};
>> +
>> +/**
>> + * struct stm32f4_i2c_timings - per-Mode tuning parameters
>> + * @duty: Fast mode duty cycle
>> + * @mul_ccr: Value to be multiplied to CCR to reach 100Khz/400Khz SCL frequency
>> + * @min_ccr: Minimum clock ctrl reg value to reach 100Khz/400Khz SCL frequency
>> + */
>> +struct stm32f4_i2c_timings {
>> + u32 rate;
>
> rate is undocumented and unused.
Good point. I will remove it. Thanks.
>
>> + u32 duty;
>> + u32 mul_ccr;
>> + u32 min_ccr;
>> +};
>> +
>> +/**
>> + * struct stm32f4_i2c_msg - client specific data
>> + * @addr: 8-bit slave addr, including r/w bit
>> + * @count: number of bytes to be transferred
>> + * @buf: data buffer
>> + * @result: result of the transfer
>> + * @stop: last I2C msg to be sent, i.e. STOP to be generated
>> + */
>> +struct stm32f4_i2c_msg {
>> + u8 addr;
>> + u32 count;
>> + u8 *buf;
>> + int result;
>> + bool stop;
>> +};
>> +
>> +/**
>> + * struct stm32f4_i2c_dev - private data of the controller
>> + * @adap: I2C adapter for this controller
>> + * @dev: device for this controller
>> + * @base: virtual memory area
>> + * @complete: completion of I2C message
>> + * @irq_event: interrupt event line for the controller
>> + * @irq_error: interrupt error line for the controller
>> + * @clk: hw i2c clock
>> + * speed: I2C clock frequency of the controller. Standard or Fast only supported
>> + * @msg: I2C transfer information
>> + */
>> +struct stm32f4_i2c_dev {
>> + struct i2c_adapter adap;
>> + struct device *dev;
>> + void __iomem *base;
>> + struct completion complete;
>> + int irq_event;
>> + int irq_error;
>
> You only use irq_event in the probe function. So there is no need to
> remember this one and you could use a local variable instead.
Ok, I will fix it in the V7. Thanks
>
>> + struct clk *clk;
>> + int speed;
>> + struct stm32f4_i2c_msg msg;
>> +};
>> +
>> +static struct stm32f4_i2c_timings i2c_timings[] = {
>> + [STM32F4_I2C_SPEED_STANDARD] = {
>> + .mul_ccr = 1,
>> + .min_ccr = 4,
>> + .duty = 0,
>> + },
>> + [STM32F4_I2C_SPEED_FAST] = {
>> + .mul_ccr = 16,
>> + .min_ccr = 1,
>> + .duty = 1,
>> + },
>
> Are these values from the datasheet?
Yes, these values come from I2C IP datasheet.
>
>> +};
>> +
>> +static inline void stm32f4_i2c_set_bits(void __iomem *reg, u32 mask)
>> +{
>> + writel_relaxed(readl_relaxed(reg) | mask, reg);
>> +}
>> +
>> +static inline void stm32f4_i2c_clr_bits(void __iomem *reg, u32 mask)
>> +{
>> + writel_relaxed(readl_relaxed(reg) & ~mask, reg);
>> +}
>> +
>> +static void stm32f4_i2c_soft_reset(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
>> +
>> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_SWRST);
>> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_SWRST);
>
> Not very critical, but you're doing an unneeded register access here
> because the register is read twice.
>
> Also I think readability would improve if you dropped
> stm32f4_i2c_{set,clr}_bits and do their logic explicitly in the callers.
>
> stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_SWRST);
> stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_SWRST);
>
> vs
>
> val = readl_relaxed(reg);
> writel_relaxed(val | STM32F4_I2C_CR1_SWRST, reg);
> writel_relaxed(val, reg);
>
If it is just for this function, I don't have any objection to use
your proposal.
But if your request, it is to drop all calls of
stm32f4_i2c_{set,clr}_bits, I am wondering if it is something really
critical ?
Indeed, this is a big impact in this driver and I would prefer to avoid it.
>> +}
>> +
>> +static void stm32f4_i2c_disable_it(struct stm32f4_i2c_dev *i2c_dev)
>
> What is "it"? If it stands for "interrupt" the more usual abbrev is
> "irq".
Yes it stands for interrupt.
So, I will replace it by irq in the next version.
>
>> +{
>> + void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
>> +
>> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_IRQ_MASK);
>> +}
>> +
>> +static void stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + u32 clk_rate, cr2, freq;
>> +
>> + cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
>> + cr2 &= ~STM32F4_I2C_CR2_FREQ_MASK;
>> + clk_rate = clk_get_rate(i2c_dev->clk);
>> + freq = clk_rate / MHZ_TO_HZ;
>> + freq = clamp(freq, STM32F4_I2C_MIN_FREQ, STM32F4_I2C_MAX_FREQ);
>> + cr2 |= STM32F4_I2C_CR2_FREQ(freq);
>> + writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
>
> Can you quote the data sheet enough in a comment here to make it obvious
> that your calculation is right?
Ok I will add it.
>
> Would it be more sensible to error out if clk_rate / MHZ_TO_HZ isn't in
> the interval [STM32F4_I2C_MIN_FREQ, STM32F4_I2C_MAX_FREQ]?
Yes, input clock must be between 2 MHz and 42 Mhz to achieve standard
or fast mode mode I²C frequencies.
If it is not the case, the I2C signal integrity is not guarantee and
could lead to communication issue between devices on the I2C bus.
>
> Usually I would expect that you need to use
> DIV_ROUND_UP(clk_rate, MHZ_TO_HZ) instead of a plain division.
Ok, I will use this macro in the next version
>
>> +}
>> +
>> +static void stm32f4_i2c_set_rise_time(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + u32 trise, freq, cr2, val;
>> +
>> + cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
>> + freq = cr2 & STM32F4_I2C_CR2_FREQ_MASK;
>> +
>> + trise = readl_relaxed(i2c_dev->base + STM32F4_I2C_TRISE);
>> + trise &= ~STM32F4_I2C_TRISE_VALUE_MASK;
>
> Are you required to use rmw for STM32F4_I2C_TRISE? I'd prefer
>
> writel_relaxed(STM32F4_I2C_TRISE_VALUE(..), i2c_dev->base + STM32F4_I2C_TRISE);
>
> unless the datasheet requires rmw.
>
>> + /* Maximum rise time computation */
>> + if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD) {
>> + trise |= STM32F4_I2C_TRISE_VALUE((freq + 1));
>
> A single pair of parenthesis is enough when you fix
> STM32F4_I2C_TRISE_VALUE as suggested above.
The datasheet does not required to use rmw so I will use your proposal
in the next version. Thanks.
>
>> + } else {
>> + val = freq * FAST_MODE_MAX_RISE_TIME / STD_MODE_MAX_RISE_TIME;
>> + trise |= STM32F4_I2C_TRISE_VALUE((val + 1));
>
> val could be local to this branch.
>
> Or make it shorter using:
>
> freq = cr2 & STM32F4_I2C_CR2_FREQ_MASK;
> if (i2c_dev->speed == STM32F4_I2C_SPEED_FAST)
> freq = freq * FAST_MODE_MAX_RISE_TIME / STD_MODE_MAX_RISE_TIME;
>
> writel_relaxed(STM32F4_I2C_TRISE_VALUE(freq + 1), ...);
>
> A quote from the data sheet about the algorithm would be good here, too.
Ok, I will use a shorter way to compute freq and add a quote from the datasheet
>
>> + }
>> +
>> + writel_relaxed(trise, i2c_dev->base + STM32F4_I2C_TRISE);
>> +}
>> +
>> +static void stm32f4_i2c_set_speed_mode(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + struct stm32f4_i2c_timings *t = &i2c_timings[i2c_dev->speed];
>> + u32 ccr, clk_rate;
>> + int val;
>> +
>> + ccr = readl_relaxed(i2c_dev->base + STM32F4_I2C_CCR);
>> + ccr &= ~(STM32F4_I2C_CCR_FS | STM32F4_I2C_CCR_DUTY |
>> + STM32F4_I2C_CCR_CCR_MASK);
>> +
>> + clk_rate = clk_get_rate(i2c_dev->clk);
>> + val = clk_rate / MHZ_TO_HZ * t->mul_ccr;
>
> Is the rounding done right? Again please describe the hardware in a
> comment.
Ok I will use DIV_ROUND_UP here and add a comment from datasheet
>
>> + if (val < t->min_ccr)
>> + val = t->min_ccr;
>> + ccr |= STM32F4_I2C_CCR_CCR(val);
>> +
>> + if (t->duty)
>> + ccr |= STM32F4_I2C_CCR_FS | STM32F4_I2C_CCR_DUTY;
>> +
>> + writel_relaxed(ccr, i2c_dev->base + STM32F4_I2C_CCR);
>> +}
>> +[...]
>> +
>> +static int stm32f4_i2c_wait_free_bus(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + u32 status;
>> + int ret;
>> +
>> + ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F4_I2C_SR2,
>> + status,
>> + !(status & STM32F4_I2C_SR2_BUSY),
>> + 10, 1000);
>> + if (ret) {
>> + dev_err(i2c_dev->dev, "bus not free\n");
>> + ret = -EBUSY;
>
> I'm not sure if "bus not free" deserves an error message. Wolfram?
>
>> + }
>> +
>> + return ret;
>> +}
>> +
>> +[...]
>> +static void stm32f4_i2c_read_msg(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> + u32 rbuf;
>> +
>> + rbuf = readl_relaxed(i2c_dev->base + STM32F4_I2C_DR);
>> + *msg->buf++ = (u8)rbuf & 0xff;
>
> unneeded cast (or unneeded & 0xff).
Ok thanks
>
>> + msg->count--;
>> +}
>> +
>> +[...]
>> +/**
>> + * stm32f4_i2c_handle_read() - Handle FIFO empty interrupt in case of read
>> + * @i2c_dev: Controller's private data
>> + */
>> +static void stm32f4_i2c_handle_read(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> + void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
>> +
>> + switch (msg->count) {
>> + case 1:
>> + stm32f4_i2c_disable_it(i2c_dev);
>> + stm32f4_i2c_read_msg(i2c_dev);
>> + complete(&i2c_dev->complete);
>> + break;
>> + case 2:
>> + case 3:
>> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
>> + break;
>> + default:
>> + stm32f4_i2c_read_msg(i2c_dev);
>> + }
>
> It looks wrong that you don't call stm32f4_i2c_read_msg if msg->count is
> 2 or 3. I guess that's because these cases are handled in
> stm32f4_i2c_handle_rx_btf? Maybe you can simplify the logic a bit?
stm32f4_i2c_handle_read is called when RXNE bit is set due to new data
present in DR register.
stm32f4_i2c_handle_rx_btf is called when BTF bit is set.
This bit is set when there is new data in shift register whereas data
in DR register has not been read yet.
The datasheet requires to wait for BTF bit for 2 byte reception and
for the 3 last bytes to be read for N bytes reception (with N > 2)
That's why, in these cases (2 and 3), I clear the ITBUF interrupt in
order to not be preempted again for RXNE event as I know that I have
to wait for BTF event.
So, this is not a wrong case but I will add a comment to explain that.
>
>> +}
>> +
>> +/**
>> + * stm32f4_i2c_handle_rx_btf() - Handle byte transfer finished interrupt
>> + * in case of read
>> + * @i2c_dev: Controller's private data
>> + */
>> +static void stm32f4_i2c_handle_rx_btf(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> + void __iomem *reg;
>> + u32 mask;
>> + int i;
>> +
>> + switch (msg->count) {
>
> I don't understand why the handling depends on the number of messages.
Please see my above comment
>
>> + case 2:
>> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> + /* Generate STOP or REPSTART */
>
> I stumbled about "REPSTART" and would spell it out as "repeated Start".
Ok
>
>> + if (msg->stop)
>> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
>> + else
>> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
>> +
>> + /* Read two last data bytes */
>> + for (i = 2; i > 0; i--)
>> + stm32f4_i2c_read_msg(i2c_dev);
>> +
>> + /* Disable EVT and ERR interrupt */
>> + reg = i2c_dev->base + STM32F4_I2C_CR2;
>> + mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
>> + stm32f4_i2c_clr_bits(reg, mask);
>> +
>> + complete(&i2c_dev->complete);
>> + break;
>> + case 3:
>> + /* Enable ACK and read data */
>> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> + stm32f4_i2c_read_msg(i2c_dev);
>> + break;
>> + default:
>> + stm32f4_i2c_read_msg(i2c_dev);
>> + }
>> +}
>> +
>> +/**
>> + * stm32f4_i2c_handle_rx_addr() - Handle address matched interrupt in case of
>> + * master receiver
>> + * @i2c_dev: Controller's private data
>> + */
>> +static void stm32f4_i2c_handle_rx_addr(struct stm32f4_i2c_dev *i2c_dev)
>> +{
>> + struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
>> + void __iomem *reg;
>> +
>> + switch (msg->count) {
>> + case 0:
>> + stm32f4_i2c_terminate_xfer(i2c_dev);
>> + /* Clear ADDR flag */
>> + readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> + break;
>> + case 1:
>> + /*
>> + * Single byte reception:
>> + * Enable NACK, clear ADDR flag and generate STOP or RepSTART
>> + */
>> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> + if (msg->stop)
>> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
>> + else
>> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
>> + break;
>> + case 2:
>> + /*
>> + * 2-byte reception:
>> + * Enable NACK and PEC Position Ack and clear ADDR flag
>
> What is PEC?
PEC stands for Packet Error Checking.
This feature is used is SMbus mode in order to guarantee data
integrity during an I2C transaction thanks to packet error code
comparaison.
The POS bit is used in reception to indicate that the next byte
received in the shift register will be ACK by hardware.
So, this is a wrong comment I would say POS ACK and I will fix it in
the next version.
>
>> + */
>> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> + stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
>> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_POS);
>> + readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> + break;
>> +
>> + default:
>> + /* N-byte reception: Enable ACK and clear ADDR flag */
>> + reg = i2c_dev->base + STM32F4_I2C_CR1;
>> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_ACK);
>> + readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> + break;
>> + }
>> +}
>> +
>> +/**
>> + * stm32f4_i2c_isr_event() - Interrupt routine for I2C bus event
>> + * @irq: interrupt number
>> + * @data: Controller's private data
>> + */
>> +static irqreturn_t stm32f4_i2c_isr_event(int irq, void *data)
>> +{
>> +[...]
>> + real_status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
>
> s/real_status/status/ ?
Ok. Thanks
>
>> +
>> + if (!(real_status & possible_status)) {
>> + dev_dbg(i2c_dev->dev,
>> + "spurious evt it (status=0x%08x, ien=0x%08x)\n",
>> + real_status, ien);
>
> s/it/irq/
Ok. Thanks
>
>> + return IRQ_NONE;
>> + }
>> +
>> + /* Use __fls() to check error bits first */
>> + flag = __fls(real_status & possible_status);
>
> If you get several events reported you only handle a single one. Is this
> effective?
You are right, if several events occur, I will execute this irq
routines for each event.
I will rework this in the next version. Thanks
>
>> + switch (1 << flag) {
>> + case STM32F4_I2C_SR1_SB:
>> + stm32f4_i2c_write_byte(i2c_dev, msg->addr);
>> + break;
>> +
>> + case STM32F4_I2C_SR1_ADDR:
>> + if (msg->addr & I2C_M_RD)
>> + stm32f4_i2c_handle_rx_addr(i2c_dev);
>> + else
>> + readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
>> +
>> + /* Enable ITBUF interrupts */
>
> What is ITBUF?
ITBUF is an interrupt generated when RxNE or TxE flag is set
>
>> + reg = i2c_dev->base + STM32F4_I2C_CR2;
>> + stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
>> + break;
>> +
>> + case STM32F4_I2C_SR1_BTF:
>> + if (msg->addr & I2C_M_RD)
>> + stm32f4_i2c_handle_rx_btf(i2c_dev);
>> + else
>> + stm32f4_i2c_handle_write(i2c_dev);
>> + break;
>> +
>> + case STM32F4_I2C_SR1_TXE:
>> + stm32f4_i2c_handle_write(i2c_dev);
>> + break;
>> +
>> + case STM32F4_I2C_SR1_RXNE:
>> + stm32f4_i2c_handle_read(i2c_dev);
>> + break;
>> +
>> + default:
>> + dev_err(i2c_dev->dev,
>> + "evt it unhandled: status=0x%08x)\n", real_status);
>
> s/it/irq/
ok
>
>> + return IRQ_NONE;
>> + }
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> +[...]
>> +static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev,
>> + struct i2c_msg *msg, bool is_first,
>> + bool is_last)
>> +{
>> +[...]
>> + /* Enable ITEVT and ITERR interrupts */
>
> This comment isn't helpful. Mentioning their meaning would be great
> instead.
ok I will add it (ITEVT = event interrupt and ITERR = error interrupt)
>
>> +[...]
>> +static int stm32f4_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
>> + int num)
>> +{
>> + struct stm32f4_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
>> + int ret, i;
>> +
>> + ret = clk_enable(i2c_dev->clk);
>> + if (ret) {
>> + dev_err(i2c_dev->dev, "Failed to enable clock\n");
>> + return ret;
>> + }
>> +
>> + stm32f4_i2c_hw_config(i2c_dev);
>> +
>> + for (i = 0; i < num && !ret; i++)
>> + ret = stm32f4_i2c_xfer_msg(i2c_dev, &msgs[i], i == 0,
>> + i == num - 1);
>> +
>> + clk_disable(i2c_dev->clk);
>> +
>> + return (ret < 0) ? ret : i;
>
> using num instead of i would be a bit more obvious.
ok
>
>> +static int stm32f4_i2c_probe(struct platform_device *pdev)
>> +{
>> +[...]
>> + i2c_dev->speed = STM32F4_I2C_SPEED_STANDARD;
>> + ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
>> + if ((!ret) && (clk_rate == 400000))
>> + i2c_dev->speed = STM32F4_I2C_SPEED_FAST;
>
> I'd use
>
> if (!ret && clk_rate >= 400000)
> i2c_dev->speed = STM32F4_I2C_SPEED_FAST;
>
> . That's less parenthesis and a more robust selection of the bus
> frequency.
ok
>
>> +
>> + i2c_dev->dev = &pdev->dev;
>> +
>> + ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_event,
>> + NULL, stm32f4_i2c_isr_event,
>> + IRQF_ONESHOT, pdev->name, i2c_dev);
>> + if (ret) {
>> + dev_err(&pdev->dev, "Failed to request irq %i\n",
>> + i2c_dev->irq_error);
>
> That's wrong. Requesting irq_event failed.
Ok Thanks.
>
>> + goto clk_free;
>> + }
>> +
>> + ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_error,
>> + NULL, stm32f4_i2c_isr_error,
>> + IRQF_ONESHOT, pdev->name, i2c_dev);
>> + if (ret) {
>> + dev_err(&pdev->dev, "Failed to request irq %i\n",
>> + i2c_dev->irq_error);
>> + goto clk_free;
>
> It would also be nice to know for which type of irq this failed. I.e.
> please point out if this is the error irq or the event irq in the
> message. Ditto for checking the return type of irq_of_parse_and_map.
Ok I will fix it in the next version.
>
>> + }
>> +
>> + adap = &i2c_dev->adap;
>> + i2c_set_adapdata(adap, i2c_dev);
>> + snprintf(adap->name, sizeof(adap->name), "STM32 I2C(%pa)", &res->start);
>> + adap->owner = THIS_MODULE;
>> + adap->timeout = 2 * HZ;
>> + adap->retries = 0;
>> + adap->algo = &stm32f4_i2c_algo;
>> + adap->dev.parent = &pdev->dev;
>> + adap->dev.of_node = pdev->dev.of_node;
>> +
>> + init_completion(&i2c_dev->complete);
>> +
>> + ret = i2c_add_adapter(adap);
>> + if (ret)
>> + goto clk_free;
>> +
>> + platform_set_drvdata(pdev, i2c_dev);
>> +
>> + dev_info(i2c_dev->dev, "STM32F4 I2C driver initialized\n");
>
> This is wrong. The driver is bound now to a device, not initialized.
Ok I will replaced initialized by registered. Thanks.
>
>> +static const struct of_device_id stm32f4_i2c_match[] = {
>> + { .compatible = "st,stm32f4-i2c", },
>> + {},
>> +};
>> +MODULE_DEVICE_TABLE(of, stm32f4_i2c_match);
>> +
>> +static struct platform_driver stm32f4_i2c_driver = {
>> + .driver = {
>> + .name = "stm32f4-i2c",
>> + .of_match_table = stm32f4_i2c_match,
>
> Is this needed?
Without of_match_table, I could not match an I2C device instance from
DT with this driver.
So maybe, there is a misunderstanding.
Could you please clarify your question ?
>
>> + },
>> + .probe = stm32f4_i2c_probe,
>> + .remove = stm32f4_i2c_remove,
>> +};
>
> Best regards
> Uwe
>
> --
> Pengutronix e.K. | Uwe Kleine-König |
> Industrial Linux Solutions | http://www.pengutronix.de/ |
Thanks again
Best regards,
Cedric
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2] i2c: designware: Cleaning and comment style fixes.
From: Peter Rosin @ 2016-12-15 15:17 UTC (permalink / raw)
To: Luis Oliveira, wsa, robh+dt, mark.rutland, jarkko.nikula,
andriy.shevchenko, mika.westerberg, linux-i2c, devicetree,
linux-kernel
Cc: Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
In-Reply-To: <d7b5a22ce09539c2af343c21ca69675bef6a0a10.1481812563.git.lolivei@synopsys.com>
On 2016-12-15 15:38, Luis Oliveira wrote:
> diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
> index 26250b425e2f..3cb81fca7738 100644
> --- a/drivers/i2c/busses/i2c-designware-core.h
> +++ b/drivers/i2c/busses/i2c-designware-core.h
> @@ -36,7 +36,7 @@
> #define DW_IC_CON_SPEED_FAST 0x4
> #define DW_IC_CON_SPEED_HIGH 0x6
> #define DW_IC_CON_SPEED_MASK 0x6
> -#define DW_IC_CON_10BITADDR_MASTER 0x10
> +#define DW_IC_CON_10BITADDR_MASTER 0x10
How is this an improvement?
Cheers,
peda
^ permalink raw reply
* Re: [PATCH 1/1] of: of_reserved_mem: Ensure cma reserved region not cross the low/high memory
From: Jason Liu @ 2016-12-15 15:10 UTC (permalink / raw)
To: Rob Herring
Cc: Laura Abbott, Jason Liu, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Frank Rowand
In-Reply-To: <CAL_JsqJygJK_VmXKad8n63-jLH+G_xQ=NwX8JVmE=xSuYMof=Q@mail.gmail.com>
2016-12-15 21:54 GMT+08:00 Rob Herring <robh+dt@kernel.org>:
> On Wed, Dec 14, 2016 at 4:21 PM, Laura Abbott <labbott@redhat.com> wrote:
>> On 12/14/2016 12:45 PM, Rob Herring wrote:
>>> On Wed, Nov 23, 2016 at 5:37 AM, Jason Liu <jason.hui.liu@nxp.com> wrote:
>>>> Need ensure the cma reserved region not cross the low/high memory boundary
>>>> when using the dynamic allocation methond through device-tree, otherwise,
>>>> kernel will fail to boot up when cma reserved region cross how/high mem.
>>>
>>> The kernel command line code setting CMA already deals with this. Why
>>> don't we just call the CMA code (cma_declare_contiguous) to deal with
>>> this?
>>>
>>> Rob
>>>
>>
>> That was proposed in the first version[1] but I think this is a generic
>> problem not specific to CMA. Even non-CMA reservations trying to span
>> zones could cause problems so the devicetree allocation code should
>> restrict reservations to a single zone.
>
> Fair enough, but that's not what this patch does. It's only for CMA.
I'm only certain that the CMA reservation from the device-tree is not
working now.
and if you guys think that this is not only the CMA but also other
non-CMA reservations
should also have this restriction on the device-tree method. I can
change the patch the patch
as the followings.
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 366d8c3..7b8857d 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -31,11 +31,15 @@ static int reserved_mem_count;
#if defined(CONFIG_HAVE_MEMBLOCK)
#include <linux/memblock.h>
-int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
- phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
- phys_addr_t *res_base)
+int __init __weak early_init_dt_alloc_reserved_memory_arch(unsigned long node,
+ phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end,
+ bool nomap, phys_addr_t *res_base)
{
phys_addr_t base;
+ phys_addr_t highmem_start;
+
+ highmem_start = __pa(high_memory - 1) + 1;
+
/*
* We use __memblock_alloc_base() because memblock_alloc_base()
* panic()s on allocation failure.
@@ -53,15 +57,29 @@ int __init __weak
early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
return -ENOMEM;
}
+ /*
+ * Sanity check for the reserved region:If the reserved region
+ * crosses the low/high memory boundary, try to fix it up and then
+ * fall back to allocate region from the low mememory space.
+ */
+
+ if (base < highmem_start && (base + size) > highmem_start) {
+ memblock_free(base, size);
+ base = memblock_alloc_range(size, align, start,
+ highmem_start, MEMBLOCK_NONE);
+ if (!base)
+ return -ENOMEM;
+ }
+
if you guys have good idea, please share or post your patch. This is
really an issue
that reserve memory from the device-tree is broken.
>
> Rob
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox