diff --git a/config/kernel/linux-sun50i-dev.config b/config/kernel/linux-sun50i-dev.config index 3817be67ea..c295246feb 100644 --- a/config/kernel/linux-sun50i-dev.config +++ b/config/kernel/linux-sun50i-dev.config @@ -2442,6 +2442,7 @@ CONFIG_THERMAL_EMULATION=y # # ACPI INT340X thermal drivers # +CONFIG_SUN8I_THS=y CONFIG_WATCHDOG=y CONFIG_WATCHDOG_CORE=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -2623,6 +2624,7 @@ CONFIG_REGULATOR_QCOM_SPMI=y # CONFIG_REGULATOR_S2MPA01 is not set CONFIG_REGULATOR_S2MPS11=y # CONFIG_REGULATOR_S5M8767 is not set +CONFIG_REGULATOR_SY8106A=y # CONFIG_REGULATOR_TPS51632 is not set # CONFIG_REGULATOR_TPS62360 is not set # CONFIG_REGULATOR_TPS65023 is not set @@ -3608,13 +3610,7 @@ CONFIG_SUNXI_CCU_NKMP=y CONFIG_SUNXI_CCU_NM=y CONFIG_SUNXI_CCU_MP=y CONFIG_SUN50I_A64_CCU=y -# CONFIG_SUN5I_CCU is not set -# CONFIG_SUN6I_A31_CCU is not set -# CONFIG_SUN8I_A23_CCU is not set -# CONFIG_SUN8I_A33_CCU is not set CONFIG_SUN8I_H3_CCU=y -# CONFIG_SUN8I_V3S_CCU is not set -# CONFIG_SUN9I_A80_CCU is not set CONFIG_SUN8I_R_CCU=y # diff --git a/patch/kernel/sun50i-dev/add-h3-h5-THS.patch b/patch/kernel/sun50i-dev/add-h3-h5-THS.patch new file mode 100644 index 0000000000..deeee383a1 --- /dev/null +++ b/patch/kernel/sun50i-dev/add-h3-h5-THS.patch @@ -0,0 +1,340 @@ +From d622c59b1a71f9e5e20663fae693b268fcb2d39b Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 25 Jun 2016 21:51:05 +0200 +Subject: [PATCH] thermal: sun8i_ths: Add support for the thermal sensor on + Allwinner H3 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds support for the sun8i thermal sensor on +Allwinner H3 SoC. + +Signed-off-by: Ondřej Jirman +--- + drivers/thermal/Kconfig | 7 ++ + drivers/thermal/Makefile | 1 + + drivers/thermal/sun8i_ths.c | 239 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 247 insertions(+) + create mode 100644 drivers/thermal/sun8i_ths.c + +diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig +index 776b3439..d46d97b 100644 +--- a/drivers/thermal/Kconfig ++++ b/drivers/thermal/Kconfig +@@ -392,6 +392,13 @@ config MTK_THERMAL + Enable this option if you want to have support for thermal management + controller present in Mediatek SoCs + ++config SUN8I_THS ++ tristate "Thermal sensor driver for Allwinner H3" ++ depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) ++ depends on OF ++ help ++ Enable this to support thermal reporting on some newer Allwinner SoCs. ++ + menu "Texas Instruments thermal drivers" + depends on ARCH_HAS_BANDGAP || COMPILE_TEST + depends on HAS_IOMEM +diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile +index 7adae20..2480dc5 100644 +--- a/drivers/thermal/Makefile ++++ b/drivers/thermal/Makefile +@@ -58,3 +58,4 @@ obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o + obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o + obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o + obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o ++obj-$(CONFIG_SUN8I_THS) += sun8i_ths.o +diff --git a/drivers/thermal/sun8i_ths.c b/drivers/thermal/sun8i_ths.c +new file mode 100644 +index 0000000..cfe7d10 +--- /dev/null ++++ b/drivers/thermal/sun8i_ths.c +@@ -0,0 +1,239 @@ ++/* ++ * Thermal sensor driver for Allwinner H3 SoC ++ * ++ * Copyright (C) 2016 Ondřej Jirman ++ * Based on the work of Josef Gajdusek ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define THS_H3_CTRL0 0x00 ++#define THS_H3_CTRL2 0x40 ++#define THS_H3_INT_CTRL 0x44 ++#define THS_H3_STAT 0x48 ++#define THS_H3_FILTER 0x70 ++#define THS_H3_CDATA 0x74 ++#define THS_H3_DATA 0x80 ++ ++#define THS_H3_CTRL0_SENSOR_ACQ0(x) (x) ++#define THS_H3_CTRL2_SENSE_EN BIT(0) ++#define THS_H3_CTRL2_SENSOR_ACQ1(x) ((x) << 16) ++#define THS_H3_INT_CTRL_DATA_IRQ_EN BIT(8) ++#define THS_H3_INT_CTRL_THERMAL_PER(x) ((x) << 12) ++#define THS_H3_STAT_DATA_IRQ_STS BIT(8) ++#define THS_H3_FILTER_TYPE(x) ((x) << 0) ++#define THS_H3_FILTER_EN BIT(2) ++ ++#define THS_H3_CLK_IN 40000000 /* Hz */ ++#define THS_H3_DATA_PERIOD 330 /* ms */ ++ ++#define THS_H3_FILTER_TYPE_VALUE 2 /* average over 2^(n+1) samples */ ++#define THS_H3_FILTER_DIV (1 << (THS_H3_FILTER_TYPE_VALUE + 1)) ++#define THS_H3_INT_CTRL_THERMAL_PER_VALUE \ ++ (THS_H3_DATA_PERIOD * (THS_H3_CLK_IN / 1000) / THS_H3_FILTER_DIV / 4096 - 1) ++#define THS_H3_CTRL0_SENSOR_ACQ0_VALUE 0x3f /* 16us */ ++#define THS_H3_CTRL2_SENSOR_ACQ1_VALUE 0x3f ++ ++struct sun8i_ths_data { ++ struct reset_control *reset; ++ struct clk *clk; ++ struct clk *busclk; ++ void __iomem *regs; ++ struct thermal_zone_device *tzd; ++ u32 temp; ++}; ++ ++static int sun8i_ths_get_temp(void *_data, int *out) ++{ ++ struct sun8i_ths_data *data = _data; ++ ++ if (data->temp == 0) ++ return -EBUSY; ++ ++ /* Formula and parameters from the Allwinner 3.4 kernel */ ++ *out = 217000 - (int)((data->temp * 1000000) / 8253); ++ return 0; ++} ++ ++static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data) ++{ ++ struct sun8i_ths_data *data = _data; ++ ++ writel(THS_H3_STAT_DATA_IRQ_STS, data->regs + THS_H3_STAT); ++ ++ data->temp = readl(data->regs + THS_H3_DATA); ++ if (data->temp) ++ thermal_zone_device_update(data->tzd, THERMAL_EVENT_TEMP_SAMPLE); ++ ++ return IRQ_HANDLED; ++} ++ ++static void sun8i_ths_h3_init(struct sun8i_ths_data *data) ++{ ++ writel(THS_H3_CTRL0_SENSOR_ACQ0(THS_H3_CTRL0_SENSOR_ACQ0_VALUE), ++ data->regs + THS_H3_CTRL0); ++ writel(THS_H3_FILTER_EN | THS_H3_FILTER_TYPE(THS_H3_FILTER_TYPE_VALUE), ++ data->regs + THS_H3_FILTER); ++ writel(THS_H3_CTRL2_SENSOR_ACQ1(THS_H3_CTRL2_SENSOR_ACQ1_VALUE) | ++ THS_H3_CTRL2_SENSE_EN, ++ data->regs + THS_H3_CTRL2); ++ writel(THS_H3_INT_CTRL_THERMAL_PER(THS_H3_INT_CTRL_THERMAL_PER_VALUE) | ++ THS_H3_INT_CTRL_DATA_IRQ_EN, ++ data->regs + THS_H3_INT_CTRL); ++} ++ ++static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = { ++ .get_temp = sun8i_ths_get_temp, ++}; ++ ++static int sun8i_ths_probe(struct platform_device *pdev) ++{ ++ struct sun8i_ths_data *data; ++ struct resource *res; ++ int ret; ++ int irq; ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "no memory resources defined\n"); ++ return -EINVAL; ++ } ++ ++ data->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(data->regs)) { ++ ret = PTR_ERR(data->regs); ++ dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret); ++ return ret; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq); ++ return irq; ++ } ++ ++ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ++ sun8i_ths_irq_thread, IRQF_ONESHOT, ++ dev_name(&pdev->dev), data); ++ if (ret) ++ return ret; ++ ++ data->busclk = devm_clk_get(&pdev->dev, "ahb"); ++ if (IS_ERR(data->busclk)) { ++ ret = PTR_ERR(data->busclk); ++ dev_err(&pdev->dev, "failed to get ahb clk: %d\n", ret); ++ return ret; ++ } ++ ++ data->clk = devm_clk_get(&pdev->dev, "ths"); ++ if (IS_ERR(data->clk)) { ++ ret = PTR_ERR(data->clk); ++ dev_err(&pdev->dev, "failed to get ths clk: %d\n", ret); ++ return ret; ++ } ++ ++ data->reset = devm_reset_control_get(&pdev->dev, "ahb"); ++ if (IS_ERR(data->reset)) { ++ ret = PTR_ERR(data->reset); ++ dev_err(&pdev->dev, "failed to get reset: %d\n", ret); ++ return ret; ++ } ++ ++ ret = reset_control_deassert(data->reset); ++ if (ret) { ++ dev_err(&pdev->dev, "reset deassert failed: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(data->busclk); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret); ++ goto err_assert_reset; ++ } ++ ++ ret = clk_prepare_enable(data->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret); ++ goto err_disable_bus; ++ } ++ ++ ret = clk_set_rate(data->clk, THS_H3_CLK_IN); ++ if (ret) ++ goto err_disable_ths; ++ ++ data->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, data, ++ &sun8i_ths_thermal_ops); ++ if (IS_ERR(data->tzd)) { ++ ret = PTR_ERR(data->tzd); ++ dev_err(&pdev->dev, "failed to register thermal zone: %d\n", ++ ret); ++ goto err_disable_ths; ++ } ++ ++ sun8i_ths_h3_init(data); ++ ++ platform_set_drvdata(pdev, data); ++ return 0; ++ ++err_disable_ths: ++ clk_disable_unprepare(data->clk); ++err_disable_bus: ++ clk_disable_unprepare(data->busclk); ++err_assert_reset: ++ reset_control_assert(data->reset); ++ return ret; ++} ++ ++static int sun8i_ths_remove(struct platform_device *pdev) ++{ ++ struct sun8i_ths_data *data = platform_get_drvdata(pdev); ++ ++ reset_control_assert(data->reset); ++ clk_disable_unprepare(data->clk); ++ clk_disable_unprepare(data->busclk); ++ return 0; ++} ++ ++static const struct of_device_id sun8i_ths_id_table[] = { ++ { .compatible = "allwinner,sun8i-h3-ths", }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, sun8i_ths_id_table); ++ ++static struct platform_driver sun8i_ths_driver = { ++ .probe = sun8i_ths_probe, ++ .remove = sun8i_ths_remove, ++ .driver = { ++ .name = "sun8i_ths", ++ .of_match_table = sun8i_ths_id_table, ++ }, ++}; ++ ++module_platform_driver(sun8i_ths_driver); ++ ++MODULE_AUTHOR("Ondřej Jirman "); ++MODULE_DESCRIPTION("Thermal sensor driver for Allwinner H3 SoC"); ++MODULE_LICENSE("GPL v2"); +From 71010833320fd2ffded4e7d6ee5e49902f6827c7 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 25 Jun 2016 00:02:04 +0200 +Subject: [PATCH] dt-bindings: document sun8i_ths - H3 thermal sensor driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds the binding documentation for the +sun8i_ths driver. This is a driver for thermal sensor +found in Allwinner H3 SoC. + +Signed-off-by: Ondřej Jirman +--- + .../devicetree/bindings/thermal/sun8i-ths.txt | 24 ++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + create mode 100644 Documentation/devicetree/bindings/thermal/sun8i-ths.txt + +diff --git a/Documentation/devicetree/bindings/thermal/sun8i-ths.txt b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt +new file mode 100644 +index 0000000..ba12881 +--- /dev/null ++++ b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt +@@ -0,0 +1,24 @@ ++* Thermal sensor driver for Allwinner H3 SoC ++ ++Required properties: ++- compatible : "allwinner,sun8i-h3-ths" ++- reg : Address range of the thermal sensor registers ++- resets : Must contain phandles to reset controls matching the entries ++ of the names ++- reset-names : Must include the name "ahb" ++- clocks : Must contain phandles to clock controls matching the entries ++ of the names ++- clock-names : Must contain "ahb" for the bus gate and "ths" for the THS ++ clock ++ ++Example: ++ths: ths@01c25000 { ++ #thermal-sensor-cells = <0>; ++ compatible = "allwinner,sun8i-h3-ths"; ++ reg = <0x01c25000 0x400>; ++ interrupts = ; ++ resets = <&bus_rst 136>; ++ reset-names = "ahb"; ++ clocks = <&bus_gates 72>, <&ths_clk>; ++ clock-names = "ahb", "ths"; ++}; diff --git a/patch/kernel/sun50i-dev/add-overlay-compilation-support.patch b/patch/kernel/sun50i-dev/add-overlay-compilation-support.patch index 361e9f86a7..9285f6ccbd 100644 --- a/patch/kernel/sun50i-dev/add-overlay-compilation-support.patch +++ b/patch/kernel/sun50i-dev/add-overlay-compilation-support.patch @@ -97,7 +97,17 @@ diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 0a07f901..5ccd3490 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib -@@ -312,6 +312,23 @@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ +@@ -278,6 +278,9 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \ + # --------------------------------------------------------------------------- + DTC ?= $(objtree)/scripts/dtc/dtc + ++# Overlay support ++DTC_FLAGS += -@ -Wno-unit_address_format ++ + # Disable noisy checks by default + ifeq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),) + DTC_FLAGS += -Wno-unit_address_vs_reg +@@ -312,6 +315,23 @@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ $(obj)/%.dtb: $(src)/%.dts FORCE $(call if_changed_dep,dtc) diff --git a/patch/kernel/sun50i-dev/add-sy8106a-driver.patch b/patch/kernel/sun50i-dev/add-sy8106a-driver.patch new file mode 100644 index 0000000000..3dd61f3c48 --- /dev/null +++ b/patch/kernel/sun50i-dev/add-sy8106a-driver.patch @@ -0,0 +1,271 @@ +From 5bcc6066f1dfbbef937ca8584a0fba44bb1468f0 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 25 Jun 2016 02:13:50 +0200 +Subject: [PATCH] regulator: SY8106A regulator driver + +SY8106A is I2C attached single output voltage regulator +made by Silergy. + +Signed-off-by: Ondrej Jirman +--- + drivers/regulator/Kconfig | 8 +- + drivers/regulator/Makefile | 2 +- + drivers/regulator/sy8106a-regulator.c | 167 ++++++++++++++++++++++++++++++++++ + 3 files changed, 175 insertions(+), 2 deletions(-) + create mode 100644 drivers/regulator/sy8106a-regulator.c + +diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig +index be06eb2..9c4b51e 100644 +--- a/drivers/regulator/Kconfig ++++ b/drivers/regulator/Kconfig +@@ -727,6 +727,13 @@ config REGULATOR_STW481X_VMMC + This driver supports the internal VMMC regulator in the STw481x + PMIC chips. + ++config REGULATOR_SY8106A ++ tristate "Silergy SY8106A" ++ depends on I2C && (OF || COMPILE_TEST) ++ select REGMAP_I2C ++ help ++ This driver provides support for SY8106A voltage regulator. ++ + config REGULATOR_TPS51632 + tristate "TI TPS51632 Power Regulator" + depends on I2C +@@ -886,4 +893,3 @@ config REGULATOR_WM8994 + WM8994 CODEC. + + endif +- +diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile +index ef7725e..a829718 100644 +--- a/drivers/regulator/Makefile ++++ b/drivers/regulator/Makefile +@@ -91,6 +91,7 @@ obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o + obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o + obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o + obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o ++obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o + obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o + obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o + obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o +@@ -114,5 +115,4 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o + obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o + obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o + +- + ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG +diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c +new file mode 100644 +index 0000000..7274965 +--- /dev/null ++++ b/drivers/regulator/sy8106a-regulator.c +@@ -0,0 +1,167 @@ ++/* ++ * sy8106a-regulator.c - Regulator device driver for SY8106A ++ * ++ * Copyright (C) 2016 Ondřej Jirman ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SY8106A_REG_VOUT1_SEL 0x01 ++#define SY8106A_REG_VOUT_COM 0x02 ++#define SY8106A_REG_VOUT1_SEL_MASK 0x7f ++#define SY8106A_DISABLE_REG BIT(0) ++#define SY8106A_GO_BIT BIT(7) ++ ++struct sy8106a { ++ struct regulator_dev *rdev; ++ struct regmap *regmap; ++}; ++ ++static const struct regmap_config sy8106a_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++}; ++ ++static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned sel) ++{ ++ /* We use our set_voltage_sel in order to avoid unnecessary I2C chatter, ++ * because the regulator_get_voltage_sel_regmap using apply_bit ++ * would perform 4 unnecessary transfers instead of one, increasing the ++ * chance of error. ++ */ ++ return regmap_write(rdev->regmap, rdev->desc->vsel_reg, ++ sel | SY8106A_GO_BIT); ++} ++ ++static const struct regulator_ops sy8106a_ops = { ++ .is_enabled = regulator_is_enabled_regmap, ++ .set_voltage_sel = sy8106a_set_voltage_sel, ++ .set_voltage_time_sel = regulator_set_voltage_time_sel, ++ .get_voltage_sel = regulator_get_voltage_sel_regmap, ++ .list_voltage = regulator_list_voltage_linear, ++}; ++ ++/* Default limits measured in millivolts and milliamps */ ++#define SY8106A_MIN_MV 680 ++#define SY8106A_MAX_MV 1950 ++#define SY8106A_STEP_MV 10 ++ ++static const struct regulator_desc sy8106a_reg = { ++ .name = "SY8106A", ++ .id = 0, ++ .ops = &sy8106a_ops, ++ .type = REGULATOR_VOLTAGE, ++ .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1, ++ .min_uV = (SY8106A_MIN_MV * 1000), ++ .uV_step = (SY8106A_STEP_MV * 1000), ++ .vsel_reg = SY8106A_REG_VOUT1_SEL, ++ .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK, ++ .enable_reg = SY8106A_REG_VOUT_COM, ++ .enable_mask = SY8106A_DISABLE_REG, ++ .disable_val = SY8106A_DISABLE_REG, ++ .enable_is_inverted = 1, ++ .owner = THIS_MODULE, ++}; ++ ++/* ++ * I2C driver interface functions ++ */ ++static int sy8106a_i2c_probe(struct i2c_client *i2c, ++ const struct i2c_device_id *id) ++{ ++ struct sy8106a *chip; ++ struct device *dev = &i2c->dev; ++ struct regulator_dev *rdev = NULL; ++ struct regulator_config config = { }; ++ unsigned int selector; ++ int error; ++ ++ chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config); ++ if (IS_ERR(chip->regmap)) { ++ error = PTR_ERR(chip->regmap); ++ dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ++ error); ++ return error; ++ } ++ ++ config.dev = &i2c->dev; ++ config.regmap = chip->regmap; ++ config.driver_data = chip; ++ ++ config.of_node = dev->of_node; ++ config.init_data = of_get_regulator_init_data(dev, dev->of_node, &sy8106a_reg); ++ if (!config.init_data) { ++ return -ENOMEM; ++ } ++ ++ /* Probe regulator */ ++ error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, &selector); ++ if (error) { ++ dev_err(&i2c->dev, "Failed to read voltage at probe time: %d\n", error); ++ return error; ++ } ++ ++ rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config); ++ if (IS_ERR(rdev)) { ++ error = PTR_ERR(rdev); ++ dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error); ++ return error; ++ } ++ ++ chip->rdev = rdev; ++ ++ i2c_set_clientdata(i2c, chip); ++ ++ return 0; ++} ++ ++static const struct of_device_id sy8106a_i2c_of_match[] = { ++ { .compatible = "silergy,sy8106a" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match); ++ ++static const struct i2c_device_id sy8106a_i2c_id[] = { ++ { "sy8106a", 0 }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id); ++ ++static struct i2c_driver sy8106a_regulator_driver = { ++ .driver = { ++ .name = "sy8106a", ++ .of_match_table = of_match_ptr(sy8106a_i2c_of_match), ++ }, ++ .probe = sy8106a_i2c_probe, ++ .id_table = sy8106a_i2c_id, ++}; ++ ++module_i2c_driver(sy8106a_regulator_driver); ++ ++MODULE_AUTHOR("Ondřej Jirman "); ++MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A"); ++MODULE_LICENSE("GPL v2"); +From cbbe21d790a5a47e69238ed64d53acd36752d7ae Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 25 Jun 2016 02:20:08 +0200 +Subject: [PATCH] dt-bindings: document SY8106A regulator driver + +This patch adds the binding documentation for the +sy8106a regulator driver. + +Signed-off-by: Ondrej Jirman +--- + .../bindings/regulator/sy8106a-regulator.txt | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + create mode 100644 Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt + +diff --git a/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt +new file mode 100644 +index 0000000..1e623a34 +--- /dev/null ++++ b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt +@@ -0,0 +1,21 @@ ++SY8106A Voltage regulator ++ ++Required properties: ++- compatible: Must be "silergy,sy8106a" ++- reg: I2C slave address - must be <0x65> ++ ++Any property defined as part of the core regulator binding, defined in ++regulator.txt, can also be used. ++ ++Example: ++ ++ sy8106a { ++ compatible = "silergy,sy8106a"; ++ reg = <0x65>; ++ regulator-name = "sy8106a-vdd"; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-ramp-delay = <200>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; diff --git a/patch/kernel/sun50i-dev/clk-ng-fixes.patch b/patch/kernel/sun50i-dev/clk-ng-fixes.patch new file mode 100644 index 0000000000..91f3aa1c2f --- /dev/null +++ b/patch/kernel/sun50i-dev/clk-ng-fixes.patch @@ -0,0 +1,346 @@ +From 8ef4d5e976df3c15453b827e5fdcb4c3fb3598dd Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Fri, 24 Mar 2017 16:33:05 +0800 +Subject: [PATCH] clk: sunxi-ng: use 1 as fallback for minimum multiplier + +A zero multiplier does not make sense for clocks. + +Use 1 as the minimum when a multiplier minimum isn't specified. + +Fixes: 2beaa601c849 ("clk: sunxi-ng: Implement minimum for multipliers") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Maxime Ripard +--- + drivers/clk/sunxi-ng/ccu_nk.c | 8 ++++---- + drivers/clk/sunxi-ng/ccu_nkm.c | 8 ++++---- + drivers/clk/sunxi-ng/ccu_nkmp.c | 4 ++-- + drivers/clk/sunxi-ng/ccu_nm.c | 2 +- + 4 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c +index b9e9b8a..2485bda 100644 +--- a/drivers/clk/sunxi-ng/ccu_nk.c ++++ b/drivers/clk/sunxi-ng/ccu_nk.c +@@ -102,9 +102,9 @@ static long ccu_nk_round_rate(struct clk_hw *hw, unsigned long rate, + if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate *= nk->fixed_post_div; + +- _nk.min_n = nk->n.min; ++ _nk.min_n = nk->n.min ?: 1; + _nk.max_n = nk->n.max ?: 1 << nk->n.width; +- _nk.min_k = nk->k.min; ++ _nk.min_k = nk->k.min ?: 1; + _nk.max_k = nk->k.max ?: 1 << nk->k.width; + + ccu_nk_find_best(*parent_rate, rate, &_nk); +@@ -127,9 +127,9 @@ static int ccu_nk_set_rate(struct clk_hw *hw, unsigned long rate, + if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV) + rate = rate * nk->fixed_post_div; + +- _nk.min_n = nk->n.min; ++ _nk.min_n = nk->n.min ?: 1; + _nk.max_n = nk->n.max ?: 1 << nk->n.width; +- _nk.min_k = nk->k.min; ++ _nk.min_k = nk->k.min ?: 1; + _nk.max_k = nk->k.max ?: 1 << nk->k.width; + + ccu_nk_find_best(parent_rate, rate, &_nk); +diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c +index 71f81e9..cba84af 100644 +--- a/drivers/clk/sunxi-ng/ccu_nkm.c ++++ b/drivers/clk/sunxi-ng/ccu_nkm.c +@@ -109,9 +109,9 @@ static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux, + struct ccu_nkm *nkm = data; + struct _ccu_nkm _nkm; + +- _nkm.min_n = nkm->n.min; ++ _nkm.min_n = nkm->n.min ?: 1; + _nkm.max_n = nkm->n.max ?: 1 << nkm->n.width; +- _nkm.min_k = nkm->k.min; ++ _nkm.min_k = nkm->k.min ?: 1; + _nkm.max_k = nkm->k.max ?: 1 << nkm->k.width; + _nkm.min_m = 1; + _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; +@@ -138,9 +138,9 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long flags; + u32 reg; + +- _nkm.min_n = nkm->n.min; ++ _nkm.min_n = nkm->n.min ?: 1; + _nkm.max_n = nkm->n.max ?: 1 << nkm->n.width; +- _nkm.min_k = nkm->k.min; ++ _nkm.min_k = nkm->k.min ?: 1; + _nkm.max_k = nkm->k.max ?: 1 << nkm->k.width; + _nkm.min_m = 1; + _nkm.max_m = nkm->m.max ?: 1 << nkm->m.width; +diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c +index 488055e..162ff26 100644 +--- a/drivers/clk/sunxi-ng/ccu_nkmp.c ++++ b/drivers/clk/sunxi-ng/ccu_nkmp.c +@@ -116,9 +116,9 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate, + struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw); + struct _ccu_nkmp _nkmp; + +- _nkmp.min_n = nkmp->n.min; ++ _nkmp.min_n = nkmp->n.min ?: 1; + _nkmp.max_n = nkmp->n.max ?: 1 << nkmp->n.width; +- _nkmp.min_k = nkmp->k.min; ++ _nkmp.min_k = nkmp->k.min ?: 1; + _nkmp.max_k = nkmp->k.max ?: 1 << nkmp->k.width; + _nkmp.min_m = 1; + _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width; +diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c +index af71b19..f312c92 100644 +--- a/drivers/clk/sunxi-ng/ccu_nm.c ++++ b/drivers/clk/sunxi-ng/ccu_nm.c +@@ -99,7 +99,7 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, + struct ccu_nm *nm = hw_to_ccu_nm(hw); + struct _ccu_nm _nm; + +- _nm.min_n = nm->n.min; ++ _nm.min_n = nm->n.min ?: 1; + _nm.max_n = nm->n.max ?: 1 << nm->n.width; + _nm.min_m = 1; + _nm.max_m = nm->m.max ?: 1 << nm->m.width; +From bafee6723b1c425dee1c415463b7386ea923d2cd Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Fri, 24 Mar 2017 16:33:06 +0800 +Subject: [PATCH] clk: sunxi-ng: Fix round_rate/set_rate multiplier minimum + mismatch + +In commit 2beaa601c849 ("clk: sunxi-ng: Implement minimum for +multipliers"), the multiplier minimums in the set_rate callback +for NM and NKMP style clocks were not updated. + +This patch fixes them to match their round_rate callbacks. + +Fixes: 2beaa601c849 ("clk: sunxi-ng: Implement minimum for multipliers") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Maxime Ripard +--- + drivers/clk/sunxi-ng/ccu_nkmp.c | 4 ++-- + drivers/clk/sunxi-ng/ccu_nm.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c +index 162ff26..e58c9578 100644 +--- a/drivers/clk/sunxi-ng/ccu_nkmp.c ++++ b/drivers/clk/sunxi-ng/ccu_nkmp.c +@@ -138,9 +138,9 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long flags; + u32 reg; + +- _nkmp.min_n = 1; ++ _nkmp.min_n = nkmp->n.min ?: 1; + _nkmp.max_n = nkmp->n.max ?: 1 << nkmp->n.width; +- _nkmp.min_k = 1; ++ _nkmp.min_k = nkmp->k.min ?: 1; + _nkmp.max_k = nkmp->k.max ?: 1 << nkmp->k.width; + _nkmp.min_m = 1; + _nkmp.max_m = nkmp->m.max ?: 1 << nkmp->m.width; +diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c +index f312c92..5e5e90a 100644 +--- a/drivers/clk/sunxi-ng/ccu_nm.c ++++ b/drivers/clk/sunxi-ng/ccu_nm.c +@@ -122,7 +122,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, + else + ccu_frac_helper_disable(&nm->common, &nm->frac); + +- _nm.min_n = 1; ++ _nm.min_n = nm->n.min ?: 1; + _nm.max_n = nm->n.max ?: 1 << nm->n.width; + _nm.min_m = 1; + _nm.max_m = nm->m.max ?: 1 << nm->m.width; +From 43b883c1d002fa910e88e5776a0c42c733bb151f Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Fri, 24 Mar 2017 16:33:07 +0800 +Subject: [PATCH] clk: sunxi-ng: a80: Fix audio PLL comment not matching actual + code + +We ignore the d1 and d2 dividers in the audio PLL, and force them to +1 (register value 0) at probe time. However the comment preceding the +audio PLL definition says we enforce the default value, which is not +the same. + +Fix the preceding comment to match what we do in code. + +Fixes: b8eb71dcdd08 ("clk: sunxi-ng: Add A80 CCU") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Maxime Ripard +--- + drivers/clk/sunxi-ng/ccu-sun9i-a80.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c +index e13e313..a031bee 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c ++++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c +@@ -70,8 +70,7 @@ static struct ccu_nm pll_c1cpux_clk = { + /* + * The Audio PLL has d1, d2 dividers in addition to the usual N, M + * factors. Since we only need 2 frequencies from this PLL: 22.5792 MHz +- * and 24.576 MHz, ignore them for now. Enforce the default for them, +- * which is d1 = 0, d2 = 1. ++ * and 24.576 MHz, ignore them for now. Enforce d1 = 0 and d2 = 0. + */ + #define SUN9I_A80_PLL_AUDIO_REG 0x008 + +From 9594d638564896ac0f40cfd316e87a55c8d30570 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Tue, 14 Feb 2017 11:35:23 +0800 +Subject: [PATCH] clk: sunxi-ng: gate: Support common pre-dividers + +Some clock gates have a pre-divider between the source input and the +gate itself. A notable example is the HSIC 12 MHz clock found on the +A83T, which has the 24 MHz main oscillator as its input, and a /2 +pre-divider. + +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Maxime Ripard +--- + drivers/clk/sunxi-ng/ccu_gate.c | 47 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c +index 8a81f9d..cd069d5 100644 +--- a/drivers/clk/sunxi-ng/ccu_gate.c ++++ b/drivers/clk/sunxi-ng/ccu_gate.c +@@ -75,8 +75,55 @@ static int ccu_gate_is_enabled(struct clk_hw *hw) + return ccu_gate_helper_is_enabled(&cg->common, cg->enable); + } + ++static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct ccu_gate *cg = hw_to_ccu_gate(hw); ++ unsigned long rate = parent_rate; ++ ++ if (cg->common.features & CCU_FEATURE_ALL_PREDIV) ++ rate /= cg->common.prediv; ++ ++ return rate; ++} ++ ++static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct ccu_gate *cg = hw_to_ccu_gate(hw); ++ int div = 1; ++ ++ if (cg->common.features & CCU_FEATURE_ALL_PREDIV) ++ div = cg->common.prediv; ++ ++ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { ++ unsigned long best_parent = rate; ++ ++ if (cg->common.features & CCU_FEATURE_ALL_PREDIV) ++ best_parent *= div; ++ *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); ++ } ++ ++ return *prate / div; ++} ++ ++static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ /* ++ * We must report success but we can do so unconditionally because ++ * clk_factor_round_rate returns values that ensure this call is a ++ * nop. ++ */ ++ ++ return 0; ++} ++ + const struct clk_ops ccu_gate_ops = { + .disable = ccu_gate_disable, + .enable = ccu_gate_enable, + .is_enabled = ccu_gate_is_enabled, ++ .round_rate = ccu_gate_round_rate, ++ .set_rate = ccu_gate_set_rate, ++ .recalc_rate = ccu_gate_recalc_rate, + }; +From 272bce4ab673fca0e42add73189e559acbf8e0ca Mon Sep 17 00:00:00 2001 +From: Peter Robinson +Date: Thu, 2 Mar 2017 17:43:57 +0000 +Subject: [PATCH] clk: sunxi-ng: tighten SoC deps on explicit AllWinner SoCs + +Tighten the depends on the various AllWinn SoCs so we don't +inadvertantly get clock drivers when we're not wanting them +like 32 bit SoC clocks for 64 bit configs. Ensure there's +still test coverage though. + +Signed-off-by: Peter Robinson +Signed-off-by: Maxime Ripard +--- + drivers/clk/sunxi-ng/Kconfig | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig +index 6b347d4..cf8dc27 100644 +--- a/drivers/clk/sunxi-ng/Kconfig ++++ b/drivers/clk/sunxi-ng/Kconfig +@@ -64,6 +64,7 @@ config SUN50I_A64_CCU + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default ARM64 && ARCH_SUNXI ++ depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST + + config SUN5I_CCU + bool "Support for the Allwinner sun5i family CCM" +@@ -75,6 +76,7 @@ config SUN5I_CCU + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN5I ++ depends on MACH_SUN5I || COMPILE_TEST + + config SUN6I_A31_CCU + bool "Support for the Allwinner A31/A31s CCU" +@@ -86,6 +88,7 @@ config SUN6I_A31_CCU + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN6I ++ depends on MACH_SUN6I || COMPILE_TEST + + config SUN8I_A23_CCU + bool "Support for the Allwinner A23 CCU" +@@ -98,6 +101,7 @@ config SUN8I_A23_CCU + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN8I ++ depends on MACH_SUN8I || COMPILE_TEST + + config SUN8I_A33_CCU + bool "Support for the Allwinner A33 CCU" +@@ -110,6 +114,7 @@ config SUN8I_A33_CCU + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN8I ++ depends on MACH_SUN8I || COMPILE_TEST + + config SUN8I_H3_CCU + bool "Support for the Allwinner H3 CCU" +@@ -121,6 +126,7 @@ config SUN8I_H3_CCU + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN8I || (ARM64 && ARCH_SUNXI) ++ depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST + + config SUN8I_V3S_CCU + bool "Support for the Allwinner V3s CCU" +@@ -132,6 +138,7 @@ config SUN8I_V3S_CCU + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN8I ++ depends on MACH_SUN8I || COMPILE_TEST + + config SUN9I_A80_CCU + bool "Support for the Allwinner A80 CCU" +@@ -143,5 +150,6 @@ config SUN9I_A80_CCU + select SUNXI_CCU_MP + select SUNXI_CCU_PHASE + default MACH_SUN9I ++ depends on MACH_SUN9I || COMPILE_TEST + + endif diff --git a/patch/kernel/sun50i-dev/unresolved/add-h5-a64-simplefb.patch b/patch/kernel/sun50i-dev/unresolved/add-h5-a64-simplefb.patch deleted file mode 100644 index 0e1eb68377..0000000000 --- a/patch/kernel/sun50i-dev/unresolved/add-h5-a64-simplefb.patch +++ /dev/null @@ -1,54 +0,0 @@ -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi -index 495edf5f..c0edd5c2 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi -@@ -45,6 +45,22 @@ - / { - interrupt-parent = <&gic>; - -+ chosen { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ -+ simplefb_hdmi: framebuffer@0 { -+ compatible = "allwinner,simple-framebuffer", -+ "simple-framebuffer"; -+ allwinner,pipeline = "de0-lcd0-hdmi"; -+ clocks = <&ccu CLK_BUS_TCON0>, <&ccu CLK_BUS_DE>, -+ <&ccu CLK_BUS_HDMI>, <&ccu CLK_DE>, -+ <&ccu CLK_TCON0>, <&ccu CLK_HDMI>; -+ status = "disabled"; -+ }; -+ }; -+ - cpus { - #address-cells = <1>; - #size-cells = <0>; -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi -index 100e9b49..e208e005 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi -+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi -@@ -52,6 +52,22 @@ - #address-cells = <1>; - #size-cells = <1>; - -+ chosen { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ -+ simplefb_hdmi: framebuffer@0 { -+ compatible = "allwinner,simple-framebuffer", -+ "simple-framebuffer"; -+ allwinner,pipeline = "de0-lcd0-hdmi"; -+ clocks = <&ccu CLK_BUS_TCON1>, <&ccu CLK_BUS_DE>, -+ <&ccu CLK_BUS_HDMI>, <&ccu CLK_DE>, -+ <&ccu CLK_TCON1>, <&ccu CLK_HDMI>; -+ status = "disabled"; -+ }; -+ }; -+ - cpus { - #address-cells = <1>; - #size-cells = <0>;