From f3ea14c6a243d927c172caf123e9d2ce803fdafc Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 2 Aug 2023 17:19:20 +0800 Subject: [PATCH 001/396] clk: renesas: r9a06g032: Use for_each_compatible_node() Use for_each_compatible_node() instead of open-coding it. Signed-off-by: Yang Yingliang Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230802091920.3270703-1-yangyingliang@huawei.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a06g032-clocks.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c index 55db63c7041a..9a50166c02b9 100644 --- a/drivers/clk/renesas/r9a06g032-clocks.c +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -1269,11 +1269,10 @@ static void r9a06g032_clocks_del_clk_provider(void *data) static void __init r9a06g032_init_h2mode(struct r9a06g032_priv *clocks) { - struct device_node *usbf_np = NULL; + struct device_node *usbf_np; u32 usb; - while ((usbf_np = of_find_compatible_node(usbf_np, NULL, - "renesas,rzn1-usbf"))) { + for_each_compatible_node(usbf_np, NULL, "renesas,rzn1-usbf") { if (of_device_is_available(usbf_np)) break; } From f2af7cb8ac0f825b415b4846a526bddba68807b1 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 8 Sep 2023 17:07:02 -0700 Subject: [PATCH 002/396] clk: asm9620: Remove 'hw' local variable that isn't checked The 'hw' pointer local variable in this function became unused after commit f5290d8e4f0c ("clk: asm9260: use parent index to link the reference clock"). Remove it to silence an unused but set variable warning. drivers/clk/clk-asm9260.c:258:17: warning: variable 'hw' set but not used [-Wunused-but-set-variable] struct clk_hw *hw, *pll_hw; ^ 1 warning generated. Cc: Dmitry Baryshkov Fixes: f5290d8e4f0c ("clk: asm9260: use parent index to link the reference clock") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202309042014.IWERPl09-lkp@intel.com/ Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20230909000703.3478902-1-sboyd@kernel.org --- drivers/clk/clk-asm9260.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c index 8b3c059e19a1..3432c801f1bd 100644 --- a/drivers/clk/clk-asm9260.c +++ b/drivers/clk/clk-asm9260.c @@ -255,7 +255,7 @@ static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = { static void __init asm9260_acc_init(struct device_node *np) { - struct clk_hw *hw, *pll_hw; + struct clk_hw *pll_hw; struct clk_hw **hws; const char *pll_clk = "pll"; struct clk_parent_data pll_parent_data = { .index = 0 }; @@ -283,7 +283,7 @@ static void __init asm9260_acc_init(struct device_node *np) for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) { const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n]; - hw = clk_hw_register_mux_table_parent_data(NULL, mc->name, mc->parent_data, + clk_hw_register_mux_table_parent_data(NULL, mc->name, mc->parent_data, mc->num_parents, mc->flags, base + mc->offset, 0, mc->mask, 0, mc->table, &asm9260_clk_lock); } @@ -292,7 +292,7 @@ static void __init asm9260_acc_init(struct device_node *np) for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) { const struct asm9260_gate_data *gd = &asm9260_mux_gates[n]; - hw = clk_hw_register_gate(NULL, gd->name, + clk_hw_register_gate(NULL, gd->name, gd->parent_name, gd->flags | CLK_SET_RATE_PARENT, base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock); } From 14aaccbd34e93c0bbaaf475d174ece170f10f694 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Thu, 31 Aug 2023 15:36:55 +0300 Subject: [PATCH 003/396] clk: gate: fix comment typo and grammar Change ouput -> output. While at it change also grammatically incorrect "it's" to "its". Signed-off-by: Baruch Siach Link: https://lore.kernel.org/r/d47978a09dd0320f9929a19fa3e829608a02b224.1693485415.git.baruch@tkos.co.il Signed-off-by: Stephen Boyd --- drivers/clk/clk-gate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 64283807600b..68e585a02fd9 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -15,7 +15,7 @@ #include /** - * DOC: basic gatable clock which can gate and ungate it's ouput + * DOC: basic gatable clock which can gate and ungate its output * * Traits of this clock: * prepare - clk_(un)prepare only ensures parent is (un)prepared From eee9cd5d25f1be6120fdf1c90c81324d22b4cc49 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 11 Sep 2023 23:09:28 +0200 Subject: [PATCH 004/396] platform/x86: x86-android-tablets: Add a comment about x86_android_tablet_get_gpiod() Add a comment explaining why the special x86_android_tablet_get_gpiod() helper is necessary for some of the GPIOs used in the x86-android-tablets; and that for normal GPIO lookups this example should not be followed. Signed-off-by: Hans de Goede Reviewed-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20230911210928.264908-1-hdegoede@redhat.com --- drivers/platform/x86/x86-android-tablets/core.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index 8a1f22aaac00..b55957bde034 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -24,6 +24,21 @@ static struct platform_device *x86_android_tablet_device; +/* + * This helper allows getting a gpio_desc *before* the actual device consuming + * the GPIO has been instantiated. This function _must_ only be used to handle + * this special case such as e.g. : + * + * 1. Getting an IRQ from a GPIO for i2c_board_info.irq which is passed to + * i2c_client_new() to instantiate i2c_client-s; or + * 2. Calling desc_to_gpio() to get an old style GPIO number for gpio_keys + * platform_data which still uses old style GPIO numbers. + * + * Since the consuming device has not been instatiated yet a dynamic lookup + * is generated using the special x86_android_tablet dev for dev_id. + * + * For normal GPIO lookups a standard static gpiod_lookup_table _must_ be used. + */ int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id, bool active_low, enum gpiod_flags dflags, struct gpio_desc **desc) From 2c97d3e55b70edf33b6e7f211bab8a748a0a2bcc Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Wed, 30 Aug 2023 15:22:37 +1200 Subject: [PATCH 005/396] platform/x86: asus-wmi: add support for ASUS screenpad Add support for the WMI methods used to turn off and adjust the brightness of the secondary "screenpad" device found on some high-end ASUS laptops like the GX650P series and others. There are some small quirks with this device when considering only the raw WMI methods: 1. The Off method can only switch the device off 2. Changing the brightness turns the device back on 3. To turn the device back on the brightness must be > 1 4. When the device is off the brightness can't be changed (so it is stored by the driver if device is off). 5. Booting with a value of 0 brightness (retained by bios) means the bios will set a value of >0 <15 6. When the device is off it is "unplugged" asus_wmi sets the minimum brightness as 20 in general use, and 60 for booting with values <= min. The ACPI methods are used in a new backlight device named asus_screenpad. Signed-off-by: Luke D. Jones Link: https://lore.kernel.org/r/20230830032237.42987-2-luke@ljones.dev Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-wmi.c | 133 +++++++++++++++++++++ drivers/platform/x86/asus-wmi.h | 1 + include/linux/platform_data/x86/asus-wmi.h | 4 + 3 files changed, 138 insertions(+) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 9f8cea5f9615..928fc74e79b4 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -127,6 +128,10 @@ module_param(fnlock_default, bool, 0444); #define NVIDIA_TEMP_MIN 75 #define NVIDIA_TEMP_MAX 87 +#define ASUS_SCREENPAD_BRIGHT_MIN 20 +#define ASUS_SCREENPAD_BRIGHT_MAX 255 +#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 + static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; static int throttle_thermal_policy_write(struct asus_wmi *); @@ -212,6 +217,7 @@ struct asus_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; + struct backlight_device *screenpad_backlight_device; struct platform_device *platform_device; struct led_classdev wlan_led; @@ -3776,6 +3782,124 @@ static int is_display_toggle(int code) return 0; } +/* Screenpad backlight *******************************************************/ + +static int read_screenpad_backlight_power(struct asus_wmi *asus) +{ + int ret; + + ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); + if (ret < 0) + return ret; + /* 1 == powered */ + return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; +} + +static int read_screenpad_brightness(struct backlight_device *bd) +{ + struct asus_wmi *asus = bl_get_data(bd); + u32 retval; + int err; + + err = read_screenpad_backlight_power(asus); + if (err < 0) + return err; + /* The device brightness can only be read if powered, so return stored */ + if (err == FB_BLANK_POWERDOWN) + return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; + + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); + if (err < 0) + return err; + + return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN; +} + +static int update_screenpad_bl_status(struct backlight_device *bd) +{ + struct asus_wmi *asus = bl_get_data(bd); + int power, err = 0; + u32 ctrl_param; + + power = read_screenpad_backlight_power(asus); + if (power < 0) + return power; + + if (bd->props.power != power) { + if (power != FB_BLANK_UNBLANK) { + /* Only brightness > 0 can power it back on */ + ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, + ctrl_param, NULL); + } else { + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); + } + } else if (power == FB_BLANK_UNBLANK) { + /* Only set brightness if powered on or we get invalid/unsync state */ + ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); + } + + /* Ensure brightness is stored to turn back on with */ + if (err == 0) + asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; + + return err; +} + +static const struct backlight_ops asus_screenpad_bl_ops = { + .get_brightness = read_screenpad_brightness, + .update_status = update_screenpad_bl_status, + .options = BL_CORE_SUSPENDRESUME, +}; + +static int asus_screenpad_init(struct asus_wmi *asus) +{ + struct backlight_device *bd; + struct backlight_properties props; + int err, power; + int brightness = 0; + + power = read_screenpad_backlight_power(asus); + if (power < 0) + return power; + + if (power != FB_BLANK_POWERDOWN) { + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); + if (err < 0) + return err; + } + /* default to an acceptable min brightness on boot if too low */ + if (brightness < ASUS_SCREENPAD_BRIGHT_MIN) + brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ + props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN; + bd = backlight_device_register("asus_screenpad", + &asus->platform_device->dev, asus, + &asus_screenpad_bl_ops, &props); + if (IS_ERR(bd)) { + pr_err("Could not register backlight device\n"); + return PTR_ERR(bd); + } + + asus->screenpad_backlight_device = bd; + asus->driver->screenpad_brightness = brightness; + bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN; + bd->props.power = power; + backlight_update_status(bd); + + return 0; +} + +static void asus_screenpad_exit(struct asus_wmi *asus) +{ + backlight_device_unregister(asus->screenpad_backlight_device); + + asus->screenpad_backlight_device = NULL; +} + /* Fn-lock ********************************************************************/ static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus) @@ -4431,6 +4555,12 @@ static int asus_wmi_add(struct platform_device *pdev) } else if (asus->driver->quirks->wmi_backlight_set_devstate) err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL); + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT)) { + err = asus_screenpad_init(asus); + if (err && err != -ENODEV) + goto fail_screenpad; + } + if (asus_wmi_has_fnlock_key(asus)) { asus->fnlock_locked = fnlock_default; asus_wmi_fnlock_update(asus); @@ -4454,6 +4584,8 @@ fail_wmi_handler: asus_wmi_backlight_exit(asus); fail_backlight: asus_wmi_rfkill_exit(asus); +fail_screenpad: + asus_screenpad_exit(asus); fail_rfkill: asus_wmi_led_exit(asus); fail_leds: @@ -4480,6 +4612,7 @@ static int asus_wmi_remove(struct platform_device *device) asus = platform_get_drvdata(device); wmi_remove_notify_handler(asus->driver->event_guid); asus_wmi_backlight_exit(asus); + asus_screenpad_exit(asus); asus_wmi_input_exit(asus); asus_wmi_led_exit(asus); asus_wmi_rfkill_exit(asus); diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index a478ebfd34df..5fbdd0eafa02 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -57,6 +57,7 @@ struct quirk_entry { struct asus_wmi_driver { int brightness; int panel_power; + int screenpad_brightness; int wlan_ctrl_by_user; const char *name; diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 16e99a1c37fc..63e630276499 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -58,6 +58,10 @@ #define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 #define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */ #define ASUS_WMI_DEVID_LIGHTBAR 0x00050025 +/* This can only be used to disable the screen, not re-enable */ +#define ASUS_WMI_DEVID_SCREENPAD_POWER 0x00050031 +/* Writing a brightness re-enables the screen if disabled */ +#define ASUS_WMI_DEVID_SCREENPAD_LIGHT 0x00050032 #define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018 #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075 From f28992902b17245af042913d6cfd6a1cc100bcaf Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 21:25:04 +0100 Subject: [PATCH 006/396] power: supply: bq256xx: Use i2c_get_match_data() Use i2c_get_match_data() for OF/ID/ACPI match instead of ID lookup by replacing OF/ACPI/ID match data from enum bq256xx_id to struct bq256xx_chip_info. Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230902202505.97609-2-biju.das.jz@bp.renesas.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq256xx_charger.c | 44 +++++++++++++------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c index 82d3cd5ee2f9..fda4286323ee 100644 --- a/drivers/power/supply/bq256xx_charger.c +++ b/drivers/power/supply/bq256xx_charger.c @@ -1702,7 +1702,7 @@ static int bq256xx_probe(struct i2c_client *client) bq->client = client; bq->dev = dev; - bq->chip_info = &bq256xx_chip_info_tbl[id->driver_data]; + bq->chip_info = i2c_get_match_data(client); mutex_init(&bq->lock); @@ -1771,37 +1771,37 @@ static int bq256xx_probe(struct i2c_client *client) } static const struct i2c_device_id bq256xx_i2c_ids[] = { - { "bq25600", BQ25600 }, - { "bq25600d", BQ25600D }, - { "bq25601", BQ25601 }, - { "bq25601d", BQ25601D }, - { "bq25611d", BQ25611D }, - { "bq25618", BQ25618 }, - { "bq25619", BQ25619 }, + { "bq25600", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25600] }, + { "bq25600d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25600D] }, + { "bq25601", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25601] }, + { "bq25601d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25601D] }, + { "bq25611d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25611D] }, + { "bq25618", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25618] }, + { "bq25619", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25619] }, {}, }; MODULE_DEVICE_TABLE(i2c, bq256xx_i2c_ids); static const struct of_device_id bq256xx_of_match[] = { - { .compatible = "ti,bq25600", .data = (void *)BQ25600 }, - { .compatible = "ti,bq25600d", .data = (void *)BQ25600D }, - { .compatible = "ti,bq25601", .data = (void *)BQ25601 }, - { .compatible = "ti,bq25601d", .data = (void *)BQ25601D }, - { .compatible = "ti,bq25611d", .data = (void *)BQ25611D }, - { .compatible = "ti,bq25618", .data = (void *)BQ25618 }, - { .compatible = "ti,bq25619", .data = (void *)BQ25619 }, + { .compatible = "ti,bq25600", .data = &bq256xx_chip_info_tbl[BQ25600] }, + { .compatible = "ti,bq25600d", .data = &bq256xx_chip_info_tbl[BQ25600D] }, + { .compatible = "ti,bq25601", .data = &bq256xx_chip_info_tbl[BQ25601] }, + { .compatible = "ti,bq25601d", .data = &bq256xx_chip_info_tbl[BQ25601D] }, + { .compatible = "ti,bq25611d", .data = &bq256xx_chip_info_tbl[BQ25611D] }, + { .compatible = "ti,bq25618", .data = &bq256xx_chip_info_tbl[BQ25618] }, + { .compatible = "ti,bq25619", .data = &bq256xx_chip_info_tbl[BQ25619] }, { }, }; MODULE_DEVICE_TABLE(of, bq256xx_of_match); static const struct acpi_device_id bq256xx_acpi_match[] = { - { "bq25600", BQ25600 }, - { "bq25600d", BQ25600D }, - { "bq25601", BQ25601 }, - { "bq25601d", BQ25601D }, - { "bq25611d", BQ25611D }, - { "bq25618", BQ25618 }, - { "bq25619", BQ25619 }, + { "bq25600", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25600] }, + { "bq25600d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25600D] }, + { "bq25601", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25601] }, + { "bq25601d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25601D] }, + { "bq25611d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25611D] }, + { "bq25618", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25618] }, + { "bq25619", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25619] }, {}, }; MODULE_DEVICE_TABLE(acpi, bq256xx_acpi_match); From 02e673e59c3d374924422f74fb229ae4ee6715fc Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 21:25:05 +0100 Subject: [PATCH 007/396] power: supply: bq256xx: Some cleanups Some cleanups: * Remove trailing comma in the terminator entry for OF/ID/ACPI table. * Drop a space from terminator entry for OF table. Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230902202505.97609-3-biju.das.jz@bp.renesas.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq256xx_charger.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c index fda4286323ee..474201815a27 100644 --- a/drivers/power/supply/bq256xx_charger.c +++ b/drivers/power/supply/bq256xx_charger.c @@ -1778,7 +1778,7 @@ static const struct i2c_device_id bq256xx_i2c_ids[] = { { "bq25611d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25611D] }, { "bq25618", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25618] }, { "bq25619", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25619] }, - {}, + {} }; MODULE_DEVICE_TABLE(i2c, bq256xx_i2c_ids); @@ -1790,7 +1790,7 @@ static const struct of_device_id bq256xx_of_match[] = { { .compatible = "ti,bq25611d", .data = &bq256xx_chip_info_tbl[BQ25611D] }, { .compatible = "ti,bq25618", .data = &bq256xx_chip_info_tbl[BQ25618] }, { .compatible = "ti,bq25619", .data = &bq256xx_chip_info_tbl[BQ25619] }, - { }, + {} }; MODULE_DEVICE_TABLE(of, bq256xx_of_match); @@ -1802,7 +1802,7 @@ static const struct acpi_device_id bq256xx_acpi_match[] = { { "bq25611d", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25611D] }, { "bq25618", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25618] }, { "bq25619", (kernel_ulong_t)&bq256xx_chip_info_tbl[BQ25619] }, - {}, + {} }; MODULE_DEVICE_TABLE(acpi, bq256xx_acpi_match); From a7d79bcc8364483b0d39c944d72b425cf06eccc5 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 31 Aug 2023 18:12:35 +0100 Subject: [PATCH 008/396] power: supply: sbs-battery: Make similar OF and ID table Make similar OF and ID table to extend support for ID match using i2c_match_data(). Currently it works only for OF match tables as the field is wrong for ID match. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230831171235.58477-1-biju.das.jz@bp.renesas.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/sbs-battery.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index cdfc8466d129..a6c204c08232 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -1135,7 +1135,7 @@ static int sbs_probe(struct i2c_client *client) if (!chip) return -ENOMEM; - chip->flags = (u32)(uintptr_t)device_get_match_data(&client->dev); + chip->flags = (uintptr_t)i2c_get_match_data(client); chip->client = client; psy_cfg.of_node = client->dev.of_node; psy_cfg.drv_data = chip; @@ -1253,9 +1253,9 @@ static SIMPLE_DEV_PM_OPS(sbs_pm_ops, sbs_suspend, NULL); #endif static const struct i2c_device_id sbs_id[] = { - { "bq20z65", 0 }, - { "bq20z75", 0 }, - { "sbs-battery", 1 }, + { "bq20z65", SBS_FLAGS_TI_BQ20ZX5 }, + { "bq20z75", SBS_FLAGS_TI_BQ20ZX5 }, + { "sbs-battery", 0 }, {} }; MODULE_DEVICE_TABLE(i2c, sbs_id); From 8e511f42ac9cdab84c692bcd0f9e0c55c75b1856 Mon Sep 17 00:00:00 2001 From: Andrew Halaney Date: Thu, 17 Aug 2023 16:41:57 -0500 Subject: [PATCH 009/396] power: reset: nvmem-reboot-mode: quiet some device deferrals Some errors are being logged that are really due to deferrals, which is confusing to users. Use dev_err_probe() to handle when to log at error level versus debug. This also has the added bonuses of logging to devices_deferred and printing the error value. Signed-off-by: Andrew Halaney Reviewed-by: Brian Masney Tested-by: Brian Masney Link: https://lore.kernel.org/r/20230817214218.638846-1-ahalaney@redhat.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/nvmem-reboot-mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c index e229308d43e2..41530b70cfc4 100644 --- a/drivers/power/reset/nvmem-reboot-mode.c +++ b/drivers/power/reset/nvmem-reboot-mode.c @@ -45,8 +45,8 @@ static int nvmem_reboot_mode_probe(struct platform_device *pdev) nvmem_rbm->cell = devm_nvmem_cell_get(&pdev->dev, "reboot-mode"); if (IS_ERR(nvmem_rbm->cell)) { - dev_err(&pdev->dev, "failed to get the nvmem cell reboot-mode\n"); - return PTR_ERR(nvmem_rbm->cell); + return dev_err_probe(&pdev->dev, PTR_ERR(nvmem_rbm->cell), + "failed to get the nvmem cell reboot-mode\n"); } ret = devm_reboot_mode_register(&pdev->dev, &nvmem_rbm->reboot); From 70c81c37cf252798bef5fe047a57129ff6a2b31b Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 7 Aug 2023 21:19:47 +0800 Subject: [PATCH 010/396] power: reset: st-poweroff: use builtin_platform_driver() to simplify code The st_reset_init() doesn't do anything special, so it can use the builtin_platform_driver() macro to eliminate boilerplate code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230807131951.3443880-2-yangyingliang@huawei.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/st-poweroff.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c index 56ba21873882..85175066beea 100644 --- a/drivers/power/reset/st-poweroff.c +++ b/drivers/power/reset/st-poweroff.c @@ -100,12 +100,7 @@ static struct platform_driver st_reset_driver = { }, }; -static int __init st_reset_init(void) -{ - return platform_driver_register(&st_reset_driver); -} - -device_initcall(st_reset_init); +builtin_platform_driver(st_reset_driver); MODULE_AUTHOR("Christophe Kerello "); MODULE_DESCRIPTION("STMicroelectronics Power off Restart driver"); From 4e579a5c68d88b340776c2270659de111f8923f6 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 7 Aug 2023 21:19:48 +0800 Subject: [PATCH 011/396] power: reset: msm: use builtin_platform_driver() to simplify code The msm_restart_init() doesn't do anything special, so it can use the builtin_platform_driver() macro to eliminate boilerplate code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230807131951.3443880-3-yangyingliang@huawei.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/msm-poweroff.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index b9a401bd280b..d96d248a6e25 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -59,9 +59,4 @@ static struct platform_driver msm_restart_driver = { .of_match_table = of_match_ptr(of_msm_restart_match), }, }; - -static int __init msm_restart_init(void) -{ - return platform_driver_register(&msm_restart_driver); -} -device_initcall(msm_restart_init); +builtin_platform_driver(msm_restart_driver); From 764db16149ec6128da548aac54a16b651461fbc8 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 7 Aug 2023 21:19:49 +0800 Subject: [PATCH 012/396] power: reset: xgene-reboot: use builtin_platform_driver() to simplify code The xgene_reboot_init() doesn't do anything special, so it can use the builtin_platform_driver() macro to eliminate boilerplate code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230807131951.3443880-4-yangyingliang@huawei.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/xgene-reboot.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c index 3260bd93158e..c2e5a99940d3 100644 --- a/drivers/power/reset/xgene-reboot.c +++ b/drivers/power/reset/xgene-reboot.c @@ -87,9 +87,4 @@ static struct platform_driver xgene_reboot_driver = { .of_match_table = xgene_reboot_of_match, }, }; - -static int __init xgene_reboot_init(void) -{ - return platform_driver_register(&xgene_reboot_driver); -} -device_initcall(xgene_reboot_init); +builtin_platform_driver(xgene_reboot_driver); From 6a7f7f27e2c766f36c6bd948a5de91ca2703c2a4 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 7 Aug 2023 21:19:50 +0800 Subject: [PATCH 013/396] power: reset: axxia-reset: use builtin_platform_driver() to simplify code The axxia_reset_init() doesn't do anything special, so it can use the builtin_platform_driver() macro to eliminate boilerplate code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230807131951.3443880-5-yangyingliang@huawei.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/axxia-reset.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/power/reset/axxia-reset.c b/drivers/power/reset/axxia-reset.c index f7b40be5d6b6..24946766760c 100644 --- a/drivers/power/reset/axxia-reset.c +++ b/drivers/power/reset/axxia-reset.c @@ -80,9 +80,4 @@ static struct platform_driver axxia_reset_driver = { .of_match_table = of_match_ptr(of_axxia_reset_match), }, }; - -static int __init axxia_reset_init(void) -{ - return platform_driver_register(&axxia_reset_driver); -} -device_initcall(axxia_reset_init); +builtin_platform_driver(axxia_reset_driver); From 5b69b5f209b7a6d21329b14b533b390fff6895d5 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Mon, 7 Aug 2023 21:19:51 +0800 Subject: [PATCH 014/396] power: reset: syscon-poweroff: use builtin_platform_driver() to simplify code The syscon_poweroff_register() doesn't do anything special, so it can use the builtin_platform_driver() macro to eliminate boilerplate code. Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20230807131951.3443880-6-yangyingliang@huawei.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/syscon-poweroff.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c index 430d440d55c6..270f289239a5 100644 --- a/drivers/power/reset/syscon-poweroff.c +++ b/drivers/power/reset/syscon-poweroff.c @@ -93,9 +93,4 @@ static struct platform_driver syscon_poweroff_driver = { .of_match_table = syscon_poweroff_of_match, }, }; - -static int __init syscon_poweroff_register(void) -{ - return platform_driver_register(&syscon_poweroff_driver); -} -device_initcall(syscon_poweroff_register); +builtin_platform_driver(syscon_poweroff_driver); From 6eca10a1c2e5c5edaf92d5a9d1bcf415456369b7 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Mon, 31 Jul 2023 19:39:59 +0800 Subject: [PATCH 015/396] power: supply: 88pm860x_battery: fix the return value handle for platform_get_irq() There is no possible for platform_get_irq() to return 0, and the return value of platform_get_irq() is more sensible to show the error reason. Signed-off-by: Ruan Jinjie Link: https://lore.kernel.org/r/20230731113959.1957820-1-ruanjinjie@huawei.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/88pm860x_battery.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/88pm860x_battery.c b/drivers/power/supply/88pm860x_battery.c index f3f3f8cd1a7f..34619c4d4ece 100644 --- a/drivers/power/supply/88pm860x_battery.c +++ b/drivers/power/supply/88pm860x_battery.c @@ -921,12 +921,12 @@ static int pm860x_battery_probe(struct platform_device *pdev) return -ENOMEM; info->irq_cc = platform_get_irq(pdev, 0); - if (info->irq_cc <= 0) - return -EINVAL; + if (info->irq_cc < 0) + return info->irq_cc; info->irq_batt = platform_get_irq(pdev, 1); - if (info->irq_batt <= 0) - return -EINVAL; + if (info->irq_batt < 0) + return info->irq_batt; info->chip = chip; info->i2c = From 389405146ca11d24f85b3277121a58f98a926a28 Mon Sep 17 00:00:00 2001 From: Ruan Jinjie Date: Thu, 27 Jul 2023 19:35:50 +0800 Subject: [PATCH 016/396] power: supply: Remove redundant dev_err_probe() for platform_get_irq_byname() There is no need to call the dev_err_probe() function directly to print a custom message when handling an error from platform_get_irq_byname() function as it is going to display an appropriate error message in case of a failure. Signed-off-by: Ruan Jinjie Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Dhruva Gole Link: https://lore.kernel.org/r/20230727113550.2599335-1-ruanjinjie@huawei.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/mt6370-charger.c | 4 +--- drivers/power/supply/qcom_pmi8998_charger.c | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c index f27dae5043f5..571cf00dde07 100644 --- a/drivers/power/supply/mt6370-charger.c +++ b/drivers/power/supply/mt6370-charger.c @@ -849,9 +849,7 @@ static int mt6370_chg_init_irq(struct mt6370_priv *priv) ret = platform_get_irq_byname(to_platform_device(priv->dev), mt6370_chg_irqs[i].name); if (ret < 0) - return dev_err_probe(priv->dev, ret, - "Failed to get irq %s\n", - mt6370_chg_irqs[i].name); + return ret; priv->irq_nums[i] = ret; ret = devm_request_threaded_irq(priv->dev, ret, NULL, diff --git a/drivers/power/supply/qcom_pmi8998_charger.c b/drivers/power/supply/qcom_pmi8998_charger.c index 10f4dd0caca1..8acf63ee6897 100644 --- a/drivers/power/supply/qcom_pmi8998_charger.c +++ b/drivers/power/supply/qcom_pmi8998_charger.c @@ -915,8 +915,7 @@ static int smb2_init_irq(struct smb2_chip *chip, int *irq, const char *name, irqnum = platform_get_irq_byname(to_platform_device(chip->dev), name); if (irqnum < 0) - return dev_err_probe(chip->dev, irqnum, - "Couldn't get irq %s byname\n", name); + return irqnum; rc = devm_request_threaded_irq(chip->dev, irqnum, NULL, handler, IRQF_ONESHOT, name, chip); From c06a65ac4e4945478f46654920f5af1be1cf384e Mon Sep 17 00:00:00 2001 From: Przemyslaw Chwiala Date: Thu, 20 Jul 2023 14:31:02 +0200 Subject: [PATCH 017/396] power: supply: max17042_battery: Do not use CONFIG_ prefix in regular C code Using CONFIG_ prefix for macros is not a good practice. Use CONFIG_ prefix in Kconfig only. Signed-off-by: Przemyslaw Chwiala Reviewed-by: Krzysztof Kozlowski Reviewed-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20230720123102.154699-1-przemekchwiala@gmail.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/max17042_battery.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 17ac2ab78c4e..e7d37e422c3f 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -36,7 +36,7 @@ #define STATUS_BR_BIT (1 << 15) /* Interrupt mask bits */ -#define CONFIG_ALRT_BIT_ENBL (1 << 2) +#define CFG_ALRT_BIT_ENBL (1 << 2) #define VFSOC0_LOCK 0x0000 #define VFSOC0_UNLOCK 0x0080 @@ -1116,8 +1116,8 @@ static int max17042_probe(struct i2c_client *client) chip); if (!ret) { regmap_update_bits(chip->regmap, MAX17042_CONFIG, - CONFIG_ALRT_BIT_ENBL, - CONFIG_ALRT_BIT_ENBL); + CFG_ALRT_BIT_ENBL, + CFG_ALRT_BIT_ENBL); max17042_set_soc_threshold(chip, 1); } else { client->irq = 0; From 716293381a0f9a400d0010628a9ba4354c2bea40 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 1 Sep 2023 14:00:55 +0200 Subject: [PATCH 018/396] dt-bindings: power: syscon-poweroff: get regmap from parent node Just like syscon-reboot device, the syscon-poweroff is supposed to be a child of syscon node, thus we can take the same approach as syscon-poweroff: deprecate the 'regmap' field in favor of taking it from the parent's node. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230901120057.47018-1-krzysztof.kozlowski@linaro.org Signed-off-by: Sebastian Reichel --- .../bindings/power/reset/syscon-poweroff.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/power/reset/syscon-poweroff.yaml b/Documentation/devicetree/bindings/power/reset/syscon-poweroff.yaml index 3412fe7e1e80..d342b113fca2 100644 --- a/Documentation/devicetree/bindings/power/reset/syscon-poweroff.yaml +++ b/Documentation/devicetree/bindings/power/reset/syscon-poweroff.yaml @@ -15,6 +15,9 @@ description: |+ defined by the register map pointed by syscon reference plus the offset with the value and mask defined in the poweroff node. Default will be little endian mode, 32 bit access only. + The SYSCON register map is normally retrieved from the parental dt-node. So + the SYSCON poweroff node should be represented as a sub-node of a "syscon", + "simple-mfd" node. properties: compatible: @@ -30,7 +33,10 @@ properties: regmap: $ref: /schemas/types.yaml#/definitions/phandle - description: Phandle to the register map node. + deprecated: true + description: + Phandle to the register map node. This property is deprecated in favor of + the syscon-poweroff node being a child of a system controller node. value: $ref: /schemas/types.yaml#/definitions/uint32 @@ -38,7 +44,6 @@ properties: required: - compatible - - regmap - offset additionalProperties: false @@ -56,7 +61,6 @@ examples: - | poweroff { compatible = "syscon-poweroff"; - regmap = <®mapnode>; offset = <0x0>; mask = <0x7a>; }; From 6f9c8a1338d90d150767331d4fab051fb8abdba5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 1 Sep 2023 14:00:56 +0200 Subject: [PATCH 019/396] power: reset: syscon-poweroff: simplify pdev->dev usage Make the probe() code a bit simpler and shorter by storing all the '&pdev->dev' as 'dev'. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230901120057.47018-2-krzysztof.kozlowski@linaro.org Signed-off-by: Sebastian Reichel --- drivers/power/reset/syscon-poweroff.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c index 270f289239a5..9ef7eef4c979 100644 --- a/drivers/power/reset/syscon-poweroff.c +++ b/drivers/power/reset/syscon-poweroff.c @@ -32,23 +32,24 @@ static void syscon_poweroff(void) static int syscon_poweroff_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int mask_err, value_err; - map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap"); + map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap"); if (IS_ERR(map)) { - dev_err(&pdev->dev, "unable to get syscon"); + dev_err(dev, "unable to get syscon"); return PTR_ERR(map); } - if (of_property_read_u32(pdev->dev.of_node, "offset", &offset)) { - dev_err(&pdev->dev, "unable to read 'offset'"); + if (of_property_read_u32(dev->of_node, "offset", &offset)) { + dev_err(dev, "unable to read 'offset'"); return -EINVAL; } - value_err = of_property_read_u32(pdev->dev.of_node, "value", &value); - mask_err = of_property_read_u32(pdev->dev.of_node, "mask", &mask); + value_err = of_property_read_u32(dev->of_node, "value", &value); + mask_err = of_property_read_u32(dev->of_node, "mask", &mask); if (value_err && mask_err) { - dev_err(&pdev->dev, "unable to read 'value' and 'mask'"); + dev_err(dev, "unable to read 'value' and 'mask'"); return -EINVAL; } @@ -62,7 +63,7 @@ static int syscon_poweroff_probe(struct platform_device *pdev) } if (pm_power_off) { - dev_err(&pdev->dev, "pm_power_off already claimed for %ps", + dev_err(dev, "pm_power_off already claimed for %ps", pm_power_off); return -EBUSY; } From 92bbb93aaaefe14c01eac18df46f8260ee4c2825 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 1 Sep 2023 14:00:57 +0200 Subject: [PATCH 020/396] power: reset: syscon-poweroff: get regmap from parent node Just like syscon-reboot device, the syscon-poweroff is supposed to be a child of syscon node, thus we can take the same approach as syscon-poweroff: deprecate the 'regmap' field in favor of taking it from the parent's node. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230901120057.47018-3-krzysztof.kozlowski@linaro.org Signed-off-by: Sebastian Reichel --- drivers/power/reset/syscon-poweroff.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/syscon-poweroff.c b/drivers/power/reset/syscon-poweroff.c index 9ef7eef4c979..c3aab7f59345 100644 --- a/drivers/power/reset/syscon-poweroff.c +++ b/drivers/power/reset/syscon-poweroff.c @@ -37,8 +37,11 @@ static int syscon_poweroff_probe(struct platform_device *pdev) map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap"); if (IS_ERR(map)) { - dev_err(dev, "unable to get syscon"); - return PTR_ERR(map); + map = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(map)) { + dev_err(dev, "unable to get syscon"); + return PTR_ERR(map); + } } if (of_property_read_u32(dev->of_node, "offset", &offset)) { From ef2730fb8122ff90747ee79261c2a9fd35032e17 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 21:05:17 +0100 Subject: [PATCH 021/396] power: supply: bq2515x: Simpilfy bq2515x_read_properties() and probe() Add struct bq2515x_info and replace device_id->info in struct bq2515x_device. Simpilfy bq2515x_read_properties() and probe() by adding struct bq2425x_chip_info as match data for OF/ID tables and use i2c_get_match_data for retrieving match data instead of ID lookup. Drop enum bq2515x_id as there is no user. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230902200518.91585-2-biju.das.jz@bp.renesas.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq2515x_charger.c | 61 ++++++++++++-------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c index 1dbacc9b015d..ada4532fda45 100644 --- a/drivers/power/supply/bq2515x_charger.c +++ b/drivers/power/supply/bq2515x_charger.c @@ -147,9 +147,14 @@ struct bq2515x_init_data { int iprechg; }; -enum bq2515x_id { - BQ25150, - BQ25155, +/** + * struct bq2515x_info - + * @regmap_config: register map config + * @ilim: input current limit + */ +struct bq2515x_info { + const struct regmap_config *regmap_config; + int ilim; }; /** @@ -164,8 +169,8 @@ enum bq2515x_id { * @ac_detect_gpio: power good (PG) pin * @ce_gpio: charge enable (CE) pin * + * @info: device info * @model_name: string value describing device model - * @device_id: value of device_id * @mains_online: boolean value indicating power supply online * * @init_data: charger initialization data structure @@ -181,8 +186,8 @@ struct bq2515x_device { struct gpio_desc *ac_detect_gpio; struct gpio_desc *ce_gpio; + const struct bq2515x_info *info; char model_name[I2C_NAME_SIZE]; - int device_id; bool mains_online; struct bq2515x_init_data init_data; @@ -998,16 +1003,8 @@ static int bq2515x_read_properties(struct bq2515x_device *bq2515x) ret = device_property_read_u32(bq2515x->dev, "input-current-limit-microamp", &bq2515x->init_data.ilim); - if (ret) { - switch (bq2515x->device_id) { - case BQ25150: - bq2515x->init_data.ilim = BQ25150_DEFAULT_ILIM_UA; - break; - case BQ25155: - bq2515x->init_data.ilim = BQ25155_DEFAULT_ILIM_UA; - break; - } - } + if (ret) + bq2515x->init_data.ilim = bq2515x->info->ilim; bq2515x->ac_detect_gpio = devm_gpiod_get_optional(bq2515x->dev, "ac-detect", GPIOD_IN); @@ -1094,19 +1091,9 @@ static int bq2515x_probe(struct i2c_client *client) strncpy(bq2515x->model_name, id->name, I2C_NAME_SIZE); - bq2515x->device_id = id->driver_data; - - switch (bq2515x->device_id) { - case BQ25150: - bq2515x->regmap = devm_regmap_init_i2c(client, - &bq25150_regmap_config); - break; - case BQ25155: - bq2515x->regmap = devm_regmap_init_i2c(client, - &bq25155_regmap_config); - break; - } - + bq2515x->info = i2c_get_match_data(client); + bq2515x->regmap = devm_regmap_init_i2c(client, + bq2515x->info->regmap_config); if (IS_ERR(bq2515x->regmap)) { dev_err(dev, "failed to allocate register map\n"); return PTR_ERR(bq2515x->regmap); @@ -1139,16 +1126,26 @@ static int bq2515x_probe(struct i2c_client *client) return 0; } +static const struct bq2515x_info bq25150 = { + .regmap_config = &bq25150_regmap_config, + .ilim = BQ25150_DEFAULT_ILIM_UA, +}; + +static const struct bq2515x_info bq25155 = { + .regmap_config = &bq25155_regmap_config, + .ilim = BQ25155_DEFAULT_ILIM_UA, +}; + static const struct i2c_device_id bq2515x_i2c_ids[] = { - { "bq25150", BQ25150, }, - { "bq25155", BQ25155, }, + { "bq25150", (kernel_ulong_t)&bq25150 }, + { "bq25155", (kernel_ulong_t)&bq25155 }, {}, }; MODULE_DEVICE_TABLE(i2c, bq2515x_i2c_ids); static const struct of_device_id bq2515x_of_match[] = { - { .compatible = "ti,bq25150", }, - { .compatible = "ti,bq25155", }, + { .compatible = "ti,bq25150", .data = &bq25150 }, + { .compatible = "ti,bq25155", .data = &bq25155 }, { }, }; MODULE_DEVICE_TABLE(of, bq2515x_of_match); From ab907d99d5d4e40ba638b6a27940d59fcb2ad24d Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 21:05:18 +0100 Subject: [PATCH 022/396] power: supply: bq2515x: Cleanup OF/ID table terminators Some cleanups: * Remove trailing comma in the terminator entry for OF/ID table. * Drop a space from terminator entry for OF table. Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230902200518.91585-3-biju.das.jz@bp.renesas.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq2515x_charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c index ada4532fda45..49fa6386a509 100644 --- a/drivers/power/supply/bq2515x_charger.c +++ b/drivers/power/supply/bq2515x_charger.c @@ -1139,14 +1139,14 @@ static const struct bq2515x_info bq25155 = { static const struct i2c_device_id bq2515x_i2c_ids[] = { { "bq25150", (kernel_ulong_t)&bq25150 }, { "bq25155", (kernel_ulong_t)&bq25155 }, - {}, + {} }; MODULE_DEVICE_TABLE(i2c, bq2515x_i2c_ids); static const struct of_device_id bq2515x_of_match[] = { { .compatible = "ti,bq25150", .data = &bq25150 }, { .compatible = "ti,bq25155", .data = &bq25155 }, - { }, + {} }; MODULE_DEVICE_TABLE(of, bq2515x_of_match); From 3dc4a291a1b156d3ee9a78672ec950601bd68c1c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 20:33:30 +0100 Subject: [PATCH 023/396] power: supply: bq24257_charger: Make chip type and name in sync Add struct bq2425x_chip_info to make enum bq2425x_chip and it's name in sync and replace chip->info in struct bq24257_device and add struct bq2425x_chip_info as match data for OF/ACPI/ID tables. Simpilfy probe() by replacing acpi_match_device() and id lookup for retrieving match data by using i2c_get_match_data(). Drop bq2425x_chip_name as there is no user and also drop the comment related to syncing chip and name as it is taken care by struct bq2425x_chip_info. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230902193331.83672-2-biju.das.jz@bp.renesas.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24257_charger.c | 70 +++++++++++++------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c index 2852860abf86..188812f4a79b 100644 --- a/drivers/power/supply/bq24257_charger.c +++ b/drivers/power/supply/bq24257_charger.c @@ -35,20 +35,15 @@ #define BQ24257_ILIM_SET_DELAY 1000 /* msec */ -/* - * When adding support for new devices make sure that enum bq2425x_chip and - * bq2425x_chip_name[] always stay in sync! - */ enum bq2425x_chip { BQ24250, BQ24251, BQ24257, }; -static const char *const bq2425x_chip_name[] = { - "bq24250", - "bq24251", - "bq24257", +struct bq2425x_chip_info { + const char *const name; + enum bq2425x_chip chip; }; enum bq24257_fields { @@ -84,7 +79,7 @@ struct bq24257_device { struct device *dev; struct power_supply *charger; - enum bq2425x_chip chip; + const struct bq2425x_chip_info *info; struct regmap *rmap; struct regmap_field *rmap_fields[F_MAX_FIELDS]; @@ -329,7 +324,7 @@ static int bq24257_power_supply_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = bq2425x_chip_name[bq->chip]; + val->strval = bq->info->name; break; case POWER_SUPPLY_PROP_ONLINE: @@ -947,10 +942,8 @@ static int bq24257_fw_probe(struct bq24257_device *bq) static int bq24257_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; - const struct acpi_device_id *acpi_id; struct bq24257_device *bq; int ret; int i; @@ -967,17 +960,9 @@ static int bq24257_probe(struct i2c_client *client) bq->client = client; bq->dev = dev; - if (ACPI_HANDLE(dev)) { - acpi_id = acpi_match_device(dev->driver->acpi_match_table, - &client->dev); - if (!acpi_id) { - dev_err(dev, "Failed to match ACPI device\n"); - return -ENODEV; - } - bq->chip = (enum bq2425x_chip)acpi_id->driver_data; - } else { - bq->chip = (enum bq2425x_chip)id->driver_data; - } + bq->info = i2c_get_match_data(client); + if (!bq->info) + return dev_err_probe(dev, -ENODEV, "Failed to match device\n"); mutex_init(&bq->lock); @@ -1015,7 +1000,7 @@ static int bq24257_probe(struct i2c_client *client) * used for the automatic setting of the input current limit setting so * explicitly disable that feature. */ - if (bq->chip == BQ24250) + if (bq->info->chip == BQ24250) bq->iilimit_autoset_enable = false; if (bq->iilimit_autoset_enable) @@ -1028,7 +1013,7 @@ static int bq24257_probe(struct i2c_client *client) * the PG state. We also use a SW-based approach for all other devices * if the PG pin is either not defined or can't be probed. */ - if (bq->chip != BQ24250) + if (bq->info->chip != BQ24250) bq24257_pg_gpio_probe(bq); if (PTR_ERR(bq->pg) == -EPROBE_DEFER) @@ -1066,7 +1051,7 @@ static int bq24257_probe(struct i2c_client *client) bq24257_irq_handler_thread, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, - bq2425x_chip_name[bq->chip], bq); + bq->info->name, bq); if (ret) { dev_err(dev, "Failed to request IRQ #%d\n", client->irq); return ret; @@ -1132,27 +1117,42 @@ static const struct dev_pm_ops bq24257_pm = { SET_SYSTEM_SLEEP_PM_OPS(bq24257_suspend, bq24257_resume) }; +static const struct bq2425x_chip_info bq24250_info = { + .name = "bq24250", + .chip = BQ24250, +}; + +static const struct bq2425x_chip_info bq24251_info = { + .name = "bq24251", + .chip = BQ24251, +}; + +static const struct bq2425x_chip_info bq24257_info = { + .name = "bq24257", + .chip = BQ24257, +}; + static const struct i2c_device_id bq24257_i2c_ids[] = { - { "bq24250", BQ24250 }, - { "bq24251", BQ24251 }, - { "bq24257", BQ24257 }, + { "bq24250", (kernel_ulong_t)&bq24250_info }, + { "bq24251", (kernel_ulong_t)&bq24251_info }, + { "bq24257", (kernel_ulong_t)&bq24257_info }, {}, }; MODULE_DEVICE_TABLE(i2c, bq24257_i2c_ids); static const struct of_device_id bq24257_of_match[] __maybe_unused = { - { .compatible = "ti,bq24250", }, - { .compatible = "ti,bq24251", }, - { .compatible = "ti,bq24257", }, + { .compatible = "ti,bq24250", &bq24250_info }, + { .compatible = "ti,bq24251", &bq24251_info }, + { .compatible = "ti,bq24257", &bq24257_info }, { }, }; MODULE_DEVICE_TABLE(of, bq24257_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id bq24257_acpi_match[] = { - { "BQ242500", BQ24250 }, - { "BQ242510", BQ24251 }, - { "BQ242570", BQ24257 }, + { "BQ242500", (kernel_ulong_t)&bq24250_info }, + { "BQ242510", (kernel_ulong_t)&bq24251_info }, + { "BQ242570", (kernel_ulong_t)&bq24257_info }, {}, }; MODULE_DEVICE_TABLE(acpi, bq24257_acpi_match); From b92f5e4fccc2ca96241904bb1a4e96547b69163d Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 2 Sep 2023 20:33:31 +0100 Subject: [PATCH 024/396] power: supply: bq24257_charger: Cleanup OF/ID table terminators Some cleanups: * Remove trailing comma in the terminator entry for OF/ID/ACPI table. * Drop a space from terminator entry for OF table. Signed-off-by: Biju Das Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230902193331.83672-3-biju.das.jz@bp.renesas.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24257_charger.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c index 188812f4a79b..801d0d2c5f2e 100644 --- a/drivers/power/supply/bq24257_charger.c +++ b/drivers/power/supply/bq24257_charger.c @@ -1136,7 +1136,7 @@ static const struct i2c_device_id bq24257_i2c_ids[] = { { "bq24250", (kernel_ulong_t)&bq24250_info }, { "bq24251", (kernel_ulong_t)&bq24251_info }, { "bq24257", (kernel_ulong_t)&bq24257_info }, - {}, + {} }; MODULE_DEVICE_TABLE(i2c, bq24257_i2c_ids); @@ -1144,7 +1144,7 @@ static const struct of_device_id bq24257_of_match[] __maybe_unused = { { .compatible = "ti,bq24250", &bq24250_info }, { .compatible = "ti,bq24251", &bq24251_info }, { .compatible = "ti,bq24257", &bq24257_info }, - { }, + {} }; MODULE_DEVICE_TABLE(of, bq24257_of_match); @@ -1153,7 +1153,7 @@ static const struct acpi_device_id bq24257_acpi_match[] = { { "BQ242500", (kernel_ulong_t)&bq24250_info }, { "BQ242510", (kernel_ulong_t)&bq24251_info }, { "BQ242570", (kernel_ulong_t)&bq24257_info }, - {}, + {} }; MODULE_DEVICE_TABLE(acpi, bq24257_acpi_match); #endif From 423c3361855c1e81f1cb91728a2ac5ddfd2cbf16 Mon Sep 17 00:00:00 2001 From: Shravan Kumar Ramani Date: Tue, 5 Sep 2023 08:49:34 -0400 Subject: [PATCH 025/396] platform/mellanox: mlxbf-pmc: Add support for BlueField-3 Add new access mechanism and list of supported events to program and read the counters in BlueField-3. Performance counter blocks being added for BlueField-3 include: - Memory Sub-system (mss) which has counters for monitoring various DRAM and related skylib events - Last level Tile, which has 2 sets of counters (llt, llt_miss) for monitoring Tile and cache metrics Signed-off-by: Shravan Kumar Ramani Reviewed-by: Vadim Pasternak Reviewed-by: David Thompson Link: https://lore.kernel.org/r/d5feee745f6bfd163e0c361e300d4b2ef1d72e00.1693917738.git.shravankr@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxbf-pmc.c | 688 ++++++++++++++++++++++++-- 1 file changed, 655 insertions(+), 33 deletions(-) diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c index 2d4bbe99959e..0b427fc24a96 100644 --- a/drivers/platform/mellanox/mlxbf-pmc.c +++ b/drivers/platform/mellanox/mlxbf-pmc.c @@ -30,14 +30,16 @@ #define MLXBF_PMC_EVENT_SET_BF1 0 #define MLXBF_PMC_EVENT_SET_BF2 1 +#define MLXBF_PMC_EVENT_SET_BF3 2 #define MLXBF_PMC_EVENT_INFO_LEN 100 #define MLXBF_PMC_MAX_BLOCKS 30 -#define MLXBF_PMC_MAX_ATTRS 30 +#define MLXBF_PMC_MAX_ATTRS 70 #define MLXBF_PMC_INFO_SZ 4 #define MLXBF_PMC_REG_SIZE 8 #define MLXBF_PMC_L3C_REG_SIZE 4 +#define MLXBF_PMC_TYPE_CRSPACE 2 #define MLXBF_PMC_TYPE_COUNTER 1 #define MLXBF_PMC_TYPE_REGISTER 0 @@ -78,6 +80,16 @@ #define MLXBF_PMC_L3C_PERF_CNT_LOW_VAL GENMASK(31, 0) #define MLXBF_PMC_L3C_PERF_CNT_HIGH_VAL GENMASK(24, 0) +#define MLXBF_PMC_CRSPACE_PERFMON_REG0 0x0 +#define MLXBF_PMC_CRSPACE_PERFSEL_SZ 4 +#define MLXBF_PMC_CRSPACE_PERFSEL0 GENMASK(23, 16) +#define MLXBF_PMC_CRSPACE_PERFSEL1 GENMASK(7, 0) +#define MLXBF_PMC_CRSPACE_PERFMON_REG0_SZ 0x2 +#define MLXBF_PMC_CRSPACE_PERFMON_CTL(n) (n * MLXBF_PMC_CRSPACE_PERFMON_REG0_SZ) +#define MLXBF_PMC_CRSPACE_PERFMON_EN BIT(30) +#define MLXBF_PMC_CRSPACE_PERFMON_CLR BIT(28) +#define MLXBF_PMC_CRSPACE_PERFMON_VAL0(n) (MLXBF_PMC_CRSPACE_PERFMON_CTL(n) + 0xc) + /** * struct mlxbf_pmc_attribute - Structure to hold attribute and block info * for each sysfs entry @@ -124,6 +136,9 @@ struct mlxbf_pmc_block_info { * @pdev: The kernel structure representing the device * @total_blocks: Total number of blocks * @tile_count: Number of tiles in the system + * @llt_enable: Info on enabled LLTs + * @mss_enable: Info on enabled MSSs + * @group_num: Group number assigned to each valid block * @hwmon_dev: Hwmon device for bfperf * @block_name: Block name * @block: Block info @@ -136,6 +151,9 @@ struct mlxbf_pmc_context { struct platform_device *pdev; uint32_t total_blocks; uint32_t tile_count; + uint8_t llt_enable; + uint8_t mss_enable; + uint32_t group_num; struct device *hwmon_dev; const char *block_name[MLXBF_PMC_MAX_BLOCKS]; struct mlxbf_pmc_block_info block[MLXBF_PMC_MAX_BLOCKS]; @@ -260,7 +278,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_ecc_events[] = { { 0x348, "DRAM_ECC_ERROR" }, }; -static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = { +static const struct mlxbf_pmc_events mlxbf_pmc_mss_events_1[] = { { 0x0, "DISABLE" }, { 0xc0, "RXREQ_MSS" }, { 0xc1, "RXDAT_MSS" }, @@ -268,6 +286,164 @@ static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = { { 0xc3, "TXDAT_MSS" }, }; +static const struct mlxbf_pmc_events mlxbf_pmc_mss_events_3[] = { + {0, "SKYLIB_CDN_TX_FLITS"}, + {1, "SKYLIB_DDN_TX_FLITS"}, + {2, "SKYLIB_NDN_TX_FLITS"}, + {3, "SKYLIB_SDN_TX_FLITS"}, + {4, "SKYLIB_UDN_TX_FLITS"}, + {5, "SKYLIB_CDN_RX_FLITS"}, + {6, "SKYLIB_DDN_RX_FLITS"}, + {7, "SKYLIB_NDN_RX_FLITS"}, + {8, "SKYLIB_SDN_RX_FLITS"}, + {9, "SKYLIB_UDN_RX_FLITS"}, + {10, "SKYLIB_CDN_TX_STALL"}, + {11, "SKYLIB_DDN_TX_STALL"}, + {12, "SKYLIB_NDN_TX_STALL"}, + {13, "SKYLIB_SDN_TX_STALL"}, + {14, "SKYLIB_UDN_TX_STALL"}, + {15, "SKYLIB_CDN_RX_STALL"}, + {16, "SKYLIB_DDN_RX_STALL"}, + {17, "SKYLIB_NDN_RX_STALL"}, + {18, "SKYLIB_SDN_RX_STALL"}, + {19, "SKYLIB_UDN_RX_STALL"}, + {20, "SKYLIB_CHI_REQ0_TX_FLITS"}, + {21, "SKYLIB_CHI_DATA0_TX_FLITS"}, + {22, "SKYLIB_CHI_RESP0_TX_FLITS"}, + {23, "SKYLIB_CHI_SNP0_TX_FLITS"}, + {24, "SKYLIB_CHI_REQ1_TX_FLITS"}, + {25, "SKYLIB_CHI_DATA1_TX_FLITS"}, + {26, "SKYLIB_CHI_RESP1_TX_FLITS"}, + {27, "SKYLIB_CHI_SNP1_TX_FLITS"}, + {28, "SKYLIB_CHI_REQ2_TX_FLITS"}, + {29, "SKYLIB_CHI_DATA2_TX_FLITS"}, + {30, "SKYLIB_CHI_RESP2_TX_FLITS"}, + {31, "SKYLIB_CHI_SNP2_TX_FLITS"}, + {32, "SKYLIB_CHI_REQ3_TX_FLITS"}, + {33, "SKYLIB_CHI_DATA3_TX_FLITS"}, + {34, "SKYLIB_CHI_RESP3_TX_FLITS"}, + {35, "SKYLIB_CHI_SNP3_TX_FLITS"}, + {36, "SKYLIB_TLP_REQ_TX_FLITS"}, + {37, "SKYLIB_TLP_RESP_TX_FLITS"}, + {38, "SKYLIB_TLP_META_TX_FLITS"}, + {39, "SKYLIB_AXIS_DATA_TX_FLITS"}, + {40, "SKYLIB_AXIS_CRED_TX_FLITS"}, + {41, "SKYLIB_APB_TX_FLITS"}, + {42, "SKYLIB_VW_TX_FLITS"}, + {43, "SKYLIB_GGA_MSN_W_TX_FLITS"}, + {44, "SKYLIB_GGA_MSN_N_TX_FLITS"}, + {45, "SKYLIB_CR_REQ_TX_FLITS"}, + {46, "SKYLIB_CR_RESP_TX_FLITS"}, + {47, "SKYLIB_MSN_PRNF_TX_FLITS"}, + {48, "SKYLIB_DBG_DATA_TX_FLITS"}, + {49, "SKYLIB_DBG_CRED_TX_FLITS"}, + {50, "SKYLIB_CHI_REQ0_RX_FLITS"}, + {51, "SKYLIB_CHI_DATA0_RX_FLITS"}, + {52, "SKYLIB_CHI_RESP0_RX_FLITS"}, + {53, "SKYLIB_CHI_SNP0_RX_FLITS"}, + {54, "SKYLIB_CHI_REQ1_RX_FLITS"}, + {55, "SKYLIB_CHI_DATA1_RX_FLITS"}, + {56, "SKYLIB_CHI_RESP1_RX_FLITS"}, + {57, "SKYLIB_CHI_SNP1_RX_FLITS"}, + {58, "SKYLIB_CHI_REQ2_RX_FLITS"}, + {59, "SKYLIB_CHI_DATA2_RX_FLITS"}, + {60, "SKYLIB_CHI_RESP2_RX_FLITS"}, + {61, "SKYLIB_CHI_SNP2_RX_FLITS"}, + {62, "SKYLIB_CHI_REQ3_RX_FLITS"}, + {63, "SKYLIB_CHI_DATA3_RX_FLITS"}, + {64, "SKYLIB_CHI_RESP3_RX_FLITS"}, + {65, "SKYLIB_CHI_SNP3_RX_FLITS"}, + {66, "SKYLIB_TLP_REQ_RX_FLITS"}, + {67, "SKYLIB_TLP_RESP_RX_FLITS"}, + {68, "SKYLIB_TLP_META_RX_FLITS"}, + {69, "SKYLIB_AXIS_DATA_RX_FLITS"}, + {70, "SKYLIB_AXIS_CRED_RX_FLITS"}, + {71, "SKYLIB_APB_RX_FLITS"}, + {72, "SKYLIB_VW_RX_FLITS"}, + {73, "SKYLIB_GGA_MSN_W_RX_FLITS"}, + {74, "SKYLIB_GGA_MSN_N_RX_FLITS"}, + {75, "SKYLIB_CR_REQ_RX_FLITS"}, + {76, "SKYLIB_CR_RESP_RX_FLITS"}, + {77, "SKYLIB_MSN_PRNF_RX_FLITS"}, + {78, "SKYLIB_DBG_DATA_RX_FLITS"}, + {79, "SKYLIB_DBG_CRED_RX_FLITS"}, + {80, "SKYLIB_CHI_REQ0_TX_STALL"}, + {81, "SKYLIB_CHI_DATA0_TX_STALL"}, + {82, "SKYLIB_CHI_RESP0_TX_STALL"}, + {83, "SKYLIB_CHI_SNP0_TX_STALL"}, + {84, "SKYLIB_CHI_REQ1_TX_STALL"}, + {85, "SKYLIB_CHI_DATA1_TX_STALL"}, + {86, "SKYLIB_CHI_RESP1_TX_STALL"}, + {87, "SKYLIB_CHI_SNP1_TX_STALL"}, + {88, "SKYLIB_CHI_REQ2_TX_STALL"}, + {89, "SKYLIB_CHI_DATA2_TX_STALL"}, + {90, "SKYLIB_CHI_RESP2_TX_STALL"}, + {91, "SKYLIB_CHI_SNP2_TX_STALL"}, + {92, "SKYLIB_CHI_REQ3_TX_STALL"}, + {93, "SKYLIB_CHI_DATA3_TX_STALL"}, + {94, "SKYLIB_CHI_RESP3_TX_STALL"}, + {95, "SKYLIB_CHI_SNP3_TX_STALL"}, + {96, "SKYLIB_TLP_REQ_TX_STALL"}, + {97, "SKYLIB_TLP_RESP_TX_STALL"}, + {98, "SKYLIB_TLP_META_TX_STALL"}, + {99, "SKYLIB_AXIS_DATA_TX_STALL"}, + {100, "SKYLIB_AXIS_CRED_TX_STALL"}, + {101, "SKYLIB_APB_TX_STALL"}, + {102, "SKYLIB_VW_TX_STALL"}, + {103, "SKYLIB_GGA_MSN_W_TX_STALL"}, + {104, "SKYLIB_GGA_MSN_N_TX_STALL"}, + {105, "SKYLIB_CR_REQ_TX_STALL"}, + {106, "SKYLIB_CR_RESP_TX_STALL"}, + {107, "SKYLIB_MSN_PRNF_TX_STALL"}, + {108, "SKYLIB_DBG_DATA_TX_STALL"}, + {109, "SKYLIB_DBG_CRED_TX_STALL"}, + {110, "SKYLIB_CHI_REQ0_RX_STALL"}, + {111, "SKYLIB_CHI_DATA0_RX_STALL"}, + {112, "SKYLIB_CHI_RESP0_RX_STALL"}, + {113, "SKYLIB_CHI_SNP0_RX_STALL"}, + {114, "SKYLIB_CHI_REQ1_RX_STALL"}, + {115, "SKYLIB_CHI_DATA1_RX_STALL"}, + {116, "SKYLIB_CHI_RESP1_RX_STALL"}, + {117, "SKYLIB_CHI_SNP1_RX_STALL"}, + {118, "SKYLIB_CHI_REQ2_RX_STALL"}, + {119, "SKYLIB_CHI_DATA2_RX_STALL"}, + {120, "SKYLIB_CHI_RESP2_RX_STALL"}, + {121, "SKYLIB_CHI_SNP2_RX_STALL"}, + {122, "SKYLIB_CHI_REQ3_RX_STALL"}, + {123, "SKYLIB_CHI_DATA3_RX_STALL"}, + {124, "SKYLIB_CHI_RESP3_RX_STALL"}, + {125, "SKYLIB_CHI_SNP3_RX_STALL"}, + {126, "SKYLIB_TLP_REQ_RX_STALL"}, + {127, "SKYLIB_TLP_RESP_RX_STALL"}, + {128, "SKYLIB_TLP_META_RX_STALL"}, + {129, "SKYLIB_AXIS_DATA_RX_STALL"}, + {130, "SKYLIB_AXIS_CRED_RX_STALL"}, + {131, "SKYLIB_APB_RX_STALL"}, + {132, "SKYLIB_VW_RX_STALL"}, + {133, "SKYLIB_GGA_MSN_W_RX_STALL"}, + {134, "SKYLIB_GGA_MSN_N_RX_STALL"}, + {135, "SKYLIB_CR_REQ_RX_STALL"}, + {136, "SKYLIB_CR_RESP_RX_STALL"}, + {137, "SKYLIB_MSN_PRNF_RX_STALL"}, + {138, "SKYLIB_DBG_DATA_RX_STALL"}, + {139, "SKYLIB_DBG_CRED_RX_STALL"}, + {140, "SKYLIB_CDN_LOOPBACK_FLITS"}, + {141, "SKYLIB_DDN_LOOPBACK_FLITS"}, + {142, "SKYLIB_NDN_LOOPBACK_FLITS"}, + {143, "SKYLIB_SDN_LOOPBACK_FLITS"}, + {144, "SKYLIB_UDN_LOOPBACK_FLITS"}, + {145, "HISTOGRAM_HISTOGRAM_BIN0"}, + {146, "HISTOGRAM_HISTOGRAM_BIN1"}, + {147, "HISTOGRAM_HISTOGRAM_BIN2"}, + {148, "HISTOGRAM_HISTOGRAM_BIN3"}, + {149, "HISTOGRAM_HISTOGRAM_BIN4"}, + {150, "HISTOGRAM_HISTOGRAM_BIN5"}, + {151, "HISTOGRAM_HISTOGRAM_BIN6"}, + {152, "HISTOGRAM_HISTOGRAM_BIN7"}, + {153, "HISTOGRAM_HISTOGRAM_BIN8"}, + {154, "HISTOGRAM_HISTOGRAM_BIN9"}, +}; + static const struct mlxbf_pmc_events mlxbf_pmc_hnf_events[] = { { 0x0, "DISABLE" }, { 0x45, "HNF_REQUESTS" }, @@ -429,6 +605,260 @@ static const struct mlxbf_pmc_events mlxbf_pmc_l3c_events[] = { { 0x2b, "ANY_REJECT_BANK1" }, }; +static const struct mlxbf_pmc_events mlxbf_pmc_llt_events[] = { + {0, "HNF0_CYCLES"}, + {1, "HNF0_REQS_RECEIVED"}, + {2, "HNF0_REQS_PROCESSED"}, + {3, "HNF0_DIR_HIT"}, + {4, "HNF0_DIR_MISS"}, + {5, "HNF0_DIR_RD_ALLOC"}, + {6, "HNF0_DIR_WR_ALLOC"}, + {7, "HNF0_DIR_VICTIM"}, + {8, "HNF0_CL_HAZARD"}, + {9, "HNF0_ALL_HAZARD"}, + {10, "HNF0_PIPE_STALLS"}, + {11, "HNF0_MEM_READS"}, + {12, "HNF0_MEM_WRITES"}, + {13, "HNF0_MEM_ACCESS"}, + {14, "HNF0_DCL_READ"}, + {15, "HNF0_DCL_INVAL"}, + {16, "HNF0_CHI_RXDAT"}, + {17, "HNF0_CHI_RXRSP"}, + {18, "HNF0_CHI_TXDAT"}, + {19, "HNF0_CHI_TXRSP"}, + {20, "HNF0_CHI_TXSNP"}, + {21, "HNF0_DCT_SNP"}, + {22, "HNF0_SNP_FWD_DATA"}, + {23, "HNF0_SNP_FWD_RSP"}, + {24, "HNF0_SNP_RSP"}, + {25, "HNF0_EXCL_FULL"}, + {26, "HNF0_EXCL_WRITE_F"}, + {27, "HNF0_EXCL_WRITE_S"}, + {28, "HNF0_EXCL_WRITE"}, + {29, "HNF0_EXCL_READ"}, + {30, "HNF0_REQ_BUF_EMPTY"}, + {31, "HNF0_ALL_MAFS_BUSY"}, + {32, "HNF0_TXDAT_NO_LCRD"}, + {33, "HNF0_TXSNP_NO_LCRD"}, + {34, "HNF0_TXRSP_NO_LCRD"}, + {35, "HNF0_TXREQ_NO_LCRD"}, + {36, "HNF0_WRITE"}, + {37, "HNF0_READ"}, + {38, "HNF0_ACCESS"}, + {39, "HNF0_MAF_N_BUSY"}, + {40, "HNF0_MAF_N_REQS"}, + {41, "HNF0_SEL_OPCODE"}, + {42, "HNF1_CYCLES"}, + {43, "HNF1_REQS_RECEIVED"}, + {44, "HNF1_REQS_PROCESSED"}, + {45, "HNF1_DIR_HIT"}, + {46, "HNF1_DIR_MISS"}, + {47, "HNF1_DIR_RD_ALLOC"}, + {48, "HNF1_DIR_WR_ALLOC"}, + {49, "HNF1_DIR_VICTIM"}, + {50, "HNF1_CL_HAZARD"}, + {51, "HNF1_ALL_HAZARD"}, + {52, "HNF1_PIPE_STALLS"}, + {53, "HNF1_MEM_READS"}, + {54, "HNF1_MEM_WRITES"}, + {55, "HNF1_MEM_ACCESS"}, + {56, "HNF1_DCL_READ"}, + {57, "HNF1_DCL_INVAL"}, + {58, "HNF1_CHI_RXDAT"}, + {59, "HNF1_CHI_RXRSP"}, + {60, "HNF1_CHI_TXDAT"}, + {61, "HNF1_CHI_TXRSP"}, + {62, "HNF1_CHI_TXSNP"}, + {63, "HNF1_DCT_SNP"}, + {64, "HNF1_SNP_FWD_DATA"}, + {65, "HNF1_SNP_FWD_RSP"}, + {66, "HNF1_SNP_RSP"}, + {67, "HNF1_EXCL_FULL"}, + {68, "HNF1_EXCL_WRITE_F"}, + {69, "HNF1_EXCL_WRITE_S"}, + {70, "HNF1_EXCL_WRITE"}, + {71, "HNF1_EXCL_READ"}, + {72, "HNF1_REQ_BUF_EMPTY"}, + {73, "HNF1_ALL_MAFS_BUSY"}, + {74, "HNF1_TXDAT_NO_LCRD"}, + {75, "HNF1_TXSNP_NO_LCRD"}, + {76, "HNF1_TXRSP_NO_LCRD"}, + {77, "HNF1_TXREQ_NO_LCRD"}, + {78, "HNF1_WRITE"}, + {79, "HNF1_READ"}, + {80, "HNF1_ACCESS"}, + {81, "HNF1_MAF_N_BUSY"}, + {82, "HNF1_MAF_N_REQS"}, + {83, "HNF1_SEL_OPCODE"}, + {84, "GDC_BANK0_RD_REQ"}, + {85, "GDC_BANK0_WR_REQ"}, + {86, "GDC_BANK0_ALLOCATE"}, + {87, "GDC_BANK0_HIT"}, + {88, "GDC_BANK0_MISS"}, + {89, "GDC_BANK0_INVALIDATE"}, + {90, "GDC_BANK0_EVICT"}, + {91, "GDC_BANK0_RD_RESP"}, + {92, "GDC_BANK0_WR_ACK"}, + {93, "GDC_BANK0_SNOOP"}, + {94, "GDC_BANK0_SNOOP_NORMAL"}, + {95, "GDC_BANK0_SNOOP_FWD"}, + {96, "GDC_BANK0_SNOOP_STASH"}, + {97, "GDC_BANK0_SNOOP_STASH_INDPND_RD"}, + {98, "GDC_BANK0_FOLLOWER"}, + {99, "GDC_BANK0_FW"}, + {100, "GDC_BANK0_HIT_DCL_BOTH"}, + {101, "GDC_BANK0_HIT_DCL_PARTIAL"}, + {102, "GDC_BANK0_EVICT_DCL"}, + {103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA0"}, + {103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA1"}, + {105, "GDC_BANK0_ARB_STRB"}, + {106, "GDC_BANK0_ARB_WAIT"}, + {107, "GDC_BANK0_GGA_STRB"}, + {108, "GDC_BANK0_GGA_WAIT"}, + {109, "GDC_BANK0_FW_STRB"}, + {110, "GDC_BANK0_FW_WAIT"}, + {111, "GDC_BANK0_SNP_STRB"}, + {112, "GDC_BANK0_SNP_WAIT"}, + {113, "GDC_BANK0_MISS_INARB_STRB"}, + {114, "GDC_BANK0_MISS_INARB_WAIT"}, + {115, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD0"}, + {116, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD1"}, + {117, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD2"}, + {118, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD3"}, + {119, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR0"}, + {120, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR1"}, + {121, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR2"}, + {122, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR3"}, + {123, "GDC_BANK1_RD_REQ"}, + {124, "GDC_BANK1_WR_REQ"}, + {125, "GDC_BANK1_ALLOCATE"}, + {126, "GDC_BANK1_HIT"}, + {127, "GDC_BANK1_MISS"}, + {128, "GDC_BANK1_INVALIDATE"}, + {129, "GDC_BANK1_EVICT"}, + {130, "GDC_BANK1_RD_RESP"}, + {131, "GDC_BANK1_WR_ACK"}, + {132, "GDC_BANK1_SNOOP"}, + {133, "GDC_BANK1_SNOOP_NORMAL"}, + {134, "GDC_BANK1_SNOOP_FWD"}, + {135, "GDC_BANK1_SNOOP_STASH"}, + {136, "GDC_BANK1_SNOOP_STASH_INDPND_RD"}, + {137, "GDC_BANK1_FOLLOWER"}, + {138, "GDC_BANK1_FW"}, + {139, "GDC_BANK1_HIT_DCL_BOTH"}, + {140, "GDC_BANK1_HIT_DCL_PARTIAL"}, + {141, "GDC_BANK1_EVICT_DCL"}, + {142, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA0"}, + {143, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA1"}, + {144, "GDC_BANK1_ARB_STRB"}, + {145, "GDC_BANK1_ARB_WAIT"}, + {146, "GDC_BANK1_GGA_STRB"}, + {147, "GDC_BANK1_GGA_WAIT"}, + {148, "GDC_BANK1_FW_STRB"}, + {149, "GDC_BANK1_FW_WAIT"}, + {150, "GDC_BANK1_SNP_STRB"}, + {151, "GDC_BANK1_SNP_WAIT"}, + {152, "GDC_BANK1_MISS_INARB_STRB"}, + {153, "GDC_BANK1_MISS_INARB_WAIT"}, + {154, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD0"}, + {155, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD1"}, + {156, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD2"}, + {157, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD3"}, + {158, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR0"}, + {159, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR1"}, + {160, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR2"}, + {161, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR3"}, + {162, "HISTOGRAM_HISTOGRAM_BIN0"}, + {163, "HISTOGRAM_HISTOGRAM_BIN1"}, + {164, "HISTOGRAM_HISTOGRAM_BIN2"}, + {165, "HISTOGRAM_HISTOGRAM_BIN3"}, + {166, "HISTOGRAM_HISTOGRAM_BIN4"}, + {167, "HISTOGRAM_HISTOGRAM_BIN5"}, + {168, "HISTOGRAM_HISTOGRAM_BIN6"}, + {169, "HISTOGRAM_HISTOGRAM_BIN7"}, + {170, "HISTOGRAM_HISTOGRAM_BIN8"}, + {171, "HISTOGRAM_HISTOGRAM_BIN9"}, +}; + +static const struct mlxbf_pmc_events mlxbf_pmc_llt_miss_events[] = { + {0, "GDC_MISS_MACHINE_RD_REQ"}, + {1, "GDC_MISS_MACHINE_WR_REQ"}, + {2, "GDC_MISS_MACHINE_SNP_REQ"}, + {3, "GDC_MISS_MACHINE_EVICT_REQ"}, + {4, "GDC_MISS_MACHINE_FW_REQ"}, + {5, "GDC_MISS_MACHINE_RD_RESP"}, + {6, "GDC_MISS_MACHINE_WR_RESP"}, + {7, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP"}, + {8, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP_TXDAT"}, + {9, "GDC_MISS_MACHINE_CHI_TXREQ"}, + {10, "GDC_MISS_MACHINE_CHI_RXRSP"}, + {11, "GDC_MISS_MACHINE_CHI_TXDAT"}, + {12, "GDC_MISS_MACHINE_CHI_RXDAT"}, + {13, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_0"}, + {14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1 "}, + {15, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_2"}, + {16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3 "}, + {17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0 "}, + {18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1 "}, + {19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2 "}, + {20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3 "}, + {21, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_0"}, + {22, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_1"}, + {23, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_2"}, + {24, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_3"}, + {25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0 "}, + {26, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_1"}, + {27, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_2"}, + {28, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_3"}, + {29, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_0"}, + {30, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_1"}, + {31, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_2"}, + {32, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_3"}, + {33, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_4"}, + {34, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_5"}, + {35, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_6"}, + {36, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_0"}, + {37, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_1"}, + {38, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_0"}, + {39, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_1"}, + {40, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_0"}, + {41, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_1"}, + {42, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_0"}, + {43, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_1"}, + {44, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_0"}, + {45, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_1"}, + {46, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_2"}, + {47, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_3"}, + {48, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_0"}, + {49, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_1"}, + {50, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_0"}, + {51, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_1"}, + {52, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_0"}, + {53, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_1"}, + {54, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_0"}, + {55, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_1"}, + {56, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_2"}, + {57, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_3"}, + {58, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_0"}, + {59, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_1"}, + {60, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_2"}, + {61, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_3"}, + {62, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_4"}, + {63, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_5"}, + {64, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_6"}, + {65, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_7"}, + {66, "HISTOGRAM_HISTOGRAM_BIN0"}, + {67, "HISTOGRAM_HISTOGRAM_BIN1"}, + {68, "HISTOGRAM_HISTOGRAM_BIN2"}, + {69, "HISTOGRAM_HISTOGRAM_BIN3"}, + {70, "HISTOGRAM_HISTOGRAM_BIN4"}, + {71, "HISTOGRAM_HISTOGRAM_BIN5"}, + {72, "HISTOGRAM_HISTOGRAM_BIN6"}, + {73, "HISTOGRAM_HISTOGRAM_BIN7"}, + {74, "HISTOGRAM_HISTOGRAM_BIN8"}, + {75, "HISTOGRAM_HISTOGRAM_BIN9"}, +}; + static struct mlxbf_pmc_context *pmc; /* UUID used to probe ATF service. */ @@ -569,8 +999,21 @@ static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk, break; } } else if (strstr(blk, "mss")) { - events = mlxbf_pmc_mss_events; - *size = ARRAY_SIZE(mlxbf_pmc_mss_events); + switch (pmc->event_set) { + case MLXBF_PMC_EVENT_SET_BF1: + case MLXBF_PMC_EVENT_SET_BF2: + events = mlxbf_pmc_mss_events_1; + *size = ARRAY_SIZE(mlxbf_pmc_mss_events_1); + break; + case MLXBF_PMC_EVENT_SET_BF3: + events = mlxbf_pmc_mss_events_3; + *size = ARRAY_SIZE(mlxbf_pmc_mss_events_3); + break; + default: + events = NULL; + *size = 0; + break; + } } else if (strstr(blk, "ecc")) { events = mlxbf_pmc_ecc_events; *size = ARRAY_SIZE(mlxbf_pmc_ecc_events); @@ -586,6 +1029,12 @@ static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk, } else if (strstr(blk, "smmu")) { events = mlxbf_pmc_smgen_events; *size = ARRAY_SIZE(mlxbf_pmc_smgen_events); + } else if (strstr(blk, "llt_miss")) { + events = mlxbf_pmc_llt_miss_events; + *size = ARRAY_SIZE(mlxbf_pmc_llt_miss_events); + } else if (strstr(blk, "llt")) { + events = mlxbf_pmc_llt_events; + *size = ARRAY_SIZE(mlxbf_pmc_llt_events); } else { events = NULL; *size = 0; @@ -712,6 +1161,43 @@ static int mlxbf_pmc_program_l3_counter(int blk_num, uint32_t cnt_num, return mlxbf_pmc_write(pmcaddr, MLXBF_PMC_WRITE_REG_32, *wordaddr); } +/* Method to handle crspace counter programming */ +static int mlxbf_pmc_program_crspace_counter(int blk_num, uint32_t cnt_num, + uint32_t evt) +{ + uint32_t word; + void *addr; + int ret; + + addr = pmc->block[blk_num].mmio_base + + (rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); + ret = mlxbf_pmc_readl(addr, &word); + if (ret) + return ret; + + if (cnt_num % 2) { + word &= ~MLXBF_PMC_CRSPACE_PERFSEL1; + word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL1, evt); + } else { + word &= ~MLXBF_PMC_CRSPACE_PERFSEL0; + word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL0, evt); + } + + return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, word); +} + +/* Method to clear crspace counter value */ +static int mlxbf_pmc_clear_crspace_counter(int blk_num, uint32_t cnt_num) +{ + void *addr; + + addr = pmc->block[blk_num].mmio_base + + MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) + + (cnt_num * 4); + + return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, 0x0); +} + /* Method to program a counter to monitor an event */ static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num, uint32_t evt, bool is_l3) @@ -724,6 +1210,10 @@ static int mlxbf_pmc_program_counter(int blk_num, uint32_t cnt_num, if (is_l3) return mlxbf_pmc_program_l3_counter(blk_num, cnt_num, evt); + if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) + return mlxbf_pmc_program_crspace_counter(blk_num, cnt_num, + evt); + /* Configure the counter */ perfctl = FIELD_PREP(MLXBF_PMC_PERFCTL_EN0, 1); perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_EB0, 0); @@ -778,7 +1268,7 @@ static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num, { uint32_t perfcnt_low = 0, perfcnt_high = 0; uint64_t value; - int status = 0; + int status; status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + MLXBF_PMC_L3C_PERF_CNT_LOW + @@ -804,6 +1294,24 @@ static int mlxbf_pmc_read_l3_counter(int blk_num, uint32_t cnt_num, return 0; } +/* Method to handle crspace counter reads */ +static int mlxbf_pmc_read_crspace_counter(int blk_num, uint32_t cnt_num, + uint64_t *result) +{ + uint32_t value; + int status = 0; + + status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + + MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) + + (cnt_num * 4), &value); + if (status) + return status; + + *result = value; + + return 0; +} + /* Method to read the counter value */ static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3, uint64_t *result) @@ -818,6 +1326,9 @@ static int mlxbf_pmc_read_counter(int blk_num, uint32_t cnt_num, bool is_l3, if (is_l3) return mlxbf_pmc_read_l3_counter(blk_num, cnt_num, result); + if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) + return mlxbf_pmc_read_crspace_counter(blk_num, cnt_num, result); + perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE; perfval_offset = perfcfg_offset + pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE; @@ -893,6 +1404,30 @@ static int mlxbf_pmc_read_l3_event(int blk_num, uint32_t cnt_num, return 0; } +/* Method to read crspace block event */ +static int mlxbf_pmc_read_crspace_event(int blk_num, uint32_t cnt_num, + uint64_t *result) +{ + uint32_t word, evt; + void *addr; + int ret; + + addr = pmc->block[blk_num].mmio_base + + (rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); + ret = mlxbf_pmc_readl(addr, &word); + if (ret) + return ret; + + if (cnt_num % 2) + evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL1, word); + else + evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL0, word); + + *result = evt; + + return 0; +} + /* Method to find the event currently being monitored by a counter */ static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3, uint64_t *result) @@ -906,6 +1441,9 @@ static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3, if (is_l3) return mlxbf_pmc_read_l3_event(blk_num, cnt_num, result); + if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) + return mlxbf_pmc_read_crspace_event(blk_num, cnt_num, result); + perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE; perfval_offset = perfcfg_offset + pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE; @@ -982,7 +1520,8 @@ static ssize_t mlxbf_pmc_counter_show(struct device *dev, if (strstr(pmc->block_name[blk_num], "l3cache")) is_l3 = true; - if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) { + if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) || + (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)) { if (mlxbf_pmc_read_counter(blk_num, cnt_num, is_l3, &value)) return -EINVAL; } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) { @@ -1040,6 +1579,10 @@ static ssize_t mlxbf_pmc_counter_store(struct device *dev, err = mlxbf_pmc_write_reg(blk_num, offset, data); if (err) return err; + } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) { + if (sscanf(attr->attr.name, "counter%d", &cnt_num) != 1) + return -EINVAL; + err = mlxbf_pmc_clear_crspace_counter(blk_num, cnt_num); } else return -EINVAL; @@ -1137,28 +1680,37 @@ static ssize_t mlxbf_pmc_event_list_show(struct device *dev, return ret; } -/* Show function for "enable" sysfs files - only for l3cache */ +/* Show function for "enable" sysfs files - only for l3cache & crspace */ static ssize_t mlxbf_pmc_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct mlxbf_pmc_attribute *attr_enable = container_of( attr, struct mlxbf_pmc_attribute, dev_attr); - uint32_t perfcnt_cfg; + uint32_t perfcnt_cfg, word; int blk_num, value; blk_num = attr_enable->nr; - if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + - MLXBF_PMC_L3C_PERF_CNT_CFG, - &perfcnt_cfg)) - return -EINVAL; + if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) { + if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + + MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), + &word)) + return -EINVAL; - value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg); + value = FIELD_GET(MLXBF_PMC_CRSPACE_PERFMON_EN, word); + } else { + if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + + MLXBF_PMC_L3C_PERF_CNT_CFG, + &perfcnt_cfg)) + return -EINVAL; + + value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg); + } return sysfs_emit(buf, "%d\n", value); } -/* Store function for "enable" sysfs files - only for l3cache */ +/* Store function for "enable" sysfs files - only for l3cache & crspace */ static ssize_t mlxbf_pmc_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1166,6 +1718,7 @@ static ssize_t mlxbf_pmc_enable_store(struct device *dev, struct mlxbf_pmc_attribute *attr_enable = container_of( attr, struct mlxbf_pmc_attribute, dev_attr); int err, en, blk_num; + uint32_t word; blk_num = attr_enable->nr; @@ -1173,19 +1726,35 @@ static ssize_t mlxbf_pmc_enable_store(struct device *dev, if (err < 0) return err; - if (!en) { - err = mlxbf_pmc_config_l3_counters(blk_num, false, false); + if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) { + err = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + + MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), + &word); + if (err) + return -EINVAL; + + word &= ~MLXBF_PMC_CRSPACE_PERFMON_EN; + word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_EN, en); + if (en) + word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_CLR, 1); + + mlxbf_pmc_write(pmc->block[blk_num].mmio_base + + MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), + MLXBF_PMC_WRITE_REG_32, word); + } else { + if (en && en != 1) + return -EINVAL; + + err = mlxbf_pmc_config_l3_counters(blk_num, false, !!en); if (err) return err; - } else if (en == 1) { - err = mlxbf_pmc_config_l3_counters(blk_num, false, true); - if (err) - return err; - err = mlxbf_pmc_config_l3_counters(blk_num, true, false); - if (err) - return err; - } else - return -EINVAL; + + if (en == 1) { + err = mlxbf_pmc_config_l3_counters(blk_num, true, false); + if (err) + return err; + } + } return count; } @@ -1206,7 +1775,8 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, int blk_num) attr = NULL; /* "enable" sysfs to start/stop the counters. Only in L3C blocks */ - if (strstr(pmc->block_name[blk_num], "l3cache")) { + if (strstr(pmc->block_name[blk_num], "l3cache") || + ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) { attr = &pmc->block[blk_num].attr_enable; attr->dev_attr.attr.mode = 0644; attr->dev_attr.show = mlxbf_pmc_enable_show; @@ -1297,7 +1867,8 @@ static int mlxbf_pmc_create_groups(struct device *dev, int blk_num) int err; /* Populate attributes based on counter type */ - if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) + if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) || + (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)) err = mlxbf_pmc_init_perftype_counter(dev, blk_num); else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) err = mlxbf_pmc_init_perftype_reg(dev, blk_num); @@ -1311,7 +1882,8 @@ static int mlxbf_pmc_create_groups(struct device *dev, int blk_num) pmc->block[blk_num].block_attr_grp.attrs = pmc->block[blk_num].block_attr; pmc->block[blk_num].block_attr_grp.name = devm_kasprintf( dev, GFP_KERNEL, pmc->block_name[blk_num]); - pmc->groups[blk_num] = &pmc->block[blk_num].block_attr_grp; + pmc->groups[pmc->group_num] = &pmc->block[blk_num].block_attr_grp; + pmc->group_num++; return 0; } @@ -1334,13 +1906,52 @@ static int mlxbf_pmc_map_counters(struct device *dev) int i, tile_num, ret; for (i = 0; i < pmc->total_blocks; ++i) { - if (strstr(pmc->block_name[i], "tile")) { + /* Create sysfs for tiles only if block number < tile_count */ + if (strstr(pmc->block_name[i], "tilenet")) { + if (sscanf(pmc->block_name[i], "tilenet%d", &tile_num) != 1) + continue; + + if (tile_num >= pmc->tile_count) + continue; + } else if (strstr(pmc->block_name[i], "tile")) { if (sscanf(pmc->block_name[i], "tile%d", &tile_num) != 1) - return -EINVAL; + continue; if (tile_num >= pmc->tile_count) continue; } + + /* Create sysfs only for enabled MSS blocks */ + if (strstr(pmc->block_name[i], "mss") && + pmc->event_set == MLXBF_PMC_EVENT_SET_BF3) { + int mss_num; + + if (sscanf(pmc->block_name[i], "mss%d", &mss_num) != 1) + continue; + + if (!((pmc->mss_enable >> mss_num) & 0x1)) + continue; + } + + /* Create sysfs only for enabled LLT blocks */ + if (strstr(pmc->block_name[i], "llt_miss")) { + int llt_num; + + if (sscanf(pmc->block_name[i], "llt_miss%d", &llt_num) != 1) + continue; + + if (!((pmc->llt_enable >> llt_num) & 0x1)) + continue; + } else if (strstr(pmc->block_name[i], "llt")) { + int llt_num; + + if (sscanf(pmc->block_name[i], "llt%d", &llt_num) != 1) + continue; + + if (!((pmc->llt_enable >> llt_num) & 0x1)) + continue; + } + ret = device_property_read_u64_array(dev, pmc->block_name[i], info, MLXBF_PMC_INFO_SZ); if (ret) @@ -1417,6 +2028,8 @@ static int mlxbf_pmc_probe(struct platform_device *pdev) pmc->event_set = MLXBF_PMC_EVENT_SET_BF1; else if (!strcmp(hid, "MLNXBFD1")) pmc->event_set = MLXBF_PMC_EVENT_SET_BF2; + else if (!strcmp(hid, "MLNXBFD2")) + pmc->event_set = MLXBF_PMC_EVENT_SET_BF3; else return -ENODEV; @@ -1430,11 +2043,19 @@ static int mlxbf_pmc_probe(struct platform_device *pdev) if (ret != pmc->total_blocks) return -EFAULT; - ret = device_property_read_u32(dev, "tile_num", &pmc->tile_count); - if (ret) - return ret; + if (device_property_read_u32(dev, "tile_num", &pmc->tile_count)) { + if (device_property_read_u8(dev, "llt_enable", &pmc->llt_enable)) { + dev_err(dev, "Number of tiles/LLTs undefined\n"); + return -EINVAL; + } + if (device_property_read_u8(dev, "mss_enable", &pmc->mss_enable)) { + dev_err(dev, "Number of tiles/MSSs undefined\n"); + return -EINVAL; + } + } pmc->pdev = pdev; + pmc->group_num = 0; ret = mlxbf_pmc_map_counters(dev); if (ret) @@ -1449,6 +2070,7 @@ static int mlxbf_pmc_probe(struct platform_device *pdev) static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0", 0 }, { "MLNXBFD1", 0 }, + { "MLNXBFD2", 0 }, {}, }; MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids); From bbaa6ffa5b6c9609d3b3c431c389b407eea5441f Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Wed, 13 Sep 2023 11:32:33 +0800 Subject: [PATCH 026/396] power: supply: core: Use blocking_notifier_call_chain to avoid RCU complaint AMD PMF driver can cause the following warning: [ 196.159546] ------------[ cut here ]------------ [ 196.159556] Voluntary context switch within RCU read-side critical section! [ 196.159571] WARNING: CPU: 0 PID: 9 at kernel/rcu/tree_plugin.h:320 rcu_note_context_switch+0x43d/0x560 [ 196.159604] Modules linked in: nvme_fabrics ccm rfcomm snd_hda_scodec_cs35l41_spi cmac algif_hash algif_skcipher af_alg bnep joydev btusb btrtl uvcvideo btintel btbcm videobuf2_vmalloc intel_rapl_msr btmtk videobuf2_memops uvc videobuf2_v4l2 intel_rapl_common binfmt_misc hid_sensor_als snd_sof_amd_vangogh hid_sensor_trigger bluetooth industrialio_triggered_buffer videodev snd_sof_amd_rembrandt hid_sensor_iio_common amdgpu ecdh_generic kfifo_buf videobuf2_common hp_wmi kvm_amd sparse_keymap snd_sof_amd_renoir wmi_bmof industrialio ecc mc nls_iso8859_1 kvm snd_sof_amd_acp irqbypass snd_sof_xtensa_dsp crct10dif_pclmul crc32_pclmul mt7921e snd_sof_pci snd_ctl_led polyval_clmulni mt7921_common polyval_generic snd_sof ghash_clmulni_intel mt792x_lib mt76_connac_lib sha512_ssse3 snd_sof_utils aesni_intel snd_hda_codec_realtek crypto_simd mt76 snd_hda_codec_generic cryptd snd_soc_core snd_hda_codec_hdmi rapl ledtrig_audio input_leds snd_compress i2c_algo_bit drm_ttm_helper mac80211 snd_pci_ps hid_multitouch ttm drm_exec [ 196.159970] drm_suballoc_helper snd_rpl_pci_acp6x amdxcp drm_buddy snd_hda_intel snd_acp_pci snd_hda_scodec_cs35l41_i2c serio_raw gpu_sched snd_hda_scodec_cs35l41 snd_acp_legacy_common snd_intel_dspcfg snd_hda_cs_dsp_ctls snd_hda_codec libarc4 drm_display_helper snd_pci_acp6x cs_dsp snd_hwdep snd_soc_cs35l41_lib video k10temp snd_pci_acp5x thunderbolt snd_hda_core drm_kms_helper cfg80211 snd_seq snd_rn_pci_acp3x snd_pcm snd_acp_config cec snd_soc_acpi snd_seq_device rc_core ccp snd_pci_acp3x snd_timer snd soundcore wmi amd_pmf platform_profile amd_pmc mac_hid serial_multi_instantiate wireless_hotkey hid_sensor_hub sch_fq_codel msr parport_pc ppdev lp parport efi_pstore ip_tables x_tables autofs4 btrfs blake2b_generic raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx libcrc32c xor raid6_pq raid1 raid0 multipath linear dm_mirror dm_region_hash dm_log cdc_ether usbnet r8152 mii hid_generic nvme i2c_hid_acpi i2c_hid nvme_core i2c_piix4 xhci_pci amd_sfh drm xhci_pci_renesas nvme_common hid [ 196.160382] CPU: 0 PID: 9 Comm: kworker/0:1 Not tainted 6.6.0-rc1 #4 [ 196.160397] Hardware name: HP HP EliteBook 845 14 inch G10 Notebook PC/8B6E, BIOS V82 Ver. 01.02.00 08/24/2023 [ 196.160405] Workqueue: events power_supply_changed_work [ 196.160426] RIP: 0010:rcu_note_context_switch+0x43d/0x560 [ 196.160440] Code: 00 48 89 be 40 08 00 00 48 89 86 48 08 00 00 48 89 10 e9 63 fe ff ff 48 c7 c7 10 e7 b0 9e c6 05 e8 d8 20 02 01 e8 13 0f f3 ff <0f> 0b e9 27 fc ff ff a9 ff ff ff 7f 0f 84 cf fc ff ff 65 48 8b 3c [ 196.160450] RSP: 0018:ffffc900001878f0 EFLAGS: 00010046 [ 196.160462] RAX: 0000000000000000 RBX: ffff88885e834040 RCX: 0000000000000000 [ 196.160470] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 196.160476] RBP: ffffc90000187910 R08: 0000000000000000 R09: 0000000000000000 [ 196.160482] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 [ 196.160488] R13: 0000000000000000 R14: ffff888100990000 R15: ffff888100990000 [ 196.160495] FS: 0000000000000000(0000) GS:ffff88885e800000(0000) knlGS:0000000000000000 [ 196.160504] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 196.160512] CR2: 000055cb053c8246 CR3: 000000013443a000 CR4: 0000000000750ef0 [ 196.160520] PKRU: 55555554 [ 196.160526] Call Trace: [ 196.160532] [ 196.160548] ? show_regs+0x72/0x90 [ 196.160570] ? rcu_note_context_switch+0x43d/0x560 [ 196.160580] ? __warn+0x8d/0x160 [ 196.160600] ? rcu_note_context_switch+0x43d/0x560 [ 196.160613] ? report_bug+0x1bb/0x1d0 [ 196.160637] ? handle_bug+0x46/0x90 [ 196.160658] ? exc_invalid_op+0x19/0x80 [ 196.160675] ? asm_exc_invalid_op+0x1b/0x20 [ 196.160709] ? rcu_note_context_switch+0x43d/0x560 [ 196.160727] __schedule+0xb9/0x15f0 [ 196.160746] ? srso_alias_return_thunk+0x5/0x7f [ 196.160765] ? srso_alias_return_thunk+0x5/0x7f [ 196.160778] ? acpi_ns_search_one_scope+0xbe/0x270 [ 196.160806] schedule+0x68/0x110 [ 196.160820] schedule_timeout+0x151/0x160 [ 196.160829] ? srso_alias_return_thunk+0x5/0x7f [ 196.160842] ? srso_alias_return_thunk+0x5/0x7f [ 196.160855] ? acpi_ns_lookup+0x3c5/0xa90 [ 196.160878] __down_common+0xff/0x220 [ 196.160905] __down_timeout+0x16/0x30 [ 196.160920] down_timeout+0x64/0x70 [ 196.160938] acpi_os_wait_semaphore+0x85/0x200 [ 196.160959] acpi_ut_acquire_mutex+0x9e/0x280 [ 196.160979] acpi_ex_enter_interpreter+0x2d/0xb0 [ 196.160992] acpi_ns_evaluate+0x2f0/0x5f0 [ 196.161005] acpi_evaluate_object+0x172/0x490 [ 196.161018] ? acpi_os_signal_semaphore+0x8a/0xd0 [ 196.161038] acpi_evaluate_integer+0x52/0xe0 [ 196.161055] ? kfree+0x79/0x120 [ 196.161071] ? srso_alias_return_thunk+0x5/0x7f [ 196.161089] acpi_ac_get_state.part.0+0x27/0x80 [ 196.161110] get_ac_property+0x5c/0x70 [ 196.161127] ? __pfx___power_supply_is_system_supplied+0x10/0x10 [ 196.161146] __power_supply_is_system_supplied+0x44/0xb0 [ 196.161166] class_for_each_device+0x124/0x160 [ 196.161184] ? acpi_ac_get_state.part.0+0x27/0x80 [ 196.161203] ? srso_alias_return_thunk+0x5/0x7f [ 196.161223] power_supply_is_system_supplied+0x3c/0x70 [ 196.161243] amd_pmf_get_power_source+0xe/0x20 [amd_pmf] [ 196.161276] amd_pmf_power_slider_update_event+0x49/0x90 [amd_pmf] [ 196.161310] amd_pmf_pwr_src_notify_call+0xe7/0x100 [amd_pmf] [ 196.161340] notifier_call_chain+0x5f/0xe0 [ 196.161362] atomic_notifier_call_chain+0x33/0x60 [ 196.161378] power_supply_changed_work+0x84/0x110 [ 196.161394] process_one_work+0x178/0x360 [ 196.161412] ? __pfx_worker_thread+0x10/0x10 [ 196.161424] worker_thread+0x307/0x430 [ 196.161440] ? __pfx_worker_thread+0x10/0x10 [ 196.161451] kthread+0xf4/0x130 [ 196.161467] ? __pfx_kthread+0x10/0x10 [ 196.161486] ret_from_fork+0x43/0x70 [ 196.161502] ? __pfx_kthread+0x10/0x10 [ 196.161518] ret_from_fork_asm+0x1b/0x30 [ 196.161558] [ 196.161562] ---[ end trace 0000000000000000 ]--- Since there's no guarantee that all the callbacks can work in atomic context, switch to use blocking_notifier_call_chain to relax the constraint. Signed-off-by: Kai-Heng Feng Reported-by: Allen Zhong Fixes: 4c71ae414474 ("platform/x86/amd/pmf: Add support SPS PMF feature") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217571 Reviewed-by: Mario Limonciello Link: https://lore.kernel.org/r/20230913033233.602986-1-kai.heng.feng@canonical.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 8 ++++---- include/linux/power_supply.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 0b69fb7bafd8..416409e2fd6d 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -29,7 +29,7 @@ struct class *power_supply_class; EXPORT_SYMBOL_GPL(power_supply_class); -ATOMIC_NOTIFIER_HEAD(power_supply_notifier); +BLOCKING_NOTIFIER_HEAD(power_supply_notifier); EXPORT_SYMBOL_GPL(power_supply_notifier); static struct device_type power_supply_dev_type; @@ -97,7 +97,7 @@ static void power_supply_changed_work(struct work_struct *work) class_for_each_device(power_supply_class, NULL, psy, __power_supply_changed_work); power_supply_update_leds(psy); - atomic_notifier_call_chain(&power_supply_notifier, + blocking_notifier_call_chain(&power_supply_notifier, PSY_EVENT_PROP_CHANGED, psy); kobject_uevent(&psy->dev.kobj, KOBJ_CHANGE); spin_lock_irqsave(&psy->changed_lock, flags); @@ -1262,13 +1262,13 @@ static void power_supply_dev_release(struct device *dev) int power_supply_reg_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_register(&power_supply_notifier, nb); + return blocking_notifier_chain_register(&power_supply_notifier, nb); } EXPORT_SYMBOL_GPL(power_supply_reg_notifier); void power_supply_unreg_notifier(struct notifier_block *nb) { - atomic_notifier_chain_unregister(&power_supply_notifier, nb); + blocking_notifier_chain_unregister(&power_supply_notifier, nb); } EXPORT_SYMBOL_GPL(power_supply_unreg_notifier); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index a427f13c757f..85b86768c0b9 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -767,7 +767,7 @@ struct power_supply_battery_info { int bti_resistance_tolerance; }; -extern struct atomic_notifier_head power_supply_notifier; +extern struct blocking_notifier_head power_supply_notifier; extern int power_supply_reg_notifier(struct notifier_block *nb); extern void power_supply_unreg_notifier(struct notifier_block *nb); #if IS_ENABLED(CONFIG_POWER_SUPPLY) From 500a4609eef46d49a260173b66cabb20bd5159ad Mon Sep 17 00:00:00 2001 From: Adam Skladowski Date: Sat, 12 Aug 2023 13:24:45 +0200 Subject: [PATCH 027/396] clk: qcom: clk-hfpll: Configure l_val in init when required Add support for pre-configuring default frequency multiplier, this appears to be required on some platforms like MSM8976. Without configuring L_VAL device reboots when trying to bring PLL up. Signed-off-by: Adam Skladowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230812112534.8610-3-a39.skl@gmail.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-hfpll.c | 4 ++++ drivers/clk/qcom/clk-hfpll.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/clk/qcom/clk-hfpll.c b/drivers/clk/qcom/clk-hfpll.c index 86f728dc69e5..705352aff067 100644 --- a/drivers/clk/qcom/clk-hfpll.c +++ b/drivers/clk/qcom/clk-hfpll.c @@ -44,6 +44,10 @@ static void __clk_hfpll_init_once(struct clk_hw *hw) regmap_write(regmap, hd->user_reg, regval); } + /* Write L_VAL from conf if it exist */ + if (hd->l_val) + regmap_write(regmap, hd->l_reg, hd->l_val); + if (hd->droop_reg) regmap_write(regmap, hd->droop_reg, hd->droop_val); diff --git a/drivers/clk/qcom/clk-hfpll.h b/drivers/clk/qcom/clk-hfpll.h index 2a57b2fb2f2f..27b9effcb3fd 100644 --- a/drivers/clk/qcom/clk-hfpll.h +++ b/drivers/clk/qcom/clk-hfpll.h @@ -18,6 +18,7 @@ struct hfpll_data { u32 status_reg; u8 lock_bit; + u32 l_val; u32 droop_val; u32 config_val; u32 user_val; From 34e000c0963e55f24be2254fa645f8dd8257a9e0 Mon Sep 17 00:00:00 2001 From: Adam Skladowski Date: Sat, 12 Aug 2023 13:24:46 +0200 Subject: [PATCH 028/396] clk: qcom: hfpll: Allow matching pdata HFPLL driver can be used to drive PLLs also on different SoCs like MSM8976 On MSM8976 each PLL gets it own different configuration, add matching pdata to driver to support multiple configurations. Signed-off-by: Adam Skladowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230812112534.8610-4-a39.skl@gmail.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/hfpll.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/hfpll.c b/drivers/clk/qcom/hfpll.c index f4d78003d189..47325eb17f07 100644 --- a/drivers/clk/qcom/hfpll.c +++ b/drivers/clk/qcom/hfpll.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,7 @@ static const struct hfpll_data hdata = { }; static const struct of_device_id qcom_hfpll_match_table[] = { - { .compatible = "qcom,hfpll" }, + { .compatible = "qcom,hfpll", .data = &hdata }, { } }; MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table); @@ -83,7 +84,7 @@ static int qcom_hfpll_probe(struct platform_device *pdev) init.parent_data = &pdata; - h->d = &hdata; + h->d = of_device_get_match_data(&pdev->dev); h->clkr.hw.init = &init; spin_lock_init(&h->lock); From de37ca2dc98607e74522d8f243aa7feac74577c5 Mon Sep 17 00:00:00 2001 From: Adam Skladowski Date: Sat, 12 Aug 2023 13:24:47 +0200 Subject: [PATCH 029/396] dt-bindings: clock: qcom,hfpll: Document MSM8976 compatibles Document MSM8976 HFPLL compatibles. Signed-off-by: Adam Skladowski Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230812112534.8610-5-a39.skl@gmail.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/clock/qcom,hfpll.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,hfpll.txt b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt index ec02a024424c..5769cbbe76be 100644 --- a/Documentation/devicetree/bindings/clock/qcom,hfpll.txt +++ b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt @@ -12,6 +12,9 @@ PROPERTIES "qcom,hfpll-apq8064", "qcom,hfpll" "qcom,hfpll-msm8974", "qcom,hfpll" "qcom,hfpll-msm8960", "qcom,hfpll" + "qcom,msm8976-hfpll-a53", "qcom,hfpll" + "qcom,msm8976-hfpll-a72", "qcom,hfpll" + "qcom,msm8976-hfpll-cci", "qcom,hfpll" - reg: Usage: required From 1fa2d1a887c763246662a88e203d69b36052770c Mon Sep 17 00:00:00 2001 From: Adam Skladowski Date: Sat, 12 Aug 2023 13:24:48 +0200 Subject: [PATCH 030/396] clk: qcom: hfpll: Add MSM8976 PLL data Add PLL configuration for MSM8976 SoC, this SoC offers 3 HFPLL. Small cluster offers two presets for 652-902Mhz range and 902Mhz-1.47Ghz. For simplicity only add second range as smaller frequencies can be obtained via apcs divider or safe parent this also saves us a hassle of reconfiguring VCO bit and config_val. A72 and CCI cluster only use single frequency range with their outputs/post_dividers/vco_bits being static. Signed-off-by: Adam Skladowski Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230812112534.8610-6-a39.skl@gmail.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/hfpll.c | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/clk/qcom/hfpll.c b/drivers/clk/qcom/hfpll.c index 47325eb17f07..dac27e31ef60 100644 --- a/drivers/clk/qcom/hfpll.c +++ b/drivers/clk/qcom/hfpll.c @@ -32,8 +32,62 @@ static const struct hfpll_data hdata = { .max_rate = 2900000000UL, }; +static const struct hfpll_data msm8976_a53 = { + .mode_reg = 0x00, + .l_reg = 0x04, + .m_reg = 0x08, + .n_reg = 0x0c, + .user_reg = 0x10, + .config_reg = 0x14, + .config_val = 0x341600, + .status_reg = 0x1c, + .lock_bit = 16, + + .l_val = 0x35, + .user_val = 0x109, + .min_rate = 902400000UL, + .max_rate = 1478400000UL, +}; + +static const struct hfpll_data msm8976_a72 = { + .mode_reg = 0x00, + .l_reg = 0x04, + .m_reg = 0x08, + .n_reg = 0x0c, + .user_reg = 0x10, + .config_reg = 0x14, + .config_val = 0x4e0405d, + .status_reg = 0x1c, + .lock_bit = 16, + + .l_val = 0x3e, + .user_val = 0x100109, + .min_rate = 940800000UL, + .max_rate = 2016000000UL, +}; + +static const struct hfpll_data msm8976_cci = { + .mode_reg = 0x00, + .l_reg = 0x04, + .m_reg = 0x08, + .n_reg = 0x0c, + .user_reg = 0x10, + .config_reg = 0x14, + .config_val = 0x141400, + .status_reg = 0x1c, + .lock_bit = 16, + + .l_val = 0x20, + .user_val = 0x100109, + .min_rate = 556800000UL, + .max_rate = 902400000UL, +}; + static const struct of_device_id qcom_hfpll_match_table[] = { { .compatible = "qcom,hfpll", .data = &hdata }, + { .compatible = "qcom,msm8976-hfpll-a53", .data = &msm8976_a53 }, + { .compatible = "qcom,msm8976-hfpll-a72", .data = &msm8976_a72 }, + { .compatible = "qcom,msm8976-hfpll-cci", .data = &msm8976_cci }, { } }; MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table); From ddf5bbee5fa6cb157ecef4fe5263f3f36635e1c3 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Mon, 31 Jul 2023 10:36:10 +0300 Subject: [PATCH 031/396] dt-bindings: power: supply: maxim,max17040: add temperature support Add temperature monitoring support. Signed-off-by: Svyatoslav Ryhel Reviewed-by: Krzysztof Kozlowski Reviewed-by: Iskren Chernev Link: https://lore.kernel.org/r/20230731073613.10394-2-clamor95@gmail.com Signed-off-by: Sebastian Reichel --- .../bindings/power/supply/maxim,max17040.yaml | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml index 2627cd3eed83..377cbb2c2c1f 100644 --- a/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml +++ b/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml @@ -55,6 +55,14 @@ properties: interrupts: maxItems: 1 + io-channels: + items: + - description: battery temperature + + io-channel-names: + items: + - const: temp + wakeup-source: type: boolean description: | @@ -95,3 +103,26 @@ examples: wakeup-source; }; }; + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + fuel-gauge@36 { + compatible = "maxim,max17043"; + reg = <0x36>; + + interrupt-parent = <&gpio>; + interrupts = <144 IRQ_TYPE_EDGE_FALLING>; + + monitored-battery = <&battery>; + power-supplies = <&charger>; + + io-channels = <&adc 8>; + io-channel-names = "temp"; + + maxim,alert-low-soc-level = <10>; + wakeup-source; + }; + }; From f4b782af61ae7bbf93008d5809b0e3a8ac2bb88e Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Mon, 31 Jul 2023 10:36:11 +0300 Subject: [PATCH 032/396] power: max17040: pass status property from supplier Optionally pass status property from supplier if has support for it. If cell is online assume it is present as well. Signed-off-by: Svyatoslav Ryhel Reviewed-by: Iskren Chernev Link: https://lore.kernel.org/r/20230731073613.10394-3-clamor95@gmail.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/max17040_battery.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index ff42db672899..92caf6c7a48c 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -389,6 +389,7 @@ static int max17040_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_PRESENT: val->intval = max17040_get_online(chip); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: @@ -400,6 +401,9 @@ static int max17040_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: val->intval = chip->low_soc_alert; break; + case POWER_SUPPLY_PROP_STATUS: + power_supply_get_property_from_supplier(psy, psp, val); + break; default: return -EINVAL; } @@ -415,9 +419,11 @@ static const struct regmap_config max17040_regmap = { static enum power_supply_property max17040_battery_props[] = { POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN, + POWER_SUPPLY_PROP_STATUS, }; static const struct power_supply_desc max17040_battery_desc = { From 814755c48f8b2c3e83b3c11535c48ab416128978 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Mon, 31 Jul 2023 10:36:12 +0300 Subject: [PATCH 033/396] power: max17040: get thermal data from adc if available Since fuel gauge does not support thermal monitoring, some vendors may couple this fuel gauge with thermal/adc sensor to monitor battery cell exact temperature. Add this feature by adding optional iio thermal channel. Signed-off-by: Svyatoslav Ryhel Reviewed-by: Iskren Chernev Link: https://lore.kernel.org/r/20230731073613.10394-4-clamor95@gmail.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 2 +- drivers/power/supply/max17040_battery.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 663a1c423806..d99db3a049f2 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -374,7 +374,7 @@ config AXP288_FUEL_GAUGE config BATTERY_MAX17040 tristate "Maxim MAX17040/17041/17043 family Fuel Gauge" - depends on I2C + depends on I2C && IIO select REGMAP_I2C help Driver supports Maxim fuel-gauge systems for lithium-ion (Li+) diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index 92caf6c7a48c..51310f6e4803 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -18,6 +18,7 @@ #include #include #include +#include #define MAX17040_VCELL 0x02 #define MAX17040_SOC 0x04 @@ -142,6 +143,7 @@ struct max17040_chip { struct delayed_work work; struct power_supply *battery; struct chip_data data; + struct iio_channel *channel_temp; /* battery capacity */ int soc; @@ -404,6 +406,13 @@ static int max17040_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_STATUS: power_supply_get_property_from_supplier(psy, psp, val); break; + case POWER_SUPPLY_PROP_TEMP: + if (!chip->channel_temp) + return -ENODATA; + + iio_read_channel_processed_scale(chip->channel_temp, + &val->intval, 10); + break; default: return -EINVAL; } @@ -424,6 +433,7 @@ static enum power_supply_property max17040_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN, POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TEMP, }; static const struct power_supply_desc max17040_battery_desc = { @@ -469,6 +479,17 @@ static int max17040_probe(struct i2c_client *client) i2c_set_clientdata(client, chip); psy_cfg.drv_data = chip; + /* Switch to devm_iio_channel_get_optional when available */ + chip->channel_temp = devm_iio_channel_get(&client->dev, "temp"); + if (IS_ERR(chip->channel_temp)) { + ret = PTR_ERR(chip->channel_temp); + if (ret != -ENODEV) + return dev_err_probe(&client->dev, PTR_ERR(chip->channel_temp), + "failed to get temp\n"); + else + chip->channel_temp = NULL; + } + chip->battery = devm_power_supply_register(&client->dev, &max17040_battery_desc, &psy_cfg); if (IS_ERR(chip->battery)) { From 1769142a14c34a8acd67657bc3e637f22f75e026 Mon Sep 17 00:00:00 2001 From: Maximilian Weigand Date: Wed, 14 Jun 2023 20:10:43 +0200 Subject: [PATCH 034/396] power: supply: rk817: query battery properties right after resume The driver reads battery properties every 8 seconds. In order to prevent problems with wrong property values right after resume, trigger an update of those properties on resuming the system and restart the 8-second interval from there. Signed-off-by: Maximilian Weigand Link: https://lore.kernel.org/r/20230601-rk817_query_at_resume-v1-1-630b0adefbd9@mweigand.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/rk817_charger.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c index 8328bcea1a29..393de49b010b 100644 --- a/drivers/power/supply/rk817_charger.c +++ b/drivers/power/supply/rk817_charger.c @@ -1198,11 +1198,24 @@ static int rk817_charger_probe(struct platform_device *pdev) return 0; } +static int __maybe_unused rk817_resume(struct device *dev) +{ + + struct rk817_charger *charger = dev_get_drvdata(dev); + + /* force an immediate update */ + mod_delayed_work(system_wq, &charger->work, 0); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(rk817_charger_pm, NULL, rk817_resume); static struct platform_driver rk817_charger_driver = { .probe = rk817_charger_probe, .driver = { .name = "rk817-charger", + .pm = &rk817_charger_pm, }, }; module_platform_driver(rk817_charger_driver); From dc2dc941730438250a5c6567b8685f065ce1dd0f Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 15 Sep 2023 14:45:15 +0200 Subject: [PATCH 035/396] dt-bindings: vendor-prefixes: Add Mitsumi Electric Co., Ltd. Mitsumi was [1] a Japanese company making various electronics devices and components. They've merged into a new entity, MinebeaMitsumi in 2017. Their current main page is available at [2] [1] https://en.wikipedia.org/wiki/Mitsumi_Electric [2] https://product.minebeamitsumi.com/en/ Acked-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230621-topic-mm8013-v4-1-975aecd173ed@linaro.org Signed-off-by: Sebastian Reichel --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 573578db9509..565b13fb429d 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -871,6 +871,8 @@ patternProperties: description: MiraMEMS Sensing Technology Co., Ltd. "^mitsubishi,.*": description: Mitsubishi Electric Corporation + "^mitsumi,.*": + description: Mitsumi Electric Co., Ltd. "^mixel,.*": description: Mixel, Inc. "^miyoo,.*": From 9d15ff53398b4b21198ee6dec4f65a251de881dc Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 15 Sep 2023 14:45:16 +0200 Subject: [PATCH 036/396] dt-bindings: power: supply: Document Mitsumi MM8013 fuel gauge The Mitsumi MM8013 is an I2C fuel gauge for Li-Ion cells. The partial datasheet is available at [1]. Add bindings for this chip. [1] https://www.mitsumi.co.jp/latest-M/Catalog/pdf/battery_mm_8013_e.pdf Reviewed-by: Krzysztof Kozlowski Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230621-topic-mm8013-v4-2-975aecd173ed@linaro.org Signed-off-by: Sebastian Reichel --- .../bindings/power/supply/mitsumi,mm8013.yaml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/mitsumi,mm8013.yaml diff --git a/Documentation/devicetree/bindings/power/supply/mitsumi,mm8013.yaml b/Documentation/devicetree/bindings/power/supply/mitsumi,mm8013.yaml new file mode 100644 index 000000000000..6865640cbdfa --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/mitsumi,mm8013.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/mitsumi,mm8013.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mitsumi MM8013 fuel gauge + +maintainers: + - Konrad Dybcio + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + const: mitsumi,mm8013 + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + fuel-gauge@55 { + compatible = "mitsumi,mm8013"; + reg = <0x55>; + }; + }; From c75f4bf6800bde67df22ac95139279ec8764118a Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 15 Sep 2023 14:45:17 +0200 Subject: [PATCH 037/396] power: supply: Introduce MM8013 fuel gauge driver Add a driver for the Mitsumi MM8013 fuel gauge. The driver is a vastly cleaned up and improved version of the one that shipped in some obscure Lenovo downstream kernel [1], with some register definitions borrowed from ChromeOS EC platform code [2]. [1] https://github.com/adazem009/kernel_lenovo_bengal/commit/b6b346427a871715709bd22aae449b9383f3b66b [2] https://chromium.googlesource.com/chromiumos/platform/ec/+/master/driver/battery/mm8013.h Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230621-topic-mm8013-v4-3-975aecd173ed@linaro.org Signed-off-by: Sebastian Reichel --- MAINTAINERS | 5 + drivers/power/supply/Kconfig | 9 ++ drivers/power/supply/Makefile | 1 + drivers/power/supply/mm8013.c | 274 ++++++++++++++++++++++++++++++++++ 4 files changed, 289 insertions(+) create mode 100644 drivers/power/supply/mm8013.c diff --git a/MAINTAINERS b/MAINTAINERS index 90f13281d297..fb458f7e397c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14376,6 +14376,11 @@ W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git F: drivers/media/radio/radio-miropcm20* +MITSUMI MM8013 FG DRIVER +M: Konrad Dybcio +F: Documentation/devicetree/bindings/power/supply/mitsumi,mm8013.yaml +F: drivers/power/supply/mm8013.c + MMP SUPPORT R: Lubomir Rintel L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index d99db3a049f2..c816dc4265df 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -951,4 +951,13 @@ config CHARGER_QCOM_SMB2 adds support for the SMB2 switch mode battery charger found in PMI8998 and related PMICs. +config FUEL_GAUGE_MM8013 + tristate "Mitsumi MM8013 fuel gauge driver" + depends on I2C + help + Say Y here to enable the Mitsumi MM8013 fuel gauge driver. + It enables the monitoring of many battery parameters, including + the state of charge, temperature, cycle count, actual and design + capacity, etc. + endif # POWER_SUPPLY diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index a8a9fa6de1e9..ba2c41f060be 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -111,3 +111,4 @@ obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o obj-$(CONFIG_BATTERY_UG3105) += ug3105_battery.o obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_pmi8998_charger.o +obj-$(CONFIG_FUEL_GAUGE_MM8013) += mm8013.o diff --git a/drivers/power/supply/mm8013.c b/drivers/power/supply/mm8013.c new file mode 100644 index 000000000000..bd8d54d6597f --- /dev/null +++ b/drivers/power/supply/mm8013.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Limited + */ +#include +#include +#include +#include + +#define REG_BATID 0x00 /* This one is very unclear */ + #define BATID_101 0x0101 /* 107kOhm */ + #define BATID_102 0x0102 /* 10kOhm */ +#define REG_TEMPERATURE 0x06 +#define REG_VOLTAGE 0x08 +#define REG_FLAGS 0x0a + #define MM8013_FLAG_OTC BIT(15) + #define MM8013_FLAG_OTD BIT(14) + #define MM8013_FLAG_BATHI BIT(13) + #define MM8013_FLAG_FC BIT(9) + #define MM8013_FLAG_CHG BIT(8) + #define MM8013_FLAG_DSG BIT(0) +#define REG_FULL_CHARGE_CAPACITY 0x0e +#define REG_AVERAGE_CURRENT 0x14 +#define REG_AVERAGE_TIME_TO_EMPTY 0x16 +#define REG_AVERAGE_TIME_TO_FULL 0x18 +#define REG_CYCLE_COUNT 0x2a +#define REG_STATE_OF_CHARGE 0x2c +#define REG_DESIGN_CAPACITY 0x3c +/* TODO: 0x62-0x68 seem to contain 'MM8013C' in a length-prefixed, non-terminated string */ + +#define DECIKELVIN_TO_DECIDEGC(t) (t - 2731) + +struct mm8013_chip { + struct i2c_client *client; + struct regmap *regmap; +}; + +static int mm8013_checkdevice(struct mm8013_chip *chip) +{ + int battery_id, ret; + u32 val; + + ret = regmap_write(chip->regmap, REG_BATID, 0x0008); + if (ret < 0) + return ret; + + regmap_read(chip->regmap, REG_BATID, &val); + if (ret < 0) + return ret; + + if (val == BATID_102) + battery_id = 2; + else if (val == BATID_101) + battery_id = 1; + else + return -EINVAL; + + dev_dbg(&chip->client->dev, "battery_id: %d\n", battery_id); + + return 0; +} + +static enum power_supply_property mm8013_battery_props[] = { + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + POWER_SUPPLY_PROP_VOLTAGE_NOW, +}; + +static int mm8013_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct mm8013_chip *chip = psy->drv_data; + int ret = 0; + u32 regval; + + switch (psp) { + case POWER_SUPPLY_PROP_CAPACITY: + ret = regmap_read(chip->regmap, REG_STATE_OF_CHARGE, ®val); + if (ret < 0) + return ret; + + val->intval = regval; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + ret = regmap_read(chip->regmap, REG_FULL_CHARGE_CAPACITY, ®val); + if (ret < 0) + return ret; + + val->intval = 1000 * regval; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + ret = regmap_read(chip->regmap, REG_DESIGN_CAPACITY, ®val); + if (ret < 0) + return ret; + + val->intval = 1000 * regval; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret = regmap_read(chip->regmap, REG_AVERAGE_CURRENT, ®val); + if (ret < 0) + return ret; + + val->intval = -1000 * (s16)regval; + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + ret = regmap_read(chip->regmap, REG_CYCLE_COUNT, ®val); + if (ret < 0) + return ret; + + val->intval = regval; + break; + case POWER_SUPPLY_PROP_HEALTH: + ret = regmap_read(chip->regmap, REG_FLAGS, ®val); + if (ret < 0) + return ret; + + if (regval & MM8013_FLAG_BATHI) + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + else if (regval & (MM8013_FLAG_OTD | MM8013_FLAG_OTC)) + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + else + val->intval = POWER_SUPPLY_HEALTH_GOOD; + break; + case POWER_SUPPLY_PROP_PRESENT: + ret = regmap_read(chip->regmap, REG_TEMPERATURE, ®val); + if (ret < 0) + return ret; + + val->intval = ((s16)regval > 0); + break; + case POWER_SUPPLY_PROP_STATUS: + ret = regmap_read(chip->regmap, REG_FLAGS, ®val); + if (ret < 0) + return ret; + + if (regval & MM8013_FLAG_DSG) + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + else if (regval & MM8013_FLAG_CHG) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else if (regval & MM8013_FLAG_FC) + val->intval = POWER_SUPPLY_STATUS_FULL; + else + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + break; + case POWER_SUPPLY_PROP_TEMP: + ret = regmap_read(chip->regmap, REG_TEMPERATURE, ®val); + if (ret < 0) + return ret; + + val->intval = DECIKELVIN_TO_DECIDEGC(regval); + break; + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: + ret = regmap_read(chip->regmap, REG_AVERAGE_TIME_TO_EMPTY, ®val); + if (ret < 0) + return ret; + + /* The estimation is not yet ready */ + if (regval == U16_MAX) + return -ENODATA; + + val->intval = regval; + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: + ret = regmap_read(chip->regmap, REG_AVERAGE_TIME_TO_FULL, ®val); + if (ret < 0) + return ret; + + /* The estimation is not yet ready */ + if (regval == U16_MAX) + return -ENODATA; + + val->intval = regval; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = regmap_read(chip->regmap, REG_VOLTAGE, ®val); + if (ret < 0) + return ret; + + val->intval = 1000 * regval; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct power_supply_desc mm8013_desc = { + .name = "mm8013", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = mm8013_battery_props, + .num_properties = ARRAY_SIZE(mm8013_battery_props), + .get_property = mm8013_get_property, +}; + +static const struct regmap_config mm8013_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = 0x68, + .use_single_read = true, + .use_single_write = true, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + +static int mm8013_probe(struct i2c_client *client) +{ + struct power_supply_config psy_cfg = {}; + struct device *dev = &client->dev; + struct power_supply *psy; + struct mm8013_chip *chip; + int ret = 0; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return dev_err_probe(dev, -EIO, + "I2C_FUNC_SMBUS_WORD_DATA not supported\n"); + + chip = devm_kzalloc(dev, sizeof(struct mm8013_chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->client = client; + + chip->regmap = devm_regmap_init_i2c(client, &mm8013_regmap_config); + if (IS_ERR(chip->regmap)) + return dev_err_probe(dev, ret, "Couldn't initialize regmap\n"); + + ret = mm8013_checkdevice(chip); + if (ret) + return dev_err_probe(dev, ret, "MM8013 not found\n"); + + psy_cfg.drv_data = chip; + psy_cfg.of_node = dev->of_node; + + psy = devm_power_supply_register(dev, &mm8013_desc, &psy_cfg); + if (IS_ERR(psy)) + return PTR_ERR(psy); + + return 0; +} + +static const struct i2c_device_id mm8013_id_table[] = { + { "mm8013", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, mm8013_id_table); + +static const struct of_device_id mm8013_match_table[] = { + { .compatible = "mitsumi,mm8013" }, + {} +}; + +static struct i2c_driver mm8013_i2c_driver = { + .probe = mm8013_probe, + .id_table = mm8013_id_table, + .driver = { + .name = "mm8013", + .of_match_table = mm8013_match_table, + }, +}; +module_i2c_driver(mm8013_i2c_driver); + +MODULE_DESCRIPTION("MM8013 fuel gauge driver"); +MODULE_LICENSE("GPL"); From 58e4aacb746321d8692996f40a1dcfb9e8b34c23 Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Fri, 15 Sep 2023 09:02:14 +0200 Subject: [PATCH 038/396] power: supply: Propagate of_node to child device Ensure that the dynamically created power supply device sets its ->of_node if the driver supplies one. This brings it in line with several other subsystems (see git grep 'of_node =.*parent.*of_node') and allows easier identification of the device from udev rules and similar. Before this patch: /sys/class/power_supply# ls -l bq256xx-battery/of_node ls: cannot access 'bq256xx-battery/of_node': No such file or directory # ls -l bq256xx-battery/hwmon1/of_node ls: cannot access 'bq256xx-battery/hwmon1/of_node': No such file or directory After: /sys/class/power_supply# ls -l bq256xx-battery/of_node lrwxrwxrwx 1 root root 0 May 17 09:14 bq256xx-battery/of_node -> ../../../../../../../../firmware/devicetree/base/virtio@1/i2c/bq25619@09 # ls -l bq256xx-battery/hwmon1/of_node lrwxrwxrwx 1 root root 0 May 17 09:14 bq256xx-battery/hwmon1/of_node -> ../../../../../../../../../firmware/devicetree/base/virtio@1/i2c/bq25619@09 Signed-off-by: Vincent Whitchurch Link: https://lore.kernel.org/r/20230915-power-of-v2-1-ca54c441867e@axis.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 416409e2fd6d..6e30674be366 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -1380,6 +1380,7 @@ __power_supply_register(struct device *parent, psy->drv_data = cfg->drv_data; psy->of_node = cfg->fwnode ? to_of_node(cfg->fwnode) : cfg->of_node; + dev->of_node = psy->of_node; psy->supplied_to = cfg->supplied_to; psy->num_supplicants = cfg->num_supplicants; } From 7f590e38317657123fed828d267372a3d6f93260 Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Fri, 15 Sep 2023 10:01:18 +0500 Subject: [PATCH 039/396] dt-bindings: power: supply: Add pm8916 VM-BMS Qualcomm Voltage Mode BMS is a battery monitoring block in PM8916 PMIC. Document it's DT binding. Signed-off-by: Nikita Travkin Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230915-pm8916-bms-lbc-v3-1-f30881e951a0@trvn.ru Signed-off-by: Sebastian Reichel --- .../power/supply/qcom,pm8916-bms-vm.yaml | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/qcom,pm8916-bms-vm.yaml diff --git a/Documentation/devicetree/bindings/power/supply/qcom,pm8916-bms-vm.yaml b/Documentation/devicetree/bindings/power/supply/qcom,pm8916-bms-vm.yaml new file mode 100644 index 000000000000..ad764e69ab57 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom,pm8916-bms-vm.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/qcom,pm8916-bms-vm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Voltage Mode BMS + +maintainers: + - Nikita Travkin + +description: + Voltage Mode BMS is a hardware block found in some Qualcomm PMICs + such as pm8916. This block performs battery voltage monitoring. + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + const: qcom,pm8916-bms-vm + + reg: + maxItems: 1 + + interrupts: + items: + - description: BMS FSM left S3 mode + - description: BMS FSM entered S2 mode + - description: OCV measured in S3 mode + - description: OCV below threshold + - description: FIFO update done + - description: BMS FSM switched state + + interrupt-names: + items: + - const: cv_leave + - const: cv_enter + - const: ocv_good + - const: ocv_thr + - const: fifo + - const: state_chg + + monitored-battery: true + + power-supplies: true + +required: + - compatible + - reg + - interrupts + - interrupt-names + - monitored-battery + +additionalProperties: false + +examples: + - | + #include + pmic { + #address-cells = <1>; + #size-cells = <0>; + + battery@4000 { + compatible = "qcom,pm8916-bms-vm"; + reg = <0x4000>; + interrupts = <0x0 0x40 0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 5 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "cv_leave", + "cv_enter", + "ocv_good", + "ocv_thr", + "fifo", + "state_chg"; + + monitored-battery = <&battery>; + power-supplies = <&pm8916_charger>; + }; + }; From 5cee843d56072135c0d4be4a2d8a20df05155009 Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Fri, 15 Sep 2023 10:01:19 +0500 Subject: [PATCH 040/396] dt-bindings: power: supply: Add pm8916 LBC Qualcomm Linear Battery Charger is a CC/CV charger block in PM8916 PMIC. Document it's DT binding. Signed-off-by: Nikita Travkin Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230915-pm8916-bms-lbc-v3-2-f30881e951a0@trvn.ru Signed-off-by: Sebastian Reichel --- .../power/supply/qcom,pm8916-lbc.yaml | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/qcom,pm8916-lbc.yaml diff --git a/Documentation/devicetree/bindings/power/supply/qcom,pm8916-lbc.yaml b/Documentation/devicetree/bindings/power/supply/qcom,pm8916-lbc.yaml new file mode 100644 index 000000000000..cdf14e5ed119 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom,pm8916-lbc.yaml @@ -0,0 +1,128 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/supply/qcom,pm8916-lbc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Linear Battery Charger + +maintainers: + - Nikita Travkin + +description: + Linear Battery Charger hardware block, found in some Qualcomm PMICs + such as pm8916. Implements a simple, autonomous CC/CV charger. + +allOf: + - $ref: power-supply.yaml# + +properties: + compatible: + const: qcom,pm8916-lbc + + reg: + items: + - description: Charger + - description: Battery + - description: USB + - description: MISC + + reg-names: + items: + - const: chgr + - const: bat_if + - const: usb + - const: misc + + interrupts: + items: + - description: Battery detection + - description: Fast charging + - description: Charging failed + - description: Charging done + - description: Battery present + - description: Battery temperature OK + - description: USB coarse detection + - description: USB IN valid + - description: Charger gone + - description: Overtemperature + + interrupt-names: + items: + - const: vbat_det + - const: fast_chg + - const: chg_fail + - const: chg_done + - const: bat_pres + - const: temp_ok + - const: coarse_det + - const: usb_vbus + - const: chg_gone + - const: overtemp + + qcom,fast-charge-safe-voltage: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 4000000 + maximum: 4775000 + description: + Maximum safe battery voltage in uV; May be pre-set by bootloader, + in which case, setting this will harmlessly fail. + + qcom,fast-charge-safe-current: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 90000 + maximum: 1440000 + description: + Maximum safe battery charge current in uA; May be pre-set by + bootloader, in which case setting this will harmlessly fail. + + monitored-battery: true + +required: + - compatible + - reg + - interrupts + - interrupt-names + - qcom,fast-charge-safe-voltage + - qcom,fast-charge-safe-current + +additionalProperties: false + +examples: + - | + #include + pmic { + #address-cells = <1>; + #size-cells = <0>; + + charger@1000 { + compatible = "qcom,pm8916-lbc"; + reg = <0x1000>, <0x1200>, <0x1300>, <0x1600>; + reg-names = "chgr", "bat_if", "usb", "misc"; + + interrupts = <0x0 0x10 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 6 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 4 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbat_det", + "fast_chg", + "chg_fail", + "chg_done", + "bat_pres", + "temp_ok", + "coarse_det", + "usb_vbus", + "chg_gone", + "overtemp"; + monitored-battery = <&battery>; + + qcom,fast-charge-safe-current = <900000>; + qcom,fast-charge-safe-voltage = <4300000>; + }; + }; From 098bce1838e0549228c8d426e5de72ec5594b5c4 Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Fri, 15 Sep 2023 10:01:20 +0500 Subject: [PATCH 041/396] power: supply: Add pm8916 VM-BMS support This driver adds basic support for VM-BMS found in pm8916. VM-BMS is a very basic fuel-gauge hardware block that is, sadly, incapable of any gauging. The hardware supports measuring OCV in sleep mode, where the battery is not in use, or measuring average voltage over time when the device is active. This driver implements basic value readout from this block. Signed-off-by: Nikita Travkin Link: https://lore.kernel.org/r/20230915-pm8916-bms-lbc-v3-3-f30881e951a0@trvn.ru Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 11 + drivers/power/supply/Makefile | 1 + drivers/power/supply/pm8916_bms_vm.c | 305 +++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 drivers/power/supply/pm8916_bms_vm.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index c816dc4265df..ed5b72b06dfa 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -629,6 +629,17 @@ config CHARGER_QCOM_SMBB documentation for more detail. The base name for this driver is 'pm8941_charger'. +config BATTERY_PM8916_BMS_VM + tristate "Qualcomm PM8916 BMS-VM support" + depends on MFD_SPMI_PMIC || COMPILE_TEST + help + Say Y to add support for Voltage Mode BMS block found in some + Qualcomm PMICs such as PM8916. This hardware block provides + battery voltage monitoring for the system. + + To compile this driver as module, choose M here: the + module will be called pm8916_bms_vm. + config CHARGER_BQ2415X tristate "TI BQ2415x battery charger driver" depends on I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index ba2c41f060be..fc82f0401a69 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o obj-$(CONFIG_CHARGER_MT6370) += mt6370-charger.o obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o +obj-$(CONFIG_BATTERY_PM8916_BMS_VM) += pm8916_bms_vm.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o diff --git a/drivers/power/supply/pm8916_bms_vm.c b/drivers/power/supply/pm8916_bms_vm.c new file mode 100644 index 000000000000..5d0dd842509c --- /dev/null +++ b/drivers/power/supply/pm8916_bms_vm.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Nikita Travkin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PM8916_PERPH_TYPE 0x04 +#define PM8916_BMS_VM_TYPE 0x020D + +#define PM8916_SEC_ACCESS 0xD0 +#define PM8916_SEC_MAGIC 0xA5 + +#define PM8916_BMS_VM_STATUS1 0x08 +#define PM8916_BMS_VM_FSM_STATE(x) (((x) & 0b00111000) >> 3) +#define PM8916_BMS_VM_FSM_STATE_S2 0x2 + +#define PM8916_BMS_VM_MODE_CTL 0x40 +#define PM8916_BMS_VM_MODE_FORCE_S3 (BIT(0) | BIT(1)) +#define PM8916_BMS_VM_MODE_NORMAL (BIT(1) | BIT(3)) + +#define PM8916_BMS_VM_EN_CTL 0x46 +#define PM8916_BMS_ENABLED BIT(7) + +#define PM8916_BMS_VM_FIFO_LENGTH_CTL 0x47 +#define PM8916_BMS_VM_S1_SAMPLE_INTERVAL_CTL 0x55 +#define PM8916_BMS_VM_S2_SAMPLE_INTERVAL_CTL 0x56 +#define PM8916_BMS_VM_S3_S7_OCV_DATA0 0x6A +#define PM8916_BMS_VM_BMS_FIFO_REG_0_LSB 0xC0 + +/* Using only 1 fifo is broken in hardware */ +#define PM8916_BMS_VM_FIFO_COUNT 2 /* 2 .. 8 */ + +#define PM8916_BMS_VM_S1_SAMPLE_INTERVAL 10 +#define PM8916_BMS_VM_S2_SAMPLE_INTERVAL 10 + +struct pm8916_bms_vm_battery { + struct device *dev; + struct power_supply *battery; + struct power_supply_battery_info *info; + struct regmap *regmap; + unsigned int reg; + unsigned int last_ocv; + time64_t last_ocv_time; + unsigned int vbat_now; +}; + +static int pm8916_bms_vm_battery_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pm8916_bms_vm_battery *bat = power_supply_get_drvdata(psy); + struct power_supply_battery_info *info = bat->info; + int supplied; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + supplied = power_supply_am_i_supplied(psy); + + if (supplied < 0 && supplied != -ENODEV) + return supplied; + else if (supplied && supplied != -ENODEV) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + + case POWER_SUPPLY_PROP_HEALTH: + if (bat->vbat_now < info->voltage_min_design_uv) + val->intval = POWER_SUPPLY_HEALTH_DEAD; + else if (bat->vbat_now > info->voltage_max_design_uv) + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + else + val->intval = POWER_SUPPLY_HEALTH_GOOD; + return 0; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = bat->vbat_now; + return 0; + + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + /* + * Hardware only reliably measures OCV when the system is off or suspended. + * We expose the last known OCV value on boot, invalidating it after 180 seconds. + */ + if (ktime_get_seconds() - bat->last_ocv_time > 180) + return -ENODATA; + + val->intval = bat->last_ocv; + return 0; + + default: + return -EINVAL; + } +} + +static enum power_supply_property pm8916_bms_vm_battery_properties[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_OCV, + POWER_SUPPLY_PROP_HEALTH, +}; + +static irqreturn_t pm8916_bms_vm_fifo_update_done_irq(int irq, void *data) +{ + struct pm8916_bms_vm_battery *bat = data; + u16 vbat_data[PM8916_BMS_VM_FIFO_COUNT]; + int ret; + + ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_BMS_VM_BMS_FIFO_REG_0_LSB, + &vbat_data, PM8916_BMS_VM_FIFO_COUNT * 2); + if (ret) + return IRQ_HANDLED; + + /* + * The VM-BMS hardware only collects voltage data and the software + * has to process it to calculate the OCV and SoC. Hardware provides + * up to 8 averaged measurements for software to take in account. + * + * Just use the last measured value for now to report the current + * battery voltage. + */ + bat->vbat_now = vbat_data[PM8916_BMS_VM_FIFO_COUNT - 1] * 300; + + power_supply_changed(bat->battery); + + return IRQ_HANDLED; +} + +static const struct power_supply_desc pm8916_bms_vm_battery_psy_desc = { + .name = "pm8916-bms-vm", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = pm8916_bms_vm_battery_properties, + .num_properties = ARRAY_SIZE(pm8916_bms_vm_battery_properties), + .get_property = pm8916_bms_vm_battery_get_property, +}; + +static int pm8916_bms_vm_battery_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pm8916_bms_vm_battery *bat; + struct power_supply_config psy_cfg = {}; + int ret, irq; + unsigned int tmp; + + bat = devm_kzalloc(dev, sizeof(*bat), GFP_KERNEL); + if (!bat) + return -ENOMEM; + + bat->dev = dev; + + bat->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!bat->regmap) + return -ENODEV; + + ret = device_property_read_u32(dev, "reg", &bat->reg); + if (ret < 0) + return -EINVAL; + + irq = platform_get_irq_byname(pdev, "fifo"); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_bms_vm_fifo_update_done_irq, + IRQF_ONESHOT, "pm8916_vm_bms", bat); + if (ret) + return ret; + + ret = regmap_bulk_read(bat->regmap, bat->reg + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + + if (tmp != PM8916_BMS_VM_TYPE) + return dev_err_probe(dev, -ENODEV, "Device reported wrong type: 0x%X\n", tmp); + + ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_S1_SAMPLE_INTERVAL_CTL, + PM8916_BMS_VM_S1_SAMPLE_INTERVAL); + if (ret) + goto comm_error; + ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_S2_SAMPLE_INTERVAL_CTL, + PM8916_BMS_VM_S2_SAMPLE_INTERVAL); + if (ret) + goto comm_error; + ret = regmap_write(bat->regmap, bat->reg + PM8916_BMS_VM_FIFO_LENGTH_CTL, + PM8916_BMS_VM_FIFO_COUNT << 4 | PM8916_BMS_VM_FIFO_COUNT); + if (ret) + goto comm_error; + ret = regmap_write(bat->regmap, + bat->reg + PM8916_BMS_VM_EN_CTL, PM8916_BMS_ENABLED); + if (ret) + goto comm_error; + + ret = regmap_bulk_read(bat->regmap, + bat->reg + PM8916_BMS_VM_S3_S7_OCV_DATA0, &tmp, 2); + if (ret) + goto comm_error; + + bat->last_ocv_time = ktime_get_seconds(); + bat->last_ocv = tmp * 300; + bat->vbat_now = bat->last_ocv; + + psy_cfg.drv_data = bat; + psy_cfg.of_node = dev->of_node; + + bat->battery = devm_power_supply_register(dev, &pm8916_bms_vm_battery_psy_desc, &psy_cfg); + if (IS_ERR(bat->battery)) + return dev_err_probe(dev, PTR_ERR(bat->battery), "Unable to register battery\n"); + + ret = power_supply_get_battery_info(bat->battery, &bat->info); + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + + platform_set_drvdata(pdev, bat); + + return 0; + +comm_error: + return dev_err_probe(dev, ret, "Unable to communicate with device\n"); +} + +static int pm8916_bms_vm_battery_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct pm8916_bms_vm_battery *bat = platform_get_drvdata(pdev); + int ret; + + /* + * Due to a hardware quirk the FSM doesn't switch states normally. + * Instead we unlock the debug registers and force S3 (Measure OCV/Sleep) + * mode every time we suspend. + */ + + ret = regmap_write(bat->regmap, + bat->reg + PM8916_SEC_ACCESS, PM8916_SEC_MAGIC); + if (ret) + goto error; + ret = regmap_write(bat->regmap, + bat->reg + PM8916_BMS_VM_MODE_CTL, PM8916_BMS_VM_MODE_FORCE_S3); + if (ret) + goto error; + + return 0; + +error: + dev_err(bat->dev, "Failed to force S3 mode: %pe\n", ERR_PTR(ret)); + return ret; +} + +static int pm8916_bms_vm_battery_resume(struct platform_device *pdev) +{ + struct pm8916_bms_vm_battery *bat = platform_get_drvdata(pdev); + int ret; + unsigned int tmp; + + ret = regmap_bulk_read(bat->regmap, + bat->reg + PM8916_BMS_VM_S3_S7_OCV_DATA0, &tmp, 2); + + bat->last_ocv_time = ktime_get_seconds(); + bat->last_ocv = tmp * 300; + + ret = regmap_write(bat->regmap, + bat->reg + PM8916_SEC_ACCESS, PM8916_SEC_MAGIC); + if (ret) + goto error; + ret = regmap_write(bat->regmap, + bat->reg + PM8916_BMS_VM_MODE_CTL, PM8916_BMS_VM_MODE_NORMAL); + if (ret) + goto error; + + return 0; + +error: + dev_err(bat->dev, "Failed to return normal mode: %pe\n", ERR_PTR(ret)); + return ret; +} + +static const struct of_device_id pm8916_bms_vm_battery_of_match[] = { + { .compatible = "qcom,pm8916-bms-vm", }, + {} +}; +MODULE_DEVICE_TABLE(of, pm8916_bms_vm_battery_of_match); + +static struct platform_driver pm8916_bms_vm_battery_driver = { + .driver = { + .name = "pm8916-bms-vm", + .of_match_table = pm8916_bms_vm_battery_of_match, + }, + .probe = pm8916_bms_vm_battery_probe, + .suspend = pm8916_bms_vm_battery_suspend, + .resume = pm8916_bms_vm_battery_resume, +}; +module_platform_driver(pm8916_bms_vm_battery_driver); + +MODULE_DESCRIPTION("pm8916 BMS-VM driver"); +MODULE_AUTHOR("Nikita Travkin "); +MODULE_LICENSE("GPL"); From f8d7a3d21160a0cab4d15b81231f2a76b0fcee13 Mon Sep 17 00:00:00 2001 From: Nikita Travkin Date: Fri, 15 Sep 2023 10:01:21 +0500 Subject: [PATCH 042/396] power: supply: Add driver for pm8916 lbc pm8916 LBC is a Linear Battery Charger hardware block in pm8916 PMIC. This block implements simple CC/CV charging for Li-Po batteries. The hardware has internal state machine to switch between modes and works mostly autonomously, only needing the limits and targets to be set to operate. This driver allows setting limits and enabling the LBC block, monitoring it's state. Signed-off-by: Nikita Travkin Link: https://lore.kernel.org/r/20230915-pm8916-bms-lbc-v3-4-f30881e951a0@trvn.ru Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 11 + drivers/power/supply/Makefile | 1 + drivers/power/supply/pm8916_lbc.c | 381 ++++++++++++++++++++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 drivers/power/supply/pm8916_lbc.c diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index ed5b72b06dfa..4bfd5a336163 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -640,6 +640,17 @@ config BATTERY_PM8916_BMS_VM To compile this driver as module, choose M here: the module will be called pm8916_bms_vm. +config CHARGER_PM8916_LBC + tristate "Qualcomm PM8916 Linear Battery Charger support" + depends on MFD_SPMI_PMIC || COMPILE_TEST + help + Say Y here to add support for Linear Battery Charger block + found in some Qualcomm PMICs such as PM8916. This hardware + blokc provides simple CC/CV battery charger. + + To compile this driver as module, choose M here: the + module will be called pm8916_lbc. + config CHARGER_BQ2415X tristate "TI BQ2415x battery charger driver" depends on I2C diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index fc82f0401a69..58b567278034 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -85,6 +85,7 @@ obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o obj-$(CONFIG_CHARGER_MT6370) += mt6370-charger.o obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o obj-$(CONFIG_BATTERY_PM8916_BMS_VM) += pm8916_bms_vm.o +obj-$(CONFIG_CHARGER_PM8916_LBC) += pm8916_lbc.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c new file mode 100644 index 000000000000..6d92e98cbecc --- /dev/null +++ b/drivers/power/supply/pm8916_lbc.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Nikita Travkin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Two bytes: type + subtype */ +#define PM8916_PERPH_TYPE 0x04 +#define PM8916_LBC_CHGR_TYPE 0x1502 +#define PM8916_LBC_BAT_IF_TYPE 0x1602 +#define PM8916_LBC_USB_TYPE 0x1702 +#define PM8916_LBC_MISC_TYPE 0x1802 + +#define PM8916_LBC_CHGR_CHG_OPTION 0x08 +#define PM8916_LBC_CHGR_PMIC_CHARGER BIT(7) + +#define PM8916_LBC_CHGR_CHG_STATUS 0x09 + +#define PM8916_INT_RT_STS 0x10 + +#define PM8916_LBC_USB_USBIN_VALID BIT(1) + +#define PM8916_LBC_CHGR_VDD_MAX 0x40 +#define PM8916_LBC_CHGR_VDD_SAFE 0x41 +#define PM8916_LBC_CHGR_IBAT_MAX 0x44 +#define PM8916_LBC_CHGR_IBAT_SAFE 0x45 + +#define PM8916_LBC_CHGR_TCHG_MAX_EN 0x60 +#define PM8916_LBC_CHGR_TCHG_MAX_ENABLED BIT(7) +#define PM8916_LBC_CHGR_TCHG_MAX 0x61 + +#define PM8916_LBC_CHGR_CHG_CTRL 0x49 +#define PM8916_LBC_CHGR_CHG_EN BIT(7) +#define PM8916_LBC_CHGR_PSTG_EN BIT(5) + +#define PM8916_LBC_CHGR_MIN_CURRENT 90000 +#define PM8916_LBC_CHGR_MAX_CURRENT 1440000 + +#define PM8916_LBC_CHGR_MIN_VOLTAGE 4000000 +#define PM8916_LBC_CHGR_MAX_VOLTAGE 4775000 +#define PM8916_LBC_CHGR_VOLTAGE_STEP 25000 + +#define PM8916_LBC_CHGR_MIN_TIME 4 +#define PM8916_LBC_CHGR_MAX_TIME 256 + +struct pm8916_lbc_charger { + struct device *dev; + struct extcon_dev *edev; + struct power_supply *charger; + struct power_supply_battery_info *info; + struct regmap *regmap; + unsigned int reg[4]; + bool online; + unsigned int charge_voltage_max; + unsigned int charge_voltage_safe; + unsigned int charge_current_max; + unsigned int charge_current_safe; +}; + +static const unsigned int pm8916_lbc_charger_cable[] = { + EXTCON_USB, + EXTCON_NONE, +}; + +enum { + LBC_CHGR = 0, + LBC_BAT_IF, + LBC_USB, + LBC_MISC, +}; + +static int pm8916_lbc_charger_configure(struct pm8916_lbc_charger *chg) +{ + int ret = 0; + unsigned int tmp; + + chg->charge_voltage_max = clamp_t(u32, chg->charge_voltage_max, + PM8916_LBC_CHGR_MIN_VOLTAGE, chg->charge_voltage_safe); + + tmp = chg->charge_voltage_max - PM8916_LBC_CHGR_MIN_VOLTAGE; + tmp /= PM8916_LBC_CHGR_VOLTAGE_STEP; + chg->charge_voltage_max = PM8916_LBC_CHGR_MIN_VOLTAGE + tmp * PM8916_LBC_CHGR_VOLTAGE_STEP; + + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_MAX, tmp); + if (ret) + goto error; + + chg->charge_current_max = min(chg->charge_current_max, chg->charge_current_safe); + + tmp = clamp_t(u32, chg->charge_current_max, + PM8916_LBC_CHGR_MIN_CURRENT, PM8916_LBC_CHGR_MAX_CURRENT); + + tmp = chg->charge_current_max / PM8916_LBC_CHGR_MIN_CURRENT - 1; + chg->charge_current_max = (tmp + 1) * PM8916_LBC_CHGR_MIN_CURRENT; + + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_IBAT_MAX, tmp); + if (ret) + goto error; + + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_CHG_CTRL, + PM8916_LBC_CHGR_CHG_EN | PM8916_LBC_CHGR_PSTG_EN); + if (ret) + goto error; + + return ret; + +error: + dev_err(chg->dev, "Failed to configure charging: %pe\n", ERR_PTR(ret)); + return ret; +} + +static int pm8916_lbc_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pm8916_lbc_charger *chg = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = chg->online; + return 0; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + val->intval = chg->charge_voltage_max; + return 0; + + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + val->intval = chg->charge_current_max; + return 0; + + default: + return -EINVAL; + }; +} + +static int pm8916_lbc_charger_set_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + struct pm8916_lbc_charger *chg = power_supply_get_drvdata(psy); + + switch (prop) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + chg->charge_current_max = val->intval; + return pm8916_lbc_charger_configure(chg); + default: + return -EINVAL; + } +} + +static int pm8916_lbc_charger_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + return true; + default: + return false; + } +} + +static enum power_supply_property pm8916_lbc_charger_properties[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, +}; + +static irqreturn_t pm8916_lbc_charger_state_changed_irq(int irq, void *data) +{ + struct pm8916_lbc_charger *chg = data; + unsigned int tmp; + int ret; + + ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp); + if (ret) + return IRQ_HANDLED; + + chg->online = !!(tmp & PM8916_LBC_USB_USBIN_VALID); + extcon_set_state_sync(chg->edev, EXTCON_USB, chg->online); + + power_supply_changed(chg->charger); + + return IRQ_HANDLED; +} + +static int pm8916_lbc_charger_probe_dt(struct pm8916_lbc_charger *chg) +{ + struct device *dev = chg->dev; + int ret = 0; + unsigned int tmp; + + ret = device_property_read_u32(dev, "qcom,fast-charge-safe-voltage", &chg->charge_voltage_safe); + if (ret) + return ret; + if (chg->charge_voltage_safe < PM8916_LBC_CHGR_MIN_VOLTAGE) + return -EINVAL; + + chg->charge_voltage_safe = clamp_t(u32, chg->charge_voltage_safe, + PM8916_LBC_CHGR_MIN_VOLTAGE, PM8916_LBC_CHGR_MAX_VOLTAGE); + + tmp = chg->charge_voltage_safe - PM8916_LBC_CHGR_MIN_VOLTAGE; + tmp /= PM8916_LBC_CHGR_VOLTAGE_STEP; + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_VDD_SAFE, tmp); + if (ret) + return ret; + + ret = device_property_read_u32(dev, "qcom,fast-charge-safe-current", &chg->charge_current_safe); + if (ret) + return ret; + if (chg->charge_current_safe < PM8916_LBC_CHGR_MIN_CURRENT) + return -EINVAL; + + chg->charge_current_safe = clamp_t(u32, chg->charge_current_safe, + PM8916_LBC_CHGR_MIN_CURRENT, PM8916_LBC_CHGR_MAX_CURRENT); + + chg->charge_current_max = chg->charge_current_safe; + + tmp = chg->charge_current_safe / PM8916_LBC_CHGR_MIN_CURRENT - 1; + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_IBAT_SAFE, tmp); + if (ret) + return ret; + + /* Disable charger timeout. */ + ret = regmap_write(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_TCHG_MAX_EN, 0x00); + if (ret) + return ret; + + return ret; +} + +static const struct power_supply_desc pm8916_lbc_charger_psy_desc = { + .name = "pm8916-lbc-chgr", + .type = POWER_SUPPLY_TYPE_USB, + .properties = pm8916_lbc_charger_properties, + .num_properties = ARRAY_SIZE(pm8916_lbc_charger_properties), + .get_property = pm8916_lbc_charger_get_property, + .set_property = pm8916_lbc_charger_set_property, + .property_is_writeable = pm8916_lbc_charger_property_is_writeable, +}; + +static int pm8916_lbc_charger_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pm8916_lbc_charger *chg; + struct power_supply_config psy_cfg = {}; + int ret, len, irq; + unsigned int tmp; + + chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL); + if (!chg) + return -ENOMEM; + + chg->dev = dev; + + chg->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chg->regmap) + return -ENODEV; + + len = device_property_count_u32(dev, "reg"); + if (len < 0) + return len; + if (len != 4) + return dev_err_probe(dev, -EINVAL, + "Wrong amount of reg values: %d (4 expected)\n", len); + + irq = platform_get_irq_byname(pdev, "usb_vbus"); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, NULL, pm8916_lbc_charger_state_changed_irq, + IRQF_ONESHOT, "pm8916_lbc", chg); + if (ret) + return ret; + + ret = device_property_read_u32_array(dev, "reg", chg->reg, len); + if (ret) + return ret; + + ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_CHGR] + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_CHGR_TYPE) + goto type_error; + + ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_BAT_IF] + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_BAT_IF_TYPE) + goto type_error; + + ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_USB] + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_USB_TYPE) + goto type_error; + + ret = regmap_bulk_read(chg->regmap, chg->reg[LBC_MISC] + PM8916_PERPH_TYPE, &tmp, 2); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_MISC_TYPE) + goto type_error; + + ret = regmap_read(chg->regmap, chg->reg[LBC_CHGR] + PM8916_LBC_CHGR_CHG_OPTION, &tmp); + if (ret) + goto comm_error; + if (tmp != PM8916_LBC_CHGR_PMIC_CHARGER) + dev_err_probe(dev, -ENODEV, "The system is using an external charger\n"); + + ret = pm8916_lbc_charger_probe_dt(chg); + if (ret) + dev_err_probe(dev, ret, "Error while parsing device tree\n"); + + psy_cfg.drv_data = chg; + psy_cfg.of_node = dev->of_node; + + chg->charger = devm_power_supply_register(dev, &pm8916_lbc_charger_psy_desc, &psy_cfg); + if (IS_ERR(chg->charger)) + return dev_err_probe(dev, PTR_ERR(chg->charger), "Unable to register charger\n"); + + ret = power_supply_get_battery_info(chg->charger, &chg->info); + if (ret) + return dev_err_probe(dev, ret, "Unable to get battery info\n"); + + chg->edev = devm_extcon_dev_allocate(dev, pm8916_lbc_charger_cable); + if (IS_ERR(chg->edev)) + return PTR_ERR(chg->edev); + + ret = devm_extcon_dev_register(dev, chg->edev); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to register extcon device\n"); + + ret = regmap_read(chg->regmap, chg->reg[LBC_USB] + PM8916_INT_RT_STS, &tmp); + if (ret) + goto comm_error; + + chg->online = !!(tmp & PM8916_LBC_USB_USBIN_VALID); + extcon_set_state_sync(chg->edev, EXTCON_USB, chg->online); + + chg->charge_voltage_max = chg->info->voltage_max_design_uv; + ret = pm8916_lbc_charger_configure(chg); + if (ret) + return ret; + + return 0; + +comm_error: + return dev_err_probe(dev, ret, "Unable to communicate with device\n"); + +type_error: + return dev_err_probe(dev, -ENODEV, "Device reported wrong type: 0x%X\n", tmp); +} + +static const struct of_device_id pm8916_lbc_charger_of_match[] = { + { .compatible = "qcom,pm8916-lbc", }, + {} +}; +MODULE_DEVICE_TABLE(of, pm8916_lbc_charger_of_match); + +static struct platform_driver pm8916_lbc_charger_driver = { + .driver = { + .name = "pm8916-lbc", + .of_match_table = pm8916_lbc_charger_of_match, + }, + .probe = pm8916_lbc_charger_probe, +}; +module_platform_driver(pm8916_lbc_charger_driver); + +MODULE_DESCRIPTION("pm8916 LBC driver"); +MODULE_AUTHOR("Nikita Travkin "); +MODULE_LICENSE("GPL"); From e39257cde7e8ceec6165f54b6e20c72e2862a0b1 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sat, 16 Sep 2023 02:31:59 +0200 Subject: [PATCH 043/396] power: supply: mm8013: Add more properties While scanning the internet for MM8013 PDFs, I found one for a different IC from Mitsumi, MM8118 at [1]. It turned out however, that when you search through the PDF, the MM8118 text has an invsible text layer containing "MM8013" underneath.. With some elbow grease, I was able to confirm that most of the registers match between the two ICs. Based on that finding, introduce live battery voltage readout, hw-decided charge behavior readout and max current readout. Also, expand the existing POWER_SUPPLY_HEALTH reporting. [1] https://product.minebeamitsumi.com/en/product/category/ics/battery/fuel_gauge/parts/download/__icsFiles/afieldfile/2023/07/12/1_download_01_12.pdf Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230916-topic-mm8013_2-v1-1-02495e07fca0@linaro.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/mm8013.c | 45 +++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/mm8013.c b/drivers/power/supply/mm8013.c index bd8d54d6597f..ddac40ef9ae5 100644 --- a/drivers/power/supply/mm8013.c +++ b/drivers/power/supply/mm8013.c @@ -17,13 +17,21 @@ #define MM8013_FLAG_OTC BIT(15) #define MM8013_FLAG_OTD BIT(14) #define MM8013_FLAG_BATHI BIT(13) + #define MM8013_FLAG_BATLOW BIT(12) + #define MM8013_FLAG_CHG_INH BIT(11) #define MM8013_FLAG_FC BIT(9) #define MM8013_FLAG_CHG BIT(8) + #define MM8013_FLAG_OCC BIT(6) + #define MM8013_FLAG_ODC BIT(5) + #define MM8013_FLAG_OT BIT(4) + #define MM8013_FLAG_UT BIT(3) #define MM8013_FLAG_DSG BIT(0) #define REG_FULL_CHARGE_CAPACITY 0x0e +#define REG_NOMINAL_CHARGE_CAPACITY 0x0c #define REG_AVERAGE_CURRENT 0x14 #define REG_AVERAGE_TIME_TO_EMPTY 0x16 #define REG_AVERAGE_TIME_TO_FULL 0x18 +#define REG_MAX_LOAD_CURRENT 0x1e #define REG_CYCLE_COUNT 0x2a #define REG_STATE_OF_CHARGE 0x2c #define REG_DESIGN_CAPACITY 0x3c @@ -63,8 +71,11 @@ static int mm8013_checkdevice(struct mm8013_chip *chip) static enum power_supply_property mm8013_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_HEALTH, @@ -92,6 +103,16 @@ static int mm8013_get_property(struct power_supply *psy, val->intval = regval; break; + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: + ret = regmap_read(chip->regmap, REG_FLAGS, ®val); + if (ret < 0) + return ret; + + if (regval & MM8013_FLAG_CHG_INH) + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; + else + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; + break; case POWER_SUPPLY_PROP_CHARGE_FULL: ret = regmap_read(chip->regmap, REG_FULL_CHARGE_CAPACITY, ®val); if (ret < 0) @@ -106,6 +127,20 @@ static int mm8013_get_property(struct power_supply *psy, val->intval = 1000 * regval; break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + ret = regmap_read(chip->regmap, REG_NOMINAL_CHARGE_CAPACITY, ®val); + if (ret < 0) + return ret; + + val->intval = 1000 * regval; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + ret = regmap_read(chip->regmap, REG_MAX_LOAD_CURRENT, ®val); + if (ret < 0) + return ret; + + val->intval = -1000 * (s16)regval; + break; case POWER_SUPPLY_PROP_CURRENT_NOW: ret = regmap_read(chip->regmap, REG_AVERAGE_CURRENT, ®val); if (ret < 0) @@ -125,9 +160,15 @@ static int mm8013_get_property(struct power_supply *psy, if (ret < 0) return ret; - if (regval & MM8013_FLAG_BATHI) + if (regval & MM8013_FLAG_UT) + val->intval = POWER_SUPPLY_HEALTH_COLD; + else if (regval & (MM8013_FLAG_ODC | MM8013_FLAG_OCC)) + val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT; + else if (regval & (MM8013_FLAG_BATLOW)) + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; + else if (regval & MM8013_FLAG_BATHI) val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - else if (regval & (MM8013_FLAG_OTD | MM8013_FLAG_OTC)) + else if (regval & (MM8013_FLAG_OT | MM8013_FLAG_OTD | MM8013_FLAG_OTC)) val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; else val->intval = POWER_SUPPLY_HEALTH_GOOD; From 12e94aee074ce1c5ffdb8f2246a8c4a095b6aa8a Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Wed, 13 Sep 2023 15:39:00 +0200 Subject: [PATCH 044/396] power: supply: core: Don't export power_supply_notifier power_supply_notifier can be internal, since all users are going through power_supply_reg_notifier()/power_supply_unreg_notifier(). Link: https://lore.kernel.org/r/20230913133900.591637-1-sebastian.reichel@collabora.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_core.c | 3 +-- include/linux/power_supply.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 6e30674be366..73265001dd4b 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -29,8 +29,7 @@ struct class *power_supply_class; EXPORT_SYMBOL_GPL(power_supply_class); -BLOCKING_NOTIFIER_HEAD(power_supply_notifier); -EXPORT_SYMBOL_GPL(power_supply_notifier); +static BLOCKING_NOTIFIER_HEAD(power_supply_notifier); static struct device_type power_supply_dev_type; diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 85b86768c0b9..c0992a77feea 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -767,7 +767,6 @@ struct power_supply_battery_info { int bti_resistance_tolerance; }; -extern struct blocking_notifier_head power_supply_notifier; extern int power_supply_reg_notifier(struct notifier_block *nb); extern void power_supply_unreg_notifier(struct notifier_block *nb); #if IS_ENABLED(CONFIG_POWER_SUPPLY) From 17939df3c9acd26e4dac1c5943dd8e58e1bcb4e7 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 12 Sep 2023 07:51:30 +0300 Subject: [PATCH 045/396] clk: renesas: rzg2l: Use core->name for clock name core->name already contains the clock name thus, there is no need to check the GET_SHIFT(core->conf) to decide on it. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230912045157.177966-11-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 47f488387f33..a1e820d2eb9e 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -265,7 +265,7 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, clk_hw_data->priv = priv; clk_hw_data->conf = core->conf; - init.name = GET_SHIFT(core->conf) ? "sd1" : "sd0"; + init.name = core->name; init.ops = &rzg2l_cpg_sd_clk_mux_ops; init.flags = 0; init.num_parents = core->num_parents; From becf4a771a12b52dc5b3d2b089598d5603f3bbec Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 12 Sep 2023 07:51:31 +0300 Subject: [PATCH 046/396] clk: renesas: rzg2l: Simplify the logic in rzg2l_mod_clock_endisable() The bitmask << 16 is anyway set on both branches of if thus move it before the if and set the lower bits of registers only in case clock is enabled. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230912045157.177966-12-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index a1e820d2eb9e..115e19823b70 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -909,10 +909,9 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable) enable ? "ON" : "OFF"); spin_lock_irqsave(&priv->rmw_lock, flags); + value = bitmask << 16; if (enable) - value = (bitmask << 16) | bitmask; - else - value = bitmask << 16; + value |= bitmask; writel(value, priv->base + CLK_ON_R(reg)); spin_unlock_irqrestore(&priv->rmw_lock, flags); From 72977f07b035e488c3f1928832a1616c6cae7278 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 12 Sep 2023 07:51:33 +0300 Subject: [PATCH 047/396] clk: renesas: rzg2l: Use FIELD_GET() for PLL register fields Use FIELD_GET() for PLL register fields. This is its purpose. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230912045157.177966-14-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 115e19823b70..9baae7bb7094 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -11,6 +11,7 @@ * Copyright (C) 2015 Renesas Electronics Corp. */ +#include #include #include #include @@ -38,14 +39,13 @@ #define WARN_DEBUG(x) do { } while (0) #endif -#define DIV_RSMASK(v, s, m) ((v >> s) & m) #define GET_SHIFT(val) ((val >> 12) & 0xff) #define GET_WIDTH(val) ((val >> 8) & 0xf) -#define KDIV(val) DIV_RSMASK(val, 16, 0xffff) -#define MDIV(val) DIV_RSMASK(val, 6, 0x3ff) -#define PDIV(val) DIV_RSMASK(val, 0, 0x3f) -#define SDIV(val) DIV_RSMASK(val, 0, 0x7) +#define KDIV(val) FIELD_GET(GENMASK(31, 16), val) +#define MDIV(val) FIELD_GET(GENMASK(15, 6), val) +#define PDIV(val) FIELD_GET(GENMASK(5, 0), val) +#define SDIV(val) FIELD_GET(GENMASK(2, 0), val) #define CLK_ON_R(reg) (reg) #define CLK_MON_R(reg) (0x180 + (reg)) From 897a3e34d6e73d2386715d5c44c57992f2c0eada Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 12 Sep 2023 07:51:34 +0300 Subject: [PATCH 048/396] clk: renesas: rzg2l: Use u32 for flag and mux_flags flag and mux_flags are intended to keep bit masks. Use u32 type for it. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230912045157.177966-15-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 6cee9e56acc7..0b28870a6f9d 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -92,8 +92,8 @@ struct cpg_core_clk { unsigned int conf; const struct clk_div_table *dtable; const char * const *parent_names; - int flag; - int mux_flags; + u32 flag; + u32 mux_flags; int num_parents; }; From 80374a7fbf7af69bb81b6e4311f2018205b62644 Mon Sep 17 00:00:00 2001 From: Ralph Siemsen Date: Wed, 13 Sep 2023 16:38:04 -0400 Subject: [PATCH 049/396] clk: renesas: r9a06g032: Fix kerneldoc warning Mention the 'dual' structure in the kdoc. This fixes the following W=1 warning during build: > drivers/clk/renesas/r9a06g032-clocks.c:119: warning: Function parameter or member 'dual' not described in 'r9a06g032_clkdesc' Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202309101314.kTRoxND5-lkp@intel.com/ Signed-off-by: Ralph Siemsen Reviewed-by: Miquel Raynal Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230913203805.465780-1-ralph.siemsen@linaro.org Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a06g032-clocks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c index 9a50166c02b9..5f91bc8348b3 100644 --- a/drivers/clk/renesas/r9a06g032-clocks.c +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -109,6 +109,7 @@ enum gate_type { * must be in ascending order, zero for unused * @div: divisor for fixed-factor clock * @mul: multiplier for fixed-factor clock + * @dual: substructure for dual clock gates * @group: UART group, 0=UART0/1/2, 1=UART3/4/5/6/7 * @sel: select either g1/r1 or g2/r2 as clock source * @g1: 1st source gate (clock enable/disable) From fbb991530fdcf1150bc23c83775c338059f4f642 Mon Sep 17 00:00:00 2001 From: Ralph Siemsen Date: Wed, 13 Sep 2023 16:38:05 -0400 Subject: [PATCH 050/396] clk: renesas: r9a06g032: Name anonymous structs Clarify the content of the r9a06g032_clkdesc structure by naming the remaining anonymous structures defined inside. Renaming each field and updating the doc then becomes necessary in order to avoid name duplications and kdoc warnings. Signed-off-by: Ralph Siemsen Reviewed-by: Miquel Raynal Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230913203805.465780-2-ralph.siemsen@linaro.org Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a06g032-clocks.c | 63 ++++++++++++++------------ 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c index 5f91bc8348b3..c1348e2d450c 100644 --- a/drivers/clk/renesas/r9a06g032-clocks.c +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -102,20 +102,22 @@ enum gate_type { * @source: the ID+1 of the parent clock element. * Root clock uses ID of ~0 (PARENT_ID); * @gate: clock enable/disable - * @div_min: smallest permitted clock divider - * @div_max: largest permitted clock divider - * @reg: clock divider register offset, in 32-bit words - * @div_table: optional list of fixed clock divider values; + * @div: substructure for clock divider + * @div.min: smallest permitted clock divider + * @div.max: largest permitted clock divider + * @div.reg: clock divider register offset, in 32-bit words + * @div.table: optional list of fixed clock divider values; * must be in ascending order, zero for unused - * @div: divisor for fixed-factor clock - * @mul: multiplier for fixed-factor clock + * @ffc: substructure for fixed-factor clocks + * @ffc.div: divisor for fixed-factor clock + * @ffc.mul: multiplier for fixed-factor clock * @dual: substructure for dual clock gates - * @group: UART group, 0=UART0/1/2, 1=UART3/4/5/6/7 - * @sel: select either g1/r1 or g2/r2 as clock source - * @g1: 1st source gate (clock enable/disable) - * @r1: 1st source reset (module reset) - * @g2: 2nd source gate (clock enable/disable) - * @r2: 2nd source reset (module reset) + * @dual.group: UART group, 0=UART0/1/2, 1=UART3/4/5/6/7 + * @dual.sel: select either g1/r1 or g2/r2 as clock source + * @dual.g1: 1st source gate (clock enable/disable) + * @dual.r1: 1st source reset (module reset) + * @dual.g2: 2nd source gate (clock enable/disable) + * @dual.r2: 2nd source reset (module reset) * * Describes a single element in the clock tree hierarchy. * As there are quite a large number of clock elements, this @@ -132,13 +134,13 @@ struct r9a06g032_clkdesc { struct r9a06g032_gate gate; /* type = K_DIV */ struct { - unsigned int div_min:10, div_max:10, reg:10; - u16 div_table[4]; - }; + unsigned int min:10, max:10, reg:10; + u16 table[4]; + } div; /* type = K_FFC */ struct { u16 div, mul; - }; + } ffc; /* type = K_DUALGATE */ struct { uint16_t group:1; @@ -179,26 +181,26 @@ struct r9a06g032_clkdesc { .type = K_FFC, \ .index = R9A06G032_##_idx, \ .name = _n, \ - .div = _div, \ - .mul = _mul \ + .ffc.div = _div, \ + .ffc.mul = _mul \ } #define D_FFC(_idx, _n, _src, _div) { \ .type = K_FFC, \ .index = R9A06G032_##_idx, \ .source = 1 + R9A06G032_##_src, \ .name = _n, \ - .div = _div, \ - .mul = 1 \ + .ffc.div = _div, \ + .ffc.mul = 1 \ } #define D_DIV(_idx, _n, _src, _reg, _min, _max, ...) { \ .type = K_DIV, \ .index = R9A06G032_##_idx, \ .source = 1 + R9A06G032_##_src, \ .name = _n, \ - .reg = _reg, \ - .div_min = _min, \ - .div_max = _max, \ - .div_table = { __VA_ARGS__ } \ + .div.reg = _reg, \ + .div.min = _min, \ + .div.max = _max, \ + .div.table = { __VA_ARGS__ } \ } #define D_UGATE(_idx, _n, _src, _g, _g1, _r1, _g2, _r2) { \ .type = K_DUALGATE, \ @@ -1064,14 +1066,14 @@ r9a06g032_register_div(struct r9a06g032_priv *clocks, div->clocks = clocks; div->index = desc->index; - div->reg = desc->reg; + div->reg = desc->div.reg; div->hw.init = &init; - div->min = desc->div_min; - div->max = desc->div_max; + div->min = desc->div.min; + div->max = desc->div.max; /* populate (optional) divider table fixed values */ for (i = 0; i < ARRAY_SIZE(div->table) && - i < ARRAY_SIZE(desc->div_table) && desc->div_table[i]; i++) { - div->table[div->table_size++] = desc->div_table[i]; + i < ARRAY_SIZE(desc->div.table) && desc->div.table[i]; i++) { + div->table[div->table_size++] = desc->div.table[i]; } clk = clk_register(NULL, &div->hw); @@ -1333,7 +1335,8 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev) case K_FFC: clk = clk_register_fixed_factor(NULL, d->name, parent_name, 0, - d->mul, d->div); + d->ffc.mul, + d->ffc.div); break; case K_GATE: clk = r9a06g032_register_gate(clocks, parent_name, d); From f392f3796bba1a160b8ad706bfe1e1ec3581ad48 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Sun, 17 Sep 2023 21:01:24 +0200 Subject: [PATCH 051/396] dt-bindings: power: supply: Drop deprecated ab8500-battery Linus Walleij modified AB8500 to use the generic simple-battery and samsung,battery bindings. This is an unused leftover that can be removed. Reviewed-by: Linus Walleij Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230917190124.1012316-1-sebastian.reichel@collabora.com Signed-off-by: Sebastian Reichel --- .../supply/stericsson,ab8500-battery.txt | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 Documentation/devicetree/bindings/power/supply/stericsson,ab8500-battery.txt diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-battery.txt b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-battery.txt deleted file mode 100644 index ee125cb0e46d..000000000000 --- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-battery.txt +++ /dev/null @@ -1,34 +0,0 @@ -AB85000 PMIC contains a node, which contains shared -information about the battery connected to the PMIC. -The node has no compatible property. - -Properties of this node are: - -thermistor-on-batctrl: - A boolean value indicating thermistor interface to battery - - Note: - 'btemp' and 'batctrl' are the pins interfaced for battery temperature - measurement, 'btemp' signal is used when NTC(negative temperature - coefficient) resister is interfaced external to battery whereas - 'batctrl' pin is used when NTC resister is internal to battery. - - Example: - ab8500_battery: ab8500_battery { - thermistor-on-batctrl; - }; - indicates: NTC resister is internal to battery, 'batctrl' is used - for thermal measurement. - - The absence of property 'thermal-on-batctrl' indicates - NTC resister is external to battery and 'btemp' signal is used - for thermal measurement. - -battery-type: - This shall be the battery manufacturing technology type, - allowed types are: - "UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn" - Example: - ab8500_battery: ab8500_battery { - stericsson,battery-type = "LIPO"; - } From dab952c77e5a0bad3a391b8cbb6995f32c9a7b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:29 +0200 Subject: [PATCH 052/396] power: supply: ab8500_btemp: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-2-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_btemp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 6f83e99d2eb7..274e86d0b59e 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -811,11 +811,9 @@ static int ab8500_btemp_probe(struct platform_device *pdev) return component_add(dev, &ab8500_btemp_component_ops); } -static int ab8500_btemp_remove(struct platform_device *pdev) +static void ab8500_btemp_remove(struct platform_device *pdev) { component_del(&pdev->dev, &ab8500_btemp_component_ops); - - return 0; } static SIMPLE_DEV_PM_OPS(ab8500_btemp_pm_ops, ab8500_btemp_suspend, ab8500_btemp_resume); @@ -828,7 +826,7 @@ MODULE_DEVICE_TABLE(of, ab8500_btemp_match); struct platform_driver ab8500_btemp_driver = { .probe = ab8500_btemp_probe, - .remove = ab8500_btemp_remove, + .remove_new = ab8500_btemp_remove, .driver = { .name = "ab8500-btemp", .of_match_table = ab8500_btemp_match, From 465ec888880be0f3170b97a0e975bcb1e9b6961b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:30 +0200 Subject: [PATCH 053/396] power: supply: ab8500_chargalg: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-3-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_chargalg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index ea4ad61d4c7e..cc5d91444422 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -1824,11 +1824,9 @@ static int ab8500_chargalg_probe(struct platform_device *pdev) return component_add(dev, &ab8500_chargalg_component_ops); } -static int ab8500_chargalg_remove(struct platform_device *pdev) +static void ab8500_chargalg_remove(struct platform_device *pdev) { component_del(&pdev->dev, &ab8500_chargalg_component_ops); - - return 0; } static SIMPLE_DEV_PM_OPS(ab8500_chargalg_pm_ops, ab8500_chargalg_suspend, ab8500_chargalg_resume); @@ -1840,7 +1838,7 @@ static const struct of_device_id ab8500_chargalg_match[] = { struct platform_driver ab8500_chargalg_driver = { .probe = ab8500_chargalg_probe, - .remove = ab8500_chargalg_remove, + .remove_new = ab8500_chargalg_remove, .driver = { .name = "ab8500_chargalg", .of_match_table = ab8500_chargalg_match, From c5b08e1bfe087c42e43e64f308b16c6f79444dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:31 +0200 Subject: [PATCH 054/396] power: supply: ab8500_charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-4-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 308e68545d44..d72f32c663bc 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3679,7 +3679,7 @@ remove_ab8500_bm: return ret; } -static int ab8500_charger_remove(struct platform_device *pdev) +static void ab8500_charger_remove(struct platform_device *pdev) { struct ab8500_charger *di = platform_get_drvdata(pdev); @@ -3688,8 +3688,6 @@ static int ab8500_charger_remove(struct platform_device *pdev) usb_unregister_notifier(di->usb_phy, &di->nb); ab8500_bm_of_remove(di->usb_chg.psy, di->bm); usb_put_phy(di->usb_phy); - - return 0; } static SIMPLE_DEV_PM_OPS(ab8500_charger_pm_ops, ab8500_charger_suspend, ab8500_charger_resume); @@ -3702,7 +3700,7 @@ MODULE_DEVICE_TABLE(of, ab8500_charger_match); static struct platform_driver ab8500_charger_driver = { .probe = ab8500_charger_probe, - .remove = ab8500_charger_remove, + .remove_new = ab8500_charger_remove, .driver = { .name = "ab8500-charger", .of_match_table = ab8500_charger_match, From 59016f4c0e106ec9ba3ac039bf7e96a474648ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:32 +0200 Subject: [PATCH 055/396] power: supply: ab8500_fg: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-5-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_fg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 53560fbb6dcd..8c593fbdd45a 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -3227,7 +3227,7 @@ static int ab8500_fg_probe(struct platform_device *pdev) return component_add(dev, &ab8500_fg_component_ops); } -static int ab8500_fg_remove(struct platform_device *pdev) +static void ab8500_fg_remove(struct platform_device *pdev) { struct ab8500_fg *di = platform_get_drvdata(pdev); @@ -3236,8 +3236,6 @@ static int ab8500_fg_remove(struct platform_device *pdev) list_del(&di->node); ab8500_fg_sysfs_exit(di); ab8500_fg_sysfs_psy_remove_attrs(di); - - return 0; } static SIMPLE_DEV_PM_OPS(ab8500_fg_pm_ops, ab8500_fg_suspend, ab8500_fg_resume); @@ -3250,7 +3248,7 @@ MODULE_DEVICE_TABLE(of, ab8500_fg_match); struct platform_driver ab8500_fg_driver = { .probe = ab8500_fg_probe, - .remove = ab8500_fg_remove, + .remove_new = ab8500_fg_remove, .driver = { .name = "ab8500-fg", .of_match_table = ab8500_fg_match, From 179297b95198526fbef8f6b92f1b486502144861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:33 +0200 Subject: [PATCH 056/396] power: supply: acer_a500_battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-6-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/acer_a500_battery.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/acer_a500_battery.c b/drivers/power/supply/acer_a500_battery.c index 32a0bfcac08f..ef5c419b1b7f 100644 --- a/drivers/power/supply/acer_a500_battery.c +++ b/drivers/power/supply/acer_a500_battery.c @@ -251,13 +251,11 @@ static int a500_battery_probe(struct platform_device *pdev) return 0; } -static int a500_battery_remove(struct platform_device *pdev) +static void a500_battery_remove(struct platform_device *pdev) { struct a500_battery *bat = dev_get_drvdata(&pdev->dev); cancel_delayed_work_sync(&bat->poll_work); - - return 0; } static int __maybe_unused a500_battery_suspend(struct device *dev) @@ -287,7 +285,7 @@ static struct platform_driver a500_battery_driver = { .pm = &a500_battery_pm_ops, }, .probe = a500_battery_probe, - .remove = a500_battery_remove, + .remove_new = a500_battery_remove, }; module_platform_driver(a500_battery_driver); From 7a9a4966777b8df6e6f97f82073f4736a5274358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:34 +0200 Subject: [PATCH 057/396] power: supply: act8945a_charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-7-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/act8945a_charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/act8945a_charger.c b/drivers/power/supply/act8945a_charger.c index e9b5f4283772..51122bfbf196 100644 --- a/drivers/power/supply/act8945a_charger.c +++ b/drivers/power/supply/act8945a_charger.c @@ -638,14 +638,12 @@ static int act8945a_charger_probe(struct platform_device *pdev) return 0; } -static int act8945a_charger_remove(struct platform_device *pdev) +static void act8945a_charger_remove(struct platform_device *pdev) { struct act8945a_charger *charger = platform_get_drvdata(pdev); charger->init_done = false; cancel_work_sync(&charger->work); - - return 0; } static struct platform_driver act8945a_charger_driver = { @@ -653,7 +651,7 @@ static struct platform_driver act8945a_charger_driver = { .name = "act8945a-charger", }, .probe = act8945a_charger_probe, - .remove = act8945a_charger_remove, + .remove_new = act8945a_charger_remove, }; module_platform_driver(act8945a_charger_driver); From 403eebf95c38302cacc48c127e575461f0e798be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:35 +0200 Subject: [PATCH 058/396] power: supply: charger-manager: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-8-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/charger-manager.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 5fa6ba7f41e1..3936ff066600 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1628,7 +1628,7 @@ err_reg_extcon: return ret; } -static int charger_manager_remove(struct platform_device *pdev) +static void charger_manager_remove(struct platform_device *pdev) { struct charger_manager *cm = platform_get_drvdata(pdev); struct charger_desc *desc = cm->desc; @@ -1648,8 +1648,6 @@ static int charger_manager_remove(struct platform_device *pdev) power_supply_unregister(cm->charger_psy); try_charger_enable(cm, false); - - return 0; } static const struct platform_device_id charger_manager_id[] = { @@ -1740,7 +1738,7 @@ static struct platform_driver charger_manager_driver = { .of_match_table = charger_manager_match, }, .probe = charger_manager_probe, - .remove = charger_manager_remove, + .remove_new = charger_manager_remove, .id_table = charger_manager_id, }; From 02fecba679bbac3b16c2245e8e462b19fb36cedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:36 +0200 Subject: [PATCH 059/396] power: supply: cpcap-battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-9-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/cpcap-battery.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index 5dd76c0ac98d..30ec76cdf34b 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -1151,7 +1151,7 @@ static int cpcap_battery_probe(struct platform_device *pdev) return 0; } -static int cpcap_battery_remove(struct platform_device *pdev) +static void cpcap_battery_remove(struct platform_device *pdev) { struct cpcap_battery_ddata *ddata = platform_get_drvdata(pdev); int error; @@ -1161,8 +1161,6 @@ static int cpcap_battery_remove(struct platform_device *pdev) 0xffff, 0); if (error) dev_err(&pdev->dev, "could not disable: %i\n", error); - - return 0; } static struct platform_driver cpcap_battery_driver = { @@ -1171,7 +1169,7 @@ static struct platform_driver cpcap_battery_driver = { .of_match_table = of_match_ptr(cpcap_battery_id_table), }, .probe = cpcap_battery_probe, - .remove = cpcap_battery_remove, + .remove_new = cpcap_battery_remove, }; module_platform_driver(cpcap_battery_driver); From 1abbcff9f0c087e88ae542e0d6b0ee0689881027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:37 +0200 Subject: [PATCH 060/396] power: supply: cpcap-charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-10-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/cpcap-charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index be9764541d52..431e951cccf0 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -966,11 +966,9 @@ static void cpcap_charger_shutdown(struct platform_device *pdev) cancel_delayed_work_sync(&ddata->detect_work); } -static int cpcap_charger_remove(struct platform_device *pdev) +static void cpcap_charger_remove(struct platform_device *pdev) { cpcap_charger_shutdown(pdev); - - return 0; } static struct platform_driver cpcap_charger_driver = { @@ -980,7 +978,7 @@ static struct platform_driver cpcap_charger_driver = { .of_match_table = of_match_ptr(cpcap_charger_id_table), }, .shutdown = cpcap_charger_shutdown, - .remove = cpcap_charger_remove, + .remove_new = cpcap_charger_remove, }; module_platform_driver(cpcap_charger_driver); From b5ba26ab7a886567759b793161cdd0aae4a76910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:38 +0200 Subject: [PATCH 061/396] power: supply: da9030_battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-11-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/da9030_battery.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/da9030_battery.c b/drivers/power/supply/da9030_battery.c index 0deba48d22d3..581cf956d2d2 100644 --- a/drivers/power/supply/da9030_battery.c +++ b/drivers/power/supply/da9030_battery.c @@ -552,7 +552,7 @@ err_charger_init: return ret; } -static int da9030_battery_remove(struct platform_device *dev) +static void da9030_battery_remove(struct platform_device *dev) { struct da9030_charger *charger = platform_get_drvdata(dev); @@ -564,8 +564,6 @@ static int da9030_battery_remove(struct platform_device *dev) cancel_delayed_work_sync(&charger->work); da9030_set_charge(charger, 0); power_supply_unregister(charger->psy); - - return 0; } static struct platform_driver da903x_battery_driver = { @@ -573,7 +571,7 @@ static struct platform_driver da903x_battery_driver = { .name = "da903x-battery", }, .probe = da9030_battery_probe, - .remove = da9030_battery_remove, + .remove_new = da9030_battery_remove, }; module_platform_driver(da903x_battery_driver); From ac67d7fd4e1bad9eac25c3a1a07e4aceda6e1ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:39 +0200 Subject: [PATCH 062/396] power: supply: da9052-battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-12-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/da9052-battery.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/da9052-battery.c b/drivers/power/supply/da9052-battery.c index d87bdecc9501..6f7c58a41e91 100644 --- a/drivers/power/supply/da9052-battery.c +++ b/drivers/power/supply/da9052-battery.c @@ -637,7 +637,7 @@ err: return ret; } -static int da9052_bat_remove(struct platform_device *pdev) +static void da9052_bat_remove(struct platform_device *pdev) { int i; struct da9052_battery *bat = platform_get_drvdata(pdev); @@ -646,13 +646,11 @@ static int da9052_bat_remove(struct platform_device *pdev) da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat); power_supply_unregister(bat->psy); - - return 0; } static struct platform_driver da9052_bat_driver = { .probe = da9052_bat_probe, - .remove = da9052_bat_remove, + .remove_new = da9052_bat_remove, .driver = { .name = "da9052-bat", }, From 749e18a800569e894e82fb5f68edd447311f9675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:40 +0200 Subject: [PATCH 063/396] power: supply: da9150-charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-13-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/da9150-charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/da9150-charger.c b/drivers/power/supply/da9150-charger.c index 27f897067aa3..37db9e4ed7f3 100644 --- a/drivers/power/supply/da9150-charger.c +++ b/drivers/power/supply/da9150-charger.c @@ -635,7 +635,7 @@ ibus_chan_fail: return ret; } -static int da9150_charger_remove(struct platform_device *pdev) +static void da9150_charger_remove(struct platform_device *pdev) { struct da9150_charger *charger = platform_get_drvdata(pdev); int irq; @@ -665,8 +665,6 @@ static int da9150_charger_remove(struct platform_device *pdev) iio_channel_release(charger->vbus_chan); iio_channel_release(charger->tjunc_chan); iio_channel_release(charger->vbat_chan); - - return 0; } static struct platform_driver da9150_charger_driver = { @@ -674,7 +672,7 @@ static struct platform_driver da9150_charger_driver = { .name = "da9150-charger", }, .probe = da9150_charger_probe, - .remove = da9150_charger_remove, + .remove_new = da9150_charger_remove, }; module_platform_driver(da9150_charger_driver); From df1953bcb723538faff6ebb403ac321797f3b04f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:41 +0200 Subject: [PATCH 064/396] power: supply: goldfish_battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-14-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/goldfish_battery.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/goldfish_battery.c b/drivers/power/supply/goldfish_battery.c index a58d713d75ce..8bb645ad1e5d 100644 --- a/drivers/power/supply/goldfish_battery.c +++ b/drivers/power/supply/goldfish_battery.c @@ -249,13 +249,12 @@ static int goldfish_battery_probe(struct platform_device *pdev) return 0; } -static int goldfish_battery_remove(struct platform_device *pdev) +static void goldfish_battery_remove(struct platform_device *pdev) { struct goldfish_battery_data *data = platform_get_drvdata(pdev); power_supply_unregister(data->battery); power_supply_unregister(data->ac); - return 0; } static const struct of_device_id goldfish_battery_of_match[] = { @@ -274,7 +273,7 @@ MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match); static struct platform_driver goldfish_battery_device = { .probe = goldfish_battery_probe, - .remove = goldfish_battery_remove, + .remove_new = goldfish_battery_remove, .driver = { .name = "goldfish-battery", .of_match_table = goldfish_battery_of_match, From cbc3e1136d1f8b934cc41b4bc12f5c732d543c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:42 +0200 Subject: [PATCH 065/396] power: supply: ipaq_micro_battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-15-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/ipaq_micro_battery.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/ipaq_micro_battery.c b/drivers/power/supply/ipaq_micro_battery.c index 192d9db0fb00..66cc649f702a 100644 --- a/drivers/power/supply/ipaq_micro_battery.c +++ b/drivers/power/supply/ipaq_micro_battery.c @@ -265,7 +265,7 @@ batt_err: return ret; } -static int micro_batt_remove(struct platform_device *pdev) +static void micro_batt_remove(struct platform_device *pdev) { struct micro_battery *mb = platform_get_drvdata(pdev); @@ -274,8 +274,6 @@ static int micro_batt_remove(struct platform_device *pdev) power_supply_unregister(micro_batt_power); cancel_delayed_work_sync(&mb->update); destroy_workqueue(mb->wq); - - return 0; } static int __maybe_unused micro_batt_suspend(struct device *dev) @@ -304,7 +302,7 @@ static struct platform_driver micro_batt_device_driver = { .pm = µ_batt_dev_pm_ops, }, .probe = micro_batt_probe, - .remove = micro_batt_remove, + .remove_new = micro_batt_remove, }; module_platform_driver(micro_batt_device_driver); From cf79047ed4a33704dd465723175041c22091d24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:43 +0200 Subject: [PATCH 066/396] power: supply: isp1704_charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-16-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/isp1704_charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/isp1704_charger.c b/drivers/power/supply/isp1704_charger.c index b6efc454e4f0..860d8614c98f 100644 --- a/drivers/power/supply/isp1704_charger.c +++ b/drivers/power/supply/isp1704_charger.c @@ -477,15 +477,13 @@ fail0: return ret; } -static int isp1704_charger_remove(struct platform_device *pdev) +static void isp1704_charger_remove(struct platform_device *pdev) { struct isp1704_charger *isp = platform_get_drvdata(pdev); usb_unregister_notifier(isp->phy, &isp->nb); power_supply_unregister(isp->psy); isp1704_charger_set_power(isp, 0); - - return 0; } #ifdef CONFIG_OF @@ -503,7 +501,7 @@ static struct platform_driver isp1704_charger_driver = { .of_match_table = of_match_ptr(omap_isp1704_of_match), }, .probe = isp1704_charger_probe, - .remove = isp1704_charger_remove, + .remove_new = isp1704_charger_remove, }; module_platform_driver(isp1704_charger_driver); From 7810ba3c5110ce66652ec6bd2abb92da5d726c3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:44 +0200 Subject: [PATCH 067/396] power: supply: lp8788-charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-17-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/lp8788-charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c index 755b6a4379b8..2c81be82a41a 100644 --- a/drivers/power/supply/lp8788-charger.c +++ b/drivers/power/supply/lp8788-charger.c @@ -714,20 +714,18 @@ static int lp8788_charger_probe(struct platform_device *pdev) return 0; } -static int lp8788_charger_remove(struct platform_device *pdev) +static void lp8788_charger_remove(struct platform_device *pdev) { struct lp8788_charger *pchg = platform_get_drvdata(pdev); flush_work(&pchg->charger_work); lp8788_irq_unregister(pdev, pchg); lp8788_psy_unregister(pchg); - - return 0; } static struct platform_driver lp8788_charger_driver = { .probe = lp8788_charger_probe, - .remove = lp8788_charger_remove, + .remove_new = lp8788_charger_remove, .driver = { .name = LP8788_DEV_CHARGER, }, From 81e487b8a4af24c28a3d5c90a6035356098720bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:45 +0200 Subject: [PATCH 068/396] power: supply: max14577_charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-18-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/max14577_charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/max14577_charger.c b/drivers/power/supply/max14577_charger.c index 96f9de775043..7c23fa89ea19 100644 --- a/drivers/power/supply/max14577_charger.c +++ b/drivers/power/supply/max14577_charger.c @@ -606,14 +606,12 @@ err: return ret; } -static int max14577_charger_remove(struct platform_device *pdev) +static void max14577_charger_remove(struct platform_device *pdev) { struct max14577_charger *chg = platform_get_drvdata(pdev); device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer); power_supply_unregister(chg->charger); - - return 0; } static const struct platform_device_id max14577_charger_id[] = { @@ -638,7 +636,7 @@ static struct platform_driver max14577_charger_driver = { .of_match_table = of_max14577_charger_dt_match, }, .probe = max14577_charger_probe, - .remove = max14577_charger_remove, + .remove_new = max14577_charger_remove, .id_table = max14577_charger_id, }; module_platform_driver(max14577_charger_driver); From cd25ac3e3200626680dac92c9784cce4d59fdc6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:46 +0200 Subject: [PATCH 069/396] power: supply: max77650-charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-19-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/max77650-charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c index e8c25da40ab2..818e13c613e3 100644 --- a/drivers/power/supply/max77650-charger.c +++ b/drivers/power/supply/max77650-charger.c @@ -345,13 +345,11 @@ static int max77650_charger_probe(struct platform_device *pdev) return max77650_charger_enable(chg); } -static int max77650_charger_remove(struct platform_device *pdev) +static void max77650_charger_remove(struct platform_device *pdev) { struct max77650_charger_data *chg = platform_get_drvdata(pdev); max77650_charger_disable(chg); - - return 0; } static const struct of_device_id max77650_charger_of_match[] = { @@ -366,7 +364,7 @@ static struct platform_driver max77650_charger_driver = { .of_match_table = max77650_charger_of_match, }, .probe = max77650_charger_probe, - .remove = max77650_charger_remove, + .remove_new = max77650_charger_remove, }; module_platform_driver(max77650_charger_driver); From 1d138270d2963b68d71852c363298460ea7435c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:47 +0200 Subject: [PATCH 070/396] power: supply: max77693_charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-20-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/max77693_charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/max77693_charger.c b/drivers/power/supply/max77693_charger.c index 794c8c054450..d0157e63b8b5 100644 --- a/drivers/power/supply/max77693_charger.c +++ b/drivers/power/supply/max77693_charger.c @@ -728,7 +728,7 @@ err: return ret; } -static int max77693_charger_remove(struct platform_device *pdev) +static void max77693_charger_remove(struct platform_device *pdev) { struct max77693_charger *chg = platform_get_drvdata(pdev); @@ -737,8 +737,6 @@ static int max77693_charger_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer); power_supply_unregister(chg->charger); - - return 0; } static const struct platform_device_id max77693_charger_id[] = { @@ -752,7 +750,7 @@ static struct platform_driver max77693_charger_driver = { .name = "max77693-charger", }, .probe = max77693_charger_probe, - .remove = max77693_charger_remove, + .remove_new = max77693_charger_remove, .id_table = max77693_charger_id, }; module_platform_driver(max77693_charger_driver); From 026f25f221866ea89a33697935995db6a1c25a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:48 +0200 Subject: [PATCH 071/396] power: supply: max8925_power: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-21-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/max8925_power.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/max8925_power.c b/drivers/power/supply/max8925_power.c index 8878f9131184..4a2d6894f94e 100644 --- a/drivers/power/supply/max8925_power.c +++ b/drivers/power/supply/max8925_power.c @@ -566,7 +566,7 @@ out: return ret; } -static int max8925_power_remove(struct platform_device *pdev) +static void max8925_power_remove(struct platform_device *pdev) { struct max8925_power_info *info = platform_get_drvdata(pdev); @@ -576,12 +576,11 @@ static int max8925_power_remove(struct platform_device *pdev) power_supply_unregister(info->battery); max8925_deinit_charger(info); } - return 0; } static struct platform_driver max8925_power_driver = { .probe = max8925_power_probe, - .remove = max8925_power_remove, + .remove_new = max8925_power_remove, .driver = { .name = "max8925-power", }, From 6e3ed20e85aacaed7d3deede835a97029ea14560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:49 +0200 Subject: [PATCH 072/396] power: supply: pcf50633-charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-22-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/pcf50633-charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c index fd44cb8ac0e2..950e30917c63 100644 --- a/drivers/power/supply/pcf50633-charger.c +++ b/drivers/power/supply/pcf50633-charger.c @@ -441,7 +441,7 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) return 0; } -static int pcf50633_mbc_remove(struct platform_device *pdev) +static void pcf50633_mbc_remove(struct platform_device *pdev) { struct pcf50633_mbc *mbc = platform_get_drvdata(pdev); int i; @@ -453,8 +453,6 @@ static int pcf50633_mbc_remove(struct platform_device *pdev) power_supply_unregister(mbc->usb); power_supply_unregister(mbc->adapter); power_supply_unregister(mbc->ac); - - return 0; } static struct platform_driver pcf50633_mbc_driver = { @@ -462,7 +460,7 @@ static struct platform_driver pcf50633_mbc_driver = { .name = "pcf50633-mbc", }, .probe = pcf50633_mbc_probe, - .remove = pcf50633_mbc_remove, + .remove_new = pcf50633_mbc_remove, }; module_platform_driver(pcf50633_mbc_driver); From 325cb83bbabcafa3e54528d40c86559dde271bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:50 +0200 Subject: [PATCH 073/396] power: supply: qcom_smbb: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-23-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/qcom_smbb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c index bd50124eef9f..4e57762e27ba 100644 --- a/drivers/power/supply/qcom_smbb.c +++ b/drivers/power/supply/qcom_smbb.c @@ -1000,15 +1000,13 @@ static int smbb_charger_probe(struct platform_device *pdev) return 0; } -static int smbb_charger_remove(struct platform_device *pdev) +static void smbb_charger_remove(struct platform_device *pdev) { struct smbb_charger *chg; chg = platform_get_drvdata(pdev); regmap_update_bits(chg->regmap, chg->addr + SMBB_CHG_CTRL, CTRL_EN, 0); - - return 0; } static const struct of_device_id smbb_charger_id_table[] = { @@ -1020,7 +1018,7 @@ MODULE_DEVICE_TABLE(of, smbb_charger_id_table); static struct platform_driver smbb_charger_driver = { .probe = smbb_charger_probe, - .remove = smbb_charger_remove, + .remove_new = smbb_charger_remove, .driver = { .name = "qcom-smbb", .of_match_table = smbb_charger_id_table, From 9f0da40ae798d3f32d649d1effef246f2c30f13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:51 +0200 Subject: [PATCH 074/396] power: supply: rx51_battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-24-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/rx51_battery.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/rx51_battery.c b/drivers/power/supply/rx51_battery.c index 6e488ecf4dcb..e2bfc81f0fd9 100644 --- a/drivers/power/supply/rx51_battery.c +++ b/drivers/power/supply/rx51_battery.c @@ -246,7 +246,7 @@ error: return ret; } -static int rx51_battery_remove(struct platform_device *pdev) +static void rx51_battery_remove(struct platform_device *pdev) { struct rx51_device_info *di = platform_get_drvdata(pdev); @@ -255,8 +255,6 @@ static int rx51_battery_remove(struct platform_device *pdev) iio_channel_release(di->channel_vbat); iio_channel_release(di->channel_bsi); iio_channel_release(di->channel_temp); - - return 0; } #ifdef CONFIG_OF @@ -269,7 +267,7 @@ MODULE_DEVICE_TABLE(of, n900_battery_of_match); static struct platform_driver rx51_battery_driver = { .probe = rx51_battery_probe, - .remove = rx51_battery_remove, + .remove_new = rx51_battery_remove, .driver = { .name = "rx51-battery", .of_match_table = of_match_ptr(n900_battery_of_match), From 0569d4cfa800ba303647dbf8170d1e89bdee3ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:52 +0200 Subject: [PATCH 075/396] power: supply: sc2731_charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-25-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/sc2731_charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/sc2731_charger.c b/drivers/power/supply/sc2731_charger.c index 9ac17cf7a126..b3d8b1ca97da 100644 --- a/drivers/power/supply/sc2731_charger.c +++ b/drivers/power/supply/sc2731_charger.c @@ -511,13 +511,11 @@ static int sc2731_charger_probe(struct platform_device *pdev) return 0; } -static int sc2731_charger_remove(struct platform_device *pdev) +static void sc2731_charger_remove(struct platform_device *pdev) { struct sc2731_charger_info *info = platform_get_drvdata(pdev); usb_unregister_notifier(info->usb_phy, &info->usb_notify); - - return 0; } static const struct of_device_id sc2731_charger_of_match[] = { @@ -532,7 +530,7 @@ static struct platform_driver sc2731_charger_driver = { .of_match_table = sc2731_charger_of_match, }, .probe = sc2731_charger_probe, - .remove = sc2731_charger_remove, + .remove_new = sc2731_charger_remove, }; module_platform_driver(sc2731_charger_driver); From 75d8365c94b685dd7377b0251d2407518dc49c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:53 +0200 Subject: [PATCH 076/396] power: supply: tps65090-charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-26-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/tps65090-charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/tps65090-charger.c b/drivers/power/supply/tps65090-charger.c index f96c705e0a9f..c59197d2aa87 100644 --- a/drivers/power/supply/tps65090-charger.c +++ b/drivers/power/supply/tps65090-charger.c @@ -328,15 +328,13 @@ fail_unregister_supply: return ret; } -static int tps65090_charger_remove(struct platform_device *pdev) +static void tps65090_charger_remove(struct platform_device *pdev) { struct tps65090_charger *cdata = platform_get_drvdata(pdev); if (cdata->irq == -ENXIO) kthread_stop(cdata->poll_task); power_supply_unregister(cdata->ac); - - return 0; } static const struct of_device_id of_tps65090_charger_match[] = { @@ -351,7 +349,7 @@ static struct platform_driver tps65090_charger_driver = { .of_match_table = of_tps65090_charger_match, }, .probe = tps65090_charger_probe, - .remove = tps65090_charger_remove, + .remove_new = tps65090_charger_remove, }; module_platform_driver(tps65090_charger_driver); From 07a9398914327bb16584f24dfba02062a5967ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:54 +0200 Subject: [PATCH 077/396] power: supply: tps65217_charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-27-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/tps65217_charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c index 96341cbde4fa..b3a1ba326a3e 100644 --- a/drivers/power/supply/tps65217_charger.c +++ b/drivers/power/supply/tps65217_charger.c @@ -253,14 +253,12 @@ static int tps65217_charger_probe(struct platform_device *pdev) return 0; } -static int tps65217_charger_remove(struct platform_device *pdev) +static void tps65217_charger_remove(struct platform_device *pdev) { struct tps65217_charger *charger = platform_get_drvdata(pdev); if (charger->poll_task) kthread_stop(charger->poll_task); - - return 0; } static const struct of_device_id tps65217_charger_match_table[] = { @@ -271,7 +269,7 @@ MODULE_DEVICE_TABLE(of, tps65217_charger_match_table); static struct platform_driver tps65217_charger_driver = { .probe = tps65217_charger_probe, - .remove = tps65217_charger_remove, + .remove_new = tps65217_charger_remove, .driver = { .name = "tps65217-charger", .of_match_table = of_match_ptr(tps65217_charger_match_table), From 83ef1dbc0de4a127661a175350696e9cfa88bbb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:55 +0200 Subject: [PATCH 078/396] power: supply: twl4030_charger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-28-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_charger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/twl4030_charger.c b/drivers/power/supply/twl4030_charger.c index e78d061d8d32..7b9b0b3e164e 100644 --- a/drivers/power/supply/twl4030_charger.c +++ b/drivers/power/supply/twl4030_charger.c @@ -1108,7 +1108,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) return 0; } -static int twl4030_bci_remove(struct platform_device *pdev) +static void twl4030_bci_remove(struct platform_device *pdev) { struct twl4030_bci *bci = platform_get_drvdata(pdev); @@ -1123,8 +1123,6 @@ static int twl4030_bci_remove(struct platform_device *pdev) TWL4030_INTERRUPTS_BCIIMR1A); twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR2A); - - return 0; } static const struct of_device_id twl_bci_of_match[] __maybe_unused = { @@ -1135,7 +1133,7 @@ MODULE_DEVICE_TABLE(of, twl_bci_of_match); static struct platform_driver twl4030_bci_driver = { .probe = twl4030_bci_probe, - .remove = twl4030_bci_remove, + .remove_new = twl4030_bci_remove, .driver = { .name = "twl4030_bci", .of_match_table = of_match_ptr(twl_bci_of_match), From ac51982b04a05eb902a223b3bc83c032903b6ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:56 +0200 Subject: [PATCH 079/396] power: supply: twl4030_madc_battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-29-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/twl4030_madc_battery.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/twl4030_madc_battery.c b/drivers/power/supply/twl4030_madc_battery.c index 7fe029673b22..33106476bea2 100644 --- a/drivers/power/supply/twl4030_madc_battery.c +++ b/drivers/power/supply/twl4030_madc_battery.c @@ -244,7 +244,7 @@ err: return ret; } -static int twl4030_madc_battery_remove(struct platform_device *pdev) +static void twl4030_madc_battery_remove(struct platform_device *pdev) { struct twl4030_madc_battery *bat = platform_get_drvdata(pdev); @@ -253,8 +253,6 @@ static int twl4030_madc_battery_remove(struct platform_device *pdev) iio_channel_release(bat->channel_vbat); iio_channel_release(bat->channel_ichg); iio_channel_release(bat->channel_temp); - - return 0; } static struct platform_driver twl4030_madc_battery_driver = { @@ -262,7 +260,7 @@ static struct platform_driver twl4030_madc_battery_driver = { .name = "twl4030_madc_battery", }, .probe = twl4030_madc_battery_probe, - .remove = twl4030_madc_battery_remove, + .remove_new = twl4030_madc_battery_remove, }; module_platform_driver(twl4030_madc_battery_driver); From fc7b34ae1347f4eb36f065458e53d6065cd85928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:57 +0200 Subject: [PATCH 080/396] power: supply: wm831x_backup: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-30-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/wm831x_backup.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/wm831x_backup.c b/drivers/power/supply/wm831x_backup.c index ffb265b8526d..1a7265660ade 100644 --- a/drivers/power/supply/wm831x_backup.c +++ b/drivers/power/supply/wm831x_backup.c @@ -197,18 +197,16 @@ static int wm831x_backup_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(devdata->backup); } -static int wm831x_backup_remove(struct platform_device *pdev) +static void wm831x_backup_remove(struct platform_device *pdev) { struct wm831x_backup *devdata = platform_get_drvdata(pdev); power_supply_unregister(devdata->backup); - - return 0; } static struct platform_driver wm831x_backup_driver = { .probe = wm831x_backup_probe, - .remove = wm831x_backup_remove, + .remove_new = wm831x_backup_remove, .driver = { .name = "wm831x-backup", }, From dab68bbb5450ee17c9acf77916ac2ed659b1e2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:58 +0200 Subject: [PATCH 081/396] power: supply: wm831x_power: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-31-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/wm831x_power.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c index 82e31066c746..e49b01ee5f3e 100644 --- a/drivers/power/supply/wm831x_power.c +++ b/drivers/power/supply/wm831x_power.c @@ -694,7 +694,7 @@ err: return ret; } -static int wm831x_power_remove(struct platform_device *pdev) +static void wm831x_power_remove(struct platform_device *pdev) { struct wm831x_power *wm831x_power = platform_get_drvdata(pdev); struct wm831x *wm831x = wm831x_power->wm831x; @@ -722,12 +722,11 @@ static int wm831x_power_remove(struct platform_device *pdev) power_supply_unregister(wm831x_power->battery); power_supply_unregister(wm831x_power->wall); power_supply_unregister(wm831x_power->usb); - return 0; } static struct platform_driver wm831x_power_driver = { .probe = wm831x_power_probe, - .remove = wm831x_power_remove, + .remove_new = wm831x_power_remove, .driver = { .name = "wm831x-power", }, From 42720969f394dc074ce1c99cd0c425b7dd6017ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:36:59 +0200 Subject: [PATCH 082/396] power: supply: wm8350_power: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-32-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/wm8350_power.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index f2786761299c..f23b4f5343bc 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -579,7 +579,7 @@ battery_failed: return ret; } -static int wm8350_power_remove(struct platform_device *pdev) +static void wm8350_power_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct wm8350_power *power = &wm8350->power; @@ -589,12 +589,11 @@ static int wm8350_power_remove(struct platform_device *pdev) power_supply_unregister(power->battery); power_supply_unregister(power->ac); power_supply_unregister(power->usb); - return 0; } static struct platform_driver wm8350_power_driver = { .probe = wm8350_power_probe, - .remove = wm8350_power_remove, + .remove_new = wm8350_power_remove, .driver = { .name = "wm8350-power", }, From 6f9fb8afe649a24c7df50ce2f7095b832713e648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 15:37:00 +0200 Subject: [PATCH 083/396] power: supply: wm97xx_battery: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918133700.1254499-33-u.kleine-koenig@pengutronix.de Signed-off-by: Sebastian Reichel --- drivers/power/supply/wm97xx_battery.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c index f4b190adb335..1cc38d1437d9 100644 --- a/drivers/power/supply/wm97xx_battery.c +++ b/drivers/power/supply/wm97xx_battery.c @@ -248,14 +248,13 @@ err3: return ret; } -static int wm97xx_bat_remove(struct platform_device *dev) +static void wm97xx_bat_remove(struct platform_device *dev) { if (charge_gpiod) free_irq(gpiod_to_irq(charge_gpiod), dev); cancel_work_sync(&bat_work); power_supply_unregister(bat_psy); kfree(prop); - return 0; } static struct platform_driver wm97xx_bat_driver = { @@ -266,7 +265,7 @@ static struct platform_driver wm97xx_bat_driver = { #endif }, .probe = wm97xx_bat_probe, - .remove = wm97xx_bat_remove, + .remove_new = wm97xx_bat_remove, }; module_platform_driver(wm97xx_bat_driver); From a6c6a5fe2a08172c2e045588531f0e05a6c296cf Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 18 Sep 2023 13:58:25 -0700 Subject: [PATCH 084/396] power: supply: pm8916_lbc: observe EXTCON config setting When CONFIG_EXTCON=m and CONFIG_CHARGER_PM8916_LBC=y, there are build errors. Fix them by having CHARGER_PM8916_LBC depend on the setting of EXTCON. aarch64-linux-ld: drivers/power/supply/pm8916_lbc.o: in function `pm8916_lbc_charger_state_changed_irq': pm8916_lbc.c:(.text+0xe8): undefined reference to `extcon_set_state_sync' aarch64-linux-ld: drivers/power/supply/pm8916_lbc.o: in function `pm8916_lbc_charger_probe': pm8916_lbc.c:(.text+0x638): undefined reference to `devm_extcon_dev_allocate' aarch64-linux-ld: pm8916_lbc.c:(.text+0x650): undefined reference to `devm_extcon_dev_register' aarch64-linux-ld: pm8916_lbc.c:(.text+0x688): undefined reference to `extcon_set_state_sync' Fixes: f8d7a3d21160 ("power: supply: Add driver for pm8916 lbc") Signed-off-by: Randy Dunlap Cc: Nikita Travkin Cc: Sebastian Reichel Cc: linux-pm@vger.kernel.org Link: https://lore.kernel.org/r/20230918205825.25864-1-rdunlap@infradead.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 4bfd5a336163..ff00a7491524 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -643,6 +643,7 @@ config BATTERY_PM8916_BMS_VM config CHARGER_PM8916_LBC tristate "Qualcomm PM8916 Linear Battery Charger support" depends on MFD_SPMI_PMIC || COMPILE_TEST + depends on EXTCON || !EXTCON help Say Y here to add support for Linear Battery Charger block found in some Qualcomm PMICs such as PM8916. This hardware From 9cbc64745fc6744c0b7a35b59545f21236d81a53 Mon Sep 17 00:00:00 2001 From: Jagadeesh Kona Date: Fri, 7 Jul 2023 09:27:40 +0530 Subject: [PATCH 085/396] dt-bindings: clock: qcom: Add SM8550 camera clock controller Add device tree bindings for the camera clock controller on Qualcomm SM8550 platform. Co-developed-by: Taniya Das Signed-off-by: Taniya Das Signed-off-by: Jagadeesh Kona Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230707035744.22245-2-quic_jkona@quicinc.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm8450-camcc.yaml | 8 +- include/dt-bindings/clock/qcom,sm8550-camcc.h | 187 ++++++++++++++++++ 2 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 include/dt-bindings/clock/qcom,sm8550-camcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml index 8178c35bc348..dc3c18e4ead7 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml @@ -13,11 +13,15 @@ description: | Qualcomm camera clock control module provides the clocks, resets and power domains on SM8450. - See also:: include/dt-bindings/clock/qcom,sm8450-camcc.h + See also:: + include/dt-bindings/clock/qcom,sm8450-camcc.h + include/dt-bindings/clock/qcom,sm8550-camcc.h properties: compatible: - const: qcom,sm8450-camcc + enum: + - qcom,sm8450-camcc + - qcom,sm8550-camcc clocks: items: diff --git a/include/dt-bindings/clock/qcom,sm8550-camcc.h b/include/dt-bindings/clock/qcom,sm8550-camcc.h new file mode 100644 index 000000000000..a2a256691c2b --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm8550-camcc.h @@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8550_H +#define _DT_BINDINGS_CLK_QCOM_CAM_CC_SM8550_H + +/* CAM_CC clocks */ +#define CAM_CC_BPS_AHB_CLK 0 +#define CAM_CC_BPS_CLK 1 +#define CAM_CC_BPS_CLK_SRC 2 +#define CAM_CC_BPS_FAST_AHB_CLK 3 +#define CAM_CC_CAMNOC_AXI_CLK 4 +#define CAM_CC_CAMNOC_AXI_CLK_SRC 5 +#define CAM_CC_CAMNOC_DCD_XO_CLK 6 +#define CAM_CC_CAMNOC_XO_CLK 7 +#define CAM_CC_CCI_0_CLK 8 +#define CAM_CC_CCI_0_CLK_SRC 9 +#define CAM_CC_CCI_1_CLK 10 +#define CAM_CC_CCI_1_CLK_SRC 11 +#define CAM_CC_CCI_2_CLK 12 +#define CAM_CC_CCI_2_CLK_SRC 13 +#define CAM_CC_CORE_AHB_CLK 14 +#define CAM_CC_CPAS_AHB_CLK 15 +#define CAM_CC_CPAS_BPS_CLK 16 +#define CAM_CC_CPAS_CRE_CLK 17 +#define CAM_CC_CPAS_FAST_AHB_CLK 18 +#define CAM_CC_CPAS_IFE_0_CLK 19 +#define CAM_CC_CPAS_IFE_1_CLK 20 +#define CAM_CC_CPAS_IFE_2_CLK 21 +#define CAM_CC_CPAS_IFE_LITE_CLK 22 +#define CAM_CC_CPAS_IPE_NPS_CLK 23 +#define CAM_CC_CPAS_SBI_CLK 24 +#define CAM_CC_CPAS_SFE_0_CLK 25 +#define CAM_CC_CPAS_SFE_1_CLK 26 +#define CAM_CC_CPHY_RX_CLK_SRC 27 +#define CAM_CC_CRE_AHB_CLK 28 +#define CAM_CC_CRE_CLK 29 +#define CAM_CC_CRE_CLK_SRC 30 +#define CAM_CC_CSI0PHYTIMER_CLK 31 +#define CAM_CC_CSI0PHYTIMER_CLK_SRC 32 +#define CAM_CC_CSI1PHYTIMER_CLK 33 +#define CAM_CC_CSI1PHYTIMER_CLK_SRC 34 +#define CAM_CC_CSI2PHYTIMER_CLK 35 +#define CAM_CC_CSI2PHYTIMER_CLK_SRC 36 +#define CAM_CC_CSI3PHYTIMER_CLK 37 +#define CAM_CC_CSI3PHYTIMER_CLK_SRC 38 +#define CAM_CC_CSI4PHYTIMER_CLK 39 +#define CAM_CC_CSI4PHYTIMER_CLK_SRC 40 +#define CAM_CC_CSI5PHYTIMER_CLK 41 +#define CAM_CC_CSI5PHYTIMER_CLK_SRC 42 +#define CAM_CC_CSI6PHYTIMER_CLK 43 +#define CAM_CC_CSI6PHYTIMER_CLK_SRC 44 +#define CAM_CC_CSI7PHYTIMER_CLK 45 +#define CAM_CC_CSI7PHYTIMER_CLK_SRC 46 +#define CAM_CC_CSID_CLK 47 +#define CAM_CC_CSID_CLK_SRC 48 +#define CAM_CC_CSID_CSIPHY_RX_CLK 49 +#define CAM_CC_CSIPHY0_CLK 50 +#define CAM_CC_CSIPHY1_CLK 51 +#define CAM_CC_CSIPHY2_CLK 52 +#define CAM_CC_CSIPHY3_CLK 53 +#define CAM_CC_CSIPHY4_CLK 54 +#define CAM_CC_CSIPHY5_CLK 55 +#define CAM_CC_CSIPHY6_CLK 56 +#define CAM_CC_CSIPHY7_CLK 57 +#define CAM_CC_DRV_AHB_CLK 58 +#define CAM_CC_DRV_XO_CLK 59 +#define CAM_CC_FAST_AHB_CLK_SRC 60 +#define CAM_CC_GDSC_CLK 61 +#define CAM_CC_ICP_AHB_CLK 62 +#define CAM_CC_ICP_CLK 63 +#define CAM_CC_ICP_CLK_SRC 64 +#define CAM_CC_IFE_0_CLK 65 +#define CAM_CC_IFE_0_CLK_SRC 66 +#define CAM_CC_IFE_0_DSP_CLK 67 +#define CAM_CC_IFE_0_DSP_CLK_SRC 68 +#define CAM_CC_IFE_0_FAST_AHB_CLK 69 +#define CAM_CC_IFE_1_CLK 70 +#define CAM_CC_IFE_1_CLK_SRC 71 +#define CAM_CC_IFE_1_DSP_CLK 72 +#define CAM_CC_IFE_1_DSP_CLK_SRC 73 +#define CAM_CC_IFE_1_FAST_AHB_CLK 74 +#define CAM_CC_IFE_2_CLK 75 +#define CAM_CC_IFE_2_CLK_SRC 76 +#define CAM_CC_IFE_2_DSP_CLK 77 +#define CAM_CC_IFE_2_DSP_CLK_SRC 78 +#define CAM_CC_IFE_2_FAST_AHB_CLK 79 +#define CAM_CC_IFE_LITE_AHB_CLK 80 +#define CAM_CC_IFE_LITE_CLK 81 +#define CAM_CC_IFE_LITE_CLK_SRC 82 +#define CAM_CC_IFE_LITE_CPHY_RX_CLK 83 +#define CAM_CC_IFE_LITE_CSID_CLK 84 +#define CAM_CC_IFE_LITE_CSID_CLK_SRC 85 +#define CAM_CC_IPE_NPS_AHB_CLK 86 +#define CAM_CC_IPE_NPS_CLK 87 +#define CAM_CC_IPE_NPS_CLK_SRC 88 +#define CAM_CC_IPE_NPS_FAST_AHB_CLK 89 +#define CAM_CC_IPE_PPS_CLK 90 +#define CAM_CC_IPE_PPS_FAST_AHB_CLK 91 +#define CAM_CC_JPEG_1_CLK 92 +#define CAM_CC_JPEG_CLK 93 +#define CAM_CC_JPEG_CLK_SRC 94 +#define CAM_CC_MCLK0_CLK 95 +#define CAM_CC_MCLK0_CLK_SRC 96 +#define CAM_CC_MCLK1_CLK 97 +#define CAM_CC_MCLK1_CLK_SRC 98 +#define CAM_CC_MCLK2_CLK 99 +#define CAM_CC_MCLK2_CLK_SRC 100 +#define CAM_CC_MCLK3_CLK 101 +#define CAM_CC_MCLK3_CLK_SRC 102 +#define CAM_CC_MCLK4_CLK 103 +#define CAM_CC_MCLK4_CLK_SRC 104 +#define CAM_CC_MCLK5_CLK 105 +#define CAM_CC_MCLK5_CLK_SRC 106 +#define CAM_CC_MCLK6_CLK 107 +#define CAM_CC_MCLK6_CLK_SRC 108 +#define CAM_CC_MCLK7_CLK 109 +#define CAM_CC_MCLK7_CLK_SRC 110 +#define CAM_CC_PLL0 111 +#define CAM_CC_PLL0_OUT_EVEN 112 +#define CAM_CC_PLL0_OUT_ODD 113 +#define CAM_CC_PLL1 114 +#define CAM_CC_PLL1_OUT_EVEN 115 +#define CAM_CC_PLL2 116 +#define CAM_CC_PLL3 117 +#define CAM_CC_PLL3_OUT_EVEN 118 +#define CAM_CC_PLL4 119 +#define CAM_CC_PLL4_OUT_EVEN 120 +#define CAM_CC_PLL5 121 +#define CAM_CC_PLL5_OUT_EVEN 122 +#define CAM_CC_PLL6 123 +#define CAM_CC_PLL6_OUT_EVEN 124 +#define CAM_CC_PLL7 125 +#define CAM_CC_PLL7_OUT_EVEN 126 +#define CAM_CC_PLL8 127 +#define CAM_CC_PLL8_OUT_EVEN 128 +#define CAM_CC_PLL9 129 +#define CAM_CC_PLL9_OUT_EVEN 130 +#define CAM_CC_PLL10 131 +#define CAM_CC_PLL10_OUT_EVEN 132 +#define CAM_CC_PLL11 133 +#define CAM_CC_PLL11_OUT_EVEN 134 +#define CAM_CC_PLL12 135 +#define CAM_CC_PLL12_OUT_EVEN 136 +#define CAM_CC_QDSS_DEBUG_CLK 137 +#define CAM_CC_QDSS_DEBUG_CLK_SRC 138 +#define CAM_CC_QDSS_DEBUG_XO_CLK 139 +#define CAM_CC_SBI_CLK 140 +#define CAM_CC_SBI_FAST_AHB_CLK 141 +#define CAM_CC_SFE_0_CLK 142 +#define CAM_CC_SFE_0_CLK_SRC 143 +#define CAM_CC_SFE_0_FAST_AHB_CLK 144 +#define CAM_CC_SFE_1_CLK 145 +#define CAM_CC_SFE_1_CLK_SRC 146 +#define CAM_CC_SFE_1_FAST_AHB_CLK 147 +#define CAM_CC_SLEEP_CLK 148 +#define CAM_CC_SLEEP_CLK_SRC 149 +#define CAM_CC_SLOW_AHB_CLK_SRC 150 +#define CAM_CC_XO_CLK_SRC 151 + +/* CAM_CC power domains */ +#define CAM_CC_BPS_GDSC 0 +#define CAM_CC_IFE_0_GDSC 1 +#define CAM_CC_IFE_1_GDSC 2 +#define CAM_CC_IFE_2_GDSC 3 +#define CAM_CC_IPE_0_GDSC 4 +#define CAM_CC_SBI_GDSC 5 +#define CAM_CC_SFE_0_GDSC 6 +#define CAM_CC_SFE_1_GDSC 7 +#define CAM_CC_TITAN_TOP_GDSC 8 + +/* CAM_CC resets */ +#define CAM_CC_BPS_BCR 0 +#define CAM_CC_DRV_BCR 1 +#define CAM_CC_ICP_BCR 2 +#define CAM_CC_IFE_0_BCR 3 +#define CAM_CC_IFE_1_BCR 4 +#define CAM_CC_IFE_2_BCR 5 +#define CAM_CC_IPE_0_BCR 6 +#define CAM_CC_QDSS_DEBUG_BCR 7 +#define CAM_CC_SBI_BCR 8 +#define CAM_CC_SFE_0_BCR 9 +#define CAM_CC_SFE_1_BCR 10 + +#endif From 3132a9a11e57f257ab79ae79ce101a38952fa50a Mon Sep 17 00:00:00 2001 From: Jagadeesh Kona Date: Fri, 7 Jul 2023 09:27:41 +0530 Subject: [PATCH 086/396] clk: qcom: clk-alpha-pll: Add support for lucid ole pll configure Lucid ole pll has as extra RINGOSC_CAL_L field in L register in addition to the fields that are part of lucid evo pll, hence add support for lucid ole pll configure function to configure the ole plls. Signed-off-by: Jagadeesh Kona Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230707035744.22245-3-quic_jkona@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-alpha-pll.c | 29 +++++++++++++++++++++++++++++ drivers/clk/qcom/clk-alpha-pll.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index e4ef645f65d1..4edbf77f3360 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -271,6 +271,7 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); #define LUCID_EVO_ENABLE_VOTE_RUN BIT(25) #define LUCID_EVO_PLL_L_VAL_MASK GENMASK(15, 0) #define LUCID_EVO_PLL_CAL_L_VAL_SHIFT 16 +#define LUCID_OLE_PLL_RINGOSC_CAL_L_VAL_SHIFT 24 /* ZONDA PLL specific */ #define ZONDA_PLL_OUT_MASK 0xf @@ -2119,6 +2120,34 @@ void clk_lucid_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regma } EXPORT_SYMBOL_GPL(clk_lucid_evo_pll_configure); +void clk_lucid_ole_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + u32 lval = config->l; + + lval |= TRION_PLL_CAL_VAL << LUCID_EVO_PLL_CAL_L_VAL_SHIFT; + lval |= TRION_PLL_CAL_VAL << LUCID_OLE_PLL_RINGOSC_CAL_L_VAL_SHIFT; + clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), lval); + clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), config->config_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), config->config_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), config->user_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), config->user_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), config->test_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), config->test_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U2(pll), config->test_ctl_hi2_val); + + /* Disable PLL output */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); + + /* Set operation mode to STANDBY and de-assert the reset */ + regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); + regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); +} +EXPORT_SYMBOL_GPL(clk_lucid_ole_pll_configure); + static int alpha_pll_lucid_evo_enable(struct clk_hw *hw) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index e4bd863027ab..3b24a660daac 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -199,6 +199,8 @@ void clk_zonda_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); void clk_lucid_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); +void clk_lucid_ole_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config); void clk_rivian_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); void clk_stromer_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, From ccc4e6a061a21d75b96d82fc4b084a8d96df6eb4 Mon Sep 17 00:00:00 2001 From: Jagadeesh Kona Date: Fri, 7 Jul 2023 09:27:42 +0530 Subject: [PATCH 087/396] clk: qcom: camcc-sm8550: Add camera clock controller driver for SM8550 Add support for the camera clock controller for camera clients to be able to request for camcc clocks on SM8550 platform. Co-developed-by: Taniya Das Signed-off-by: Taniya Das Signed-off-by: Jagadeesh Kona Reviewed-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230707035744.22245-4-quic_jkona@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 7 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/camcc-sm8550.c | 3383 +++++++++++++++++++++++++++++++ 3 files changed, 3391 insertions(+) create mode 100644 drivers/clk/qcom/camcc-sm8550.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 865db5202e4c..4b72e98eaa70 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -764,6 +764,13 @@ config SM_CAMCC_8450 Support for the camera clock controller on SM8450 devices. Say Y if you want to support camera devices and camera functionality. +config SM_CAMCC_8550 + tristate "SM8550 Camera Clock Controller" + select SM_GCC_8550 + help + Support for the camera clock controller on SM8550 devices. + Say Y if you want to support camera devices and camera functionality. + config SM_DISPCC_6115 tristate "SM6115 Display Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 4790c8cca426..a301b08dba05 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_SDX_GCC_75) += gcc-sdx75.o obj-$(CONFIG_SM_CAMCC_6350) += camcc-sm6350.o obj-$(CONFIG_SM_CAMCC_8250) += camcc-sm8250.o obj-$(CONFIG_SM_CAMCC_8450) += camcc-sm8450.o +obj-$(CONFIG_SM_CAMCC_8550) += camcc-sm8550.o obj-$(CONFIG_SM_DISPCC_6115) += dispcc-sm6115.o obj-$(CONFIG_SM_DISPCC_6125) += dispcc-sm6125.o obj-$(CONFIG_SM_DISPCC_6350) += dispcc-sm6350.o diff --git a/drivers/clk/qcom/camcc-sm8550.c b/drivers/clk/qcom/camcc-sm8550.c new file mode 100644 index 000000000000..075bea32087c --- /dev/null +++ b/drivers/clk/qcom/camcc-sm8550.c @@ -0,0 +1,3383 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_IFACE, + DT_BI_TCXO, +}; + +enum { + P_BI_TCXO, + P_CAM_CC_PLL0_OUT_EVEN, + P_CAM_CC_PLL0_OUT_MAIN, + P_CAM_CC_PLL0_OUT_ODD, + P_CAM_CC_PLL1_OUT_EVEN, + P_CAM_CC_PLL2_OUT_EVEN, + P_CAM_CC_PLL2_OUT_MAIN, + P_CAM_CC_PLL3_OUT_EVEN, + P_CAM_CC_PLL4_OUT_EVEN, + P_CAM_CC_PLL5_OUT_EVEN, + P_CAM_CC_PLL6_OUT_EVEN, + P_CAM_CC_PLL7_OUT_EVEN, + P_CAM_CC_PLL8_OUT_EVEN, + P_CAM_CC_PLL9_OUT_EVEN, + P_CAM_CC_PLL9_OUT_ODD, + P_CAM_CC_PLL10_OUT_EVEN, + P_CAM_CC_PLL11_OUT_EVEN, + P_CAM_CC_PLL12_OUT_EVEN, +}; + +static const struct pll_vco lucid_ole_vco[] = { + { 249600000, 2300000000, 0 }, +}; + +static const struct pll_vco rivian_ole_vco[] = { + { 777000000, 1285000000, 0 }, +}; + +static const struct alpha_pll_config cam_cc_pll0_config = { + .l = 0x3e, + .alpha = 0x8000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00008400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll0 = { + .offset = 0x0, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll0_out_odd[] = { + { 0x2, 3 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = { + .offset = 0x0, + .post_div_shift = 14, + .post_div_table = post_div_table_cam_cc_pll0_out_odd, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_odd), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll0_out_odd", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll1_config = { + .l = 0x2f, + .alpha = 0x6555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll1_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = { + .offset = 0x1000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll1_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll1_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll1_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll1.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll2_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x10000030, + .config_ctl_hi_val = 0x80890263, + .config_ctl_hi1_val = 0x00000217, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00100000, +}; + +static struct clk_alpha_pll cam_cc_pll2 = { + .offset = 0x2000, + .vco_table = rivian_ole_vco, + .num_vco = ARRAY_SIZE(rivian_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_RIVIAN_EVO], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll2", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_rivian_evo_ops, + }, + }, +}; + +static const struct alpha_pll_config cam_cc_pll3_config = { + .l = 0x30, + .alpha = 0x8aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll3 = { + .offset = 0x3000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll3", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll3_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = { + .offset = 0x3000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll3_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll3_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll3_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll3.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll4_config = { + .l = 0x30, + .alpha = 0x8aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll4 = { + .offset = 0x4000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll4_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll4_out_even = { + .offset = 0x4000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll4_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll4_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll4_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll4.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll5_config = { + .l = 0x30, + .alpha = 0x8aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll5 = { + .offset = 0x5000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll5", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll5_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll5_out_even = { + .offset = 0x5000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll5_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll5_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll5_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll5.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll6_config = { + .l = 0x30, + .alpha = 0x8aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll6 = { + .offset = 0x6000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll6", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll6_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll6_out_even = { + .offset = 0x6000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll6_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll6_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll6_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll6.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll7_config = { + .l = 0x30, + .alpha = 0x8aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll7 = { + .offset = 0x7000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll7_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll7_out_even = { + .offset = 0x7000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll7_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll7_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll7_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll7.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll8_config = { + .l = 0x14, + .alpha = 0xd555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll8 = { + .offset = 0x8000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll8", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll8_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll8_out_even = { + .offset = 0x8000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll8_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll8_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll8_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll8.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll9_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll9 = { + .offset = 0x9000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll9_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll9_out_even = { + .offset = 0x9000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll9_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll9_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll9_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll9.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll10_config = { + .l = 0x30, + .alpha = 0x8aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll10 = { + .offset = 0xa000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll10", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll10_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll10_out_even = { + .offset = 0xa000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll10_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll10_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll10_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll10.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll11_config = { + .l = 0x30, + .alpha = 0x8aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll11 = { + .offset = 0xb000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll11", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll11_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll11_out_even = { + .offset = 0xb000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll11_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll11_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll11_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll11.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct alpha_pll_config cam_cc_pll12_config = { + .l = 0x30, + .alpha = 0x8aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000400, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll cam_cc_pll12 = { + .offset = 0xc000, + .vco_table = lucid_ole_vco, + .num_vco = ARRAY_SIZE(lucid_ole_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll12", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_cam_cc_pll12_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll12_out_even = { + .offset = 0xc000, + .post_div_shift = 10, + .post_div_table = post_div_table_cam_cc_pll12_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll12_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_pll12_out_even", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_pll12.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static const struct parent_map cam_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL0_OUT_MAIN, 1 }, + { P_CAM_CC_PLL0_OUT_EVEN, 2 }, + { P_CAM_CC_PLL0_OUT_ODD, 3 }, + { P_CAM_CC_PLL9_OUT_ODD, 4 }, + { P_CAM_CC_PLL9_OUT_EVEN, 5 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll0.clkr.hw }, + { .hw = &cam_cc_pll0_out_even.clkr.hw }, + { .hw = &cam_cc_pll0_out_odd.clkr.hw }, + { .hw = &cam_cc_pll9.clkr.hw }, + { .hw = &cam_cc_pll9_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL2_OUT_EVEN, 3 }, + { P_CAM_CC_PLL2_OUT_MAIN, 5 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll2.clkr.hw }, + { .hw = &cam_cc_pll2.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL8_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll8_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL3_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll3_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL10_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll10_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL4_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll4_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL11_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll11_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL5_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll5_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL12_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll12_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_9[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL1_OUT_EVEN, 4 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_9[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll1_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_10[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL6_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_10[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll6_out_even.clkr.hw }, +}; + +static const struct parent_map cam_cc_parent_map_11[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL7_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_11[] = { + { .index = DT_BI_TCXO }, + { .hw = &cam_cc_pll7_out_even.clkr.hw }, +}; + +static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_CAM_CC_PLL8_OUT_EVEN, 1, 0, 0), + F(400000000, P_CAM_CC_PLL8_OUT_EVEN, 1, 0, 0), + F(480000000, P_CAM_CC_PLL8_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL8_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_bps_clk_src = { + .cmd_rcgr = 0x10278, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_2, + .freq_tbl = ftbl_cam_cc_bps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_bps_clk_src", + .parent_data = cam_cc_parent_data_2, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_camnoc_axi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_camnoc_axi_clk_src = { + .cmd_rcgr = 0x13de0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_camnoc_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_camnoc_axi_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cci_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cci_0_clk_src = { + .cmd_rcgr = 0x13900, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_0_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_cci_1_clk_src = { + .cmd_rcgr = 0x13a30, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_1_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_cci_2_clk_src = { + .cmd_rcgr = 0x13b60, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_2_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(480000000, P_CAM_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cphy_rx_clk_src = { + .cmd_rcgr = 0x11290, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cphy_rx_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cre_clk_src[] = { + F(200000000, P_CAM_CC_PLL0_OUT_ODD, 2, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAM_CC_PLL9_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cre_clk_src = { + .cmd_rcgr = 0x1353c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cre_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cre_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = { + .cmd_rcgr = 0x15980, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi0phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = { + .cmd_rcgr = 0x15ab8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi1phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = { + .cmd_rcgr = 0x15bec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi2phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = { + .cmd_rcgr = 0x15d20, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi3phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_csi4phytimer_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_csi4phytimer_clk_src = { + .cmd_rcgr = 0x15e54, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi4phytimer_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi4phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi5phytimer_clk_src = { + .cmd_rcgr = 0x15f88, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi5phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi6phytimer_clk_src = { + .cmd_rcgr = 0x160bc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi6phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_csi7phytimer_clk_src = { + .cmd_rcgr = 0x161f0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi7phytimer_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_csid_clk_src[] = { + F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(480000000, P_CAM_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_csid_clk_src = { + .cmd_rcgr = 0x13ca8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csid_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csid_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_fast_ahb_clk_src = { + .cmd_rcgr = 0x10018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_fast_ahb_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAM_CC_PLL9_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_icp_clk_src = { + .cmd_rcgr = 0x137c4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_icp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_icp_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(466000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(594000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_clk_src = { + .cmd_rcgr = 0x11018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_3, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_0_clk_src", + .parent_data = cam_cc_parent_data_3, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_dsp_clk_src[] = { + F(466000000, P_CAM_CC_PLL10_OUT_EVEN, 1, 0, 0), + F(594000000, P_CAM_CC_PLL10_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL10_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL10_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_dsp_clk_src = { + .cmd_rcgr = 0x11154, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_4, + .freq_tbl = ftbl_cam_cc_ife_0_dsp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_0_dsp_clk_src", + .parent_data = cam_cc_parent_data_4, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(466000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0), + F(594000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL4_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_1_clk_src = { + .cmd_rcgr = 0x12018, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_5, + .freq_tbl = ftbl_cam_cc_ife_1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_1_clk_src", + .parent_data = cam_cc_parent_data_5, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_1_dsp_clk_src[] = { + F(466000000, P_CAM_CC_PLL11_OUT_EVEN, 1, 0, 0), + F(594000000, P_CAM_CC_PLL11_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL11_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL11_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_1_dsp_clk_src = { + .cmd_rcgr = 0x12154, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_6, + .freq_tbl = ftbl_cam_cc_ife_1_dsp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_1_dsp_clk_src", + .parent_data = cam_cc_parent_data_6, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_2_clk_src[] = { + F(466000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0), + F(594000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL5_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_2_clk_src = { + .cmd_rcgr = 0x122a8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_7, + .freq_tbl = ftbl_cam_cc_ife_2_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_2_clk_src", + .parent_data = cam_cc_parent_data_7, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_2_dsp_clk_src[] = { + F(466000000, P_CAM_CC_PLL12_OUT_EVEN, 1, 0, 0), + F(594000000, P_CAM_CC_PLL12_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL12_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL12_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_2_dsp_clk_src = { + .cmd_rcgr = 0x123e4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_8, + .freq_tbl = ftbl_cam_cc_ife_2_dsp_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_2_dsp_clk_src", + .parent_data = cam_cc_parent_data_8, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_clk_src = { + .cmd_rcgr = 0x13000, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csid_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = { + .cmd_rcgr = 0x1313c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csid_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_csid_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ipe_nps_clk_src[] = { + F(455000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0), + F(575000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0), + F(825000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ipe_nps_clk_src = { + .cmd_rcgr = 0x103cc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_9, + .freq_tbl = ftbl_cam_cc_ipe_nps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_nps_clk_src", + .parent_data = cam_cc_parent_data_9, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_jpeg_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_ODD, 2, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAM_CC_PLL9_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_jpeg_clk_src = { + .cmd_rcgr = 0x13674, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_jpeg_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_jpeg_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_CAM_CC_PLL2_OUT_MAIN, 10, 1, 4), + F(68571429, P_CAM_CC_PLL2_OUT_MAIN, 14, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_mclk0_clk_src = { + .cmd_rcgr = 0x15000, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk0_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk1_clk_src = { + .cmd_rcgr = 0x15130, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk1_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk2_clk_src = { + .cmd_rcgr = 0x15260, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk2_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk3_clk_src = { + .cmd_rcgr = 0x15390, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk3_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk4_clk_src = { + .cmd_rcgr = 0x154c0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk4_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk5_clk_src = { + .cmd_rcgr = 0x155f0, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk5_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk6_clk_src = { + .cmd_rcgr = 0x15720, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk6_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 cam_cc_mclk7_clk_src = { + .cmd_rcgr = 0x15850, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk7_clk_src", + .parent_data = cam_cc_parent_data_1, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_sfe_0_clk_src[] = { + F(466000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0), + F(594000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_sfe_0_clk_src = { + .cmd_rcgr = 0x13294, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_10, + .freq_tbl = ftbl_cam_cc_sfe_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_0_clk_src", + .parent_data = cam_cc_parent_data_10, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_10), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_sfe_1_clk_src[] = { + F(466000000, P_CAM_CC_PLL7_OUT_EVEN, 1, 0, 0), + F(594000000, P_CAM_CC_PLL7_OUT_EVEN, 1, 0, 0), + F(675000000, P_CAM_CC_PLL7_OUT_EVEN, 1, 0, 0), + F(785000000, P_CAM_CC_PLL7_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_sfe_1_clk_src = { + .cmd_rcgr = 0x133f4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_11, + .freq_tbl = ftbl_cam_cc_sfe_1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_1_clk_src", + .parent_data = cam_cc_parent_data_11, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_slow_ahb_clk_src = { + .cmd_rcgr = 0x10148, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_slow_ahb_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_branch cam_cc_bps_ahb_clk = { + .halt_reg = 0x10274, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10274, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_bps_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_clk = { + .halt_reg = 0x103a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x103a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_bps_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_bps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_fast_ahb_clk = { + .halt_reg = 0x10144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10144, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_bps_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_camnoc_axi_clk = { + .halt_reg = 0x13f0c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13f0c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_camnoc_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_0_clk = { + .halt_reg = 0x13a2c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13a2c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cci_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_1_clk = { + .halt_reg = 0x13b5c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13b5c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cci_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_2_clk = { + .halt_reg = 0x13c8c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13c8c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cci_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cci_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_core_ahb_clk = { + .halt_reg = 0x1406c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1406c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_core_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ahb_clk = { + .halt_reg = 0x13c90, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13c90, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_bps_clk = { + .halt_reg = 0x103b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x103b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_bps_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_bps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_cre_clk = { + .halt_reg = 0x1366c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1366c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_cre_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cre_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_fast_ahb_clk = { + .halt_reg = 0x13c9c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13c9c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ife_0_clk = { + .halt_reg = 0x11150, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11150, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ife_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ife_1_clk = { + .halt_reg = 0x12150, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12150, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ife_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ife_2_clk = { + .halt_reg = 0x123e0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x123e0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ife_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ife_lite_clk = { + .halt_reg = 0x13138, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13138, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ife_lite_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_lite_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ipe_nps_clk = { + .halt_reg = 0x10504, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10504, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_ipe_nps_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ipe_nps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_sbi_clk = { + .halt_reg = 0x1054c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1054c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_sbi_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_sfe_0_clk = { + .halt_reg = 0x133cc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x133cc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_sfe_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_sfe_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_sfe_1_clk = { + .halt_reg = 0x1352c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1352c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cpas_sfe_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_sfe_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cre_ahb_clk = { + .halt_reg = 0x13670, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13670, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cre_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cre_clk = { + .halt_reg = 0x13668, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13668, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_cre_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cre_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi0phytimer_clk = { + .halt_reg = 0x15aac, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15aac, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi0phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi0phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi1phytimer_clk = { + .halt_reg = 0x15be4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15be4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi1phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi1phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi2phytimer_clk = { + .halt_reg = 0x15d18, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15d18, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi2phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi2phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi3phytimer_clk = { + .halt_reg = 0x15e4c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15e4c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi3phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi3phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi4phytimer_clk = { + .halt_reg = 0x15f80, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15f80, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi4phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi4phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi5phytimer_clk = { + .halt_reg = 0x160b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x160b4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi5phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi5phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi6phytimer_clk = { + .halt_reg = 0x161e8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x161e8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi6phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi6phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi7phytimer_clk = { + .halt_reg = 0x1631c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1631c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csi7phytimer_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csi7phytimer_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csid_clk = { + .halt_reg = 0x13dd4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13dd4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csid_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csid_csiphy_rx_clk = { + .halt_reg = 0x15ab4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15ab4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csid_csiphy_rx_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy0_clk = { + .halt_reg = 0x15ab0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15ab0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy1_clk = { + .halt_reg = 0x15be8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15be8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy2_clk = { + .halt_reg = 0x15d1c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15d1c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy2_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy3_clk = { + .halt_reg = 0x15e50, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15e50, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy3_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy4_clk = { + .halt_reg = 0x15f84, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15f84, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy4_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy5_clk = { + .halt_reg = 0x160b8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x160b8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy5_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy6_clk = { + .halt_reg = 0x161ec, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x161ec, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy6_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy7_clk = { + .halt_reg = 0x16320, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16320, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_csiphy7_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_drv_ahb_clk = { + .halt_reg = 0x142d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x142d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_drv_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_ahb_clk = { + .halt_reg = 0x138fc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x138fc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_icp_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_clk = { + .halt_reg = 0x138f0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x138f0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_icp_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_icp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_clk = { + .halt_reg = 0x11144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11144, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_dsp_clk = { + .halt_reg = 0x11280, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11280, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_0_dsp_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_dsp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_fast_ahb_clk = { + .halt_reg = 0x1128c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1128c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_0_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_clk = { + .halt_reg = 0x12144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12144, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_dsp_clk = { + .halt_reg = 0x12280, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12280, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_1_dsp_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_1_dsp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_fast_ahb_clk = { + .halt_reg = 0x1228c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1228c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_1_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_2_clk = { + .halt_reg = 0x123d4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x123d4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_2_dsp_clk = { + .halt_reg = 0x12510, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12510, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_2_dsp_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_2_dsp_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_2_fast_ahb_clk = { + .halt_reg = 0x1251c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1251c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_2_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_ahb_clk = { + .halt_reg = 0x13278, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13278, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_clk = { + .halt_reg = 0x1312c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1312c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_lite_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = { + .halt_reg = 0x13274, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13274, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_cphy_rx_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_cphy_rx_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_csid_clk = { + .halt_reg = 0x13268, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13268, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ife_lite_csid_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_lite_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_nps_ahb_clk = { + .halt_reg = 0x1051c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1051c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_nps_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_slow_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_nps_clk = { + .halt_reg = 0x104f8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x104f8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_nps_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ipe_nps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_nps_fast_ahb_clk = { + .halt_reg = 0x10520, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10520, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_nps_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_pps_clk = { + .halt_reg = 0x10508, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10508, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_pps_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ipe_nps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_pps_fast_ahb_clk = { + .halt_reg = 0x10524, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10524, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_ipe_pps_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_jpeg_1_clk = { + .halt_reg = 0x137ac, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x137ac, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_jpeg_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_jpeg_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_jpeg_clk = { + .halt_reg = 0x137a0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x137a0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_jpeg_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_jpeg_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk0_clk = { + .halt_reg = 0x1512c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1512c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk1_clk = { + .halt_reg = 0x1525c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1525c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk2_clk = { + .halt_reg = 0x1538c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1538c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk2_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk3_clk = { + .halt_reg = 0x154bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x154bc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk3_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk4_clk = { + .halt_reg = 0x155ec, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x155ec, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk4_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk5_clk = { + .halt_reg = 0x1571c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1571c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk5_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk6_clk = { + .halt_reg = 0x1584c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1584c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk6_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk7_clk = { + .halt_reg = 0x1597c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1597c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_mclk7_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_mclk7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sbi_clk = { + .halt_reg = 0x10540, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10540, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sbi_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_ife_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sbi_fast_ahb_clk = { + .halt_reg = 0x10550, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10550, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sbi_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sfe_0_clk = { + .halt_reg = 0x133c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x133c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_sfe_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sfe_0_fast_ahb_clk = { + .halt_reg = 0x133d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x133d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_0_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sfe_1_clk = { + .halt_reg = 0x13520, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13520, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_sfe_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sfe_1_fast_ahb_clk = { + .halt_reg = 0x13538, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13538, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sfe_1_fast_ahb_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_fast_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc cam_cc_bps_gdsc = { + .gdscr = 0x10004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_bps_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc cam_cc_ife_0_gdsc = { + .gdscr = 0x11004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_ife_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc cam_cc_ife_1_gdsc = { + .gdscr = 0x12004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_ife_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc cam_cc_ife_2_gdsc = { + .gdscr = 0x12294, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_ife_2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc cam_cc_ipe_0_gdsc = { + .gdscr = 0x103b8, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_ipe_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc cam_cc_sbi_gdsc = { + .gdscr = 0x1052c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_sbi_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc cam_cc_sfe_0_gdsc = { + .gdscr = 0x13280, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_sfe_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc cam_cc_sfe_1_gdsc = { + .gdscr = 0x133e0, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_sfe_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc cam_cc_titan_top_gdsc = { + .gdscr = 0x14058, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "cam_cc_titan_top_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *cam_cc_sm8550_clocks[] = { + [CAM_CC_BPS_AHB_CLK] = &cam_cc_bps_ahb_clk.clkr, + [CAM_CC_BPS_CLK] = &cam_cc_bps_clk.clkr, + [CAM_CC_BPS_CLK_SRC] = &cam_cc_bps_clk_src.clkr, + [CAM_CC_BPS_FAST_AHB_CLK] = &cam_cc_bps_fast_ahb_clk.clkr, + [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr, + [CAM_CC_CAMNOC_AXI_CLK_SRC] = &cam_cc_camnoc_axi_clk_src.clkr, + [CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr, + [CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr, + [CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr, + [CAM_CC_CCI_1_CLK_SRC] = &cam_cc_cci_1_clk_src.clkr, + [CAM_CC_CCI_2_CLK] = &cam_cc_cci_2_clk.clkr, + [CAM_CC_CCI_2_CLK_SRC] = &cam_cc_cci_2_clk_src.clkr, + [CAM_CC_CORE_AHB_CLK] = &cam_cc_core_ahb_clk.clkr, + [CAM_CC_CPAS_AHB_CLK] = &cam_cc_cpas_ahb_clk.clkr, + [CAM_CC_CPAS_BPS_CLK] = &cam_cc_cpas_bps_clk.clkr, + [CAM_CC_CPAS_CRE_CLK] = &cam_cc_cpas_cre_clk.clkr, + [CAM_CC_CPAS_FAST_AHB_CLK] = &cam_cc_cpas_fast_ahb_clk.clkr, + [CAM_CC_CPAS_IFE_0_CLK] = &cam_cc_cpas_ife_0_clk.clkr, + [CAM_CC_CPAS_IFE_1_CLK] = &cam_cc_cpas_ife_1_clk.clkr, + [CAM_CC_CPAS_IFE_2_CLK] = &cam_cc_cpas_ife_2_clk.clkr, + [CAM_CC_CPAS_IFE_LITE_CLK] = &cam_cc_cpas_ife_lite_clk.clkr, + [CAM_CC_CPAS_IPE_NPS_CLK] = &cam_cc_cpas_ipe_nps_clk.clkr, + [CAM_CC_CPAS_SBI_CLK] = &cam_cc_cpas_sbi_clk.clkr, + [CAM_CC_CPAS_SFE_0_CLK] = &cam_cc_cpas_sfe_0_clk.clkr, + [CAM_CC_CPAS_SFE_1_CLK] = &cam_cc_cpas_sfe_1_clk.clkr, + [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr, + [CAM_CC_CRE_AHB_CLK] = &cam_cc_cre_ahb_clk.clkr, + [CAM_CC_CRE_CLK] = &cam_cc_cre_clk.clkr, + [CAM_CC_CRE_CLK_SRC] = &cam_cc_cre_clk_src.clkr, + [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr, + [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr, + [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr, + [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr, + [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr, + [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr, + [CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr, + [CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr, + [CAM_CC_CSI4PHYTIMER_CLK] = &cam_cc_csi4phytimer_clk.clkr, + [CAM_CC_CSI4PHYTIMER_CLK_SRC] = &cam_cc_csi4phytimer_clk_src.clkr, + [CAM_CC_CSI5PHYTIMER_CLK] = &cam_cc_csi5phytimer_clk.clkr, + [CAM_CC_CSI5PHYTIMER_CLK_SRC] = &cam_cc_csi5phytimer_clk_src.clkr, + [CAM_CC_CSI6PHYTIMER_CLK] = &cam_cc_csi6phytimer_clk.clkr, + [CAM_CC_CSI6PHYTIMER_CLK_SRC] = &cam_cc_csi6phytimer_clk_src.clkr, + [CAM_CC_CSI7PHYTIMER_CLK] = &cam_cc_csi7phytimer_clk.clkr, + [CAM_CC_CSI7PHYTIMER_CLK_SRC] = &cam_cc_csi7phytimer_clk_src.clkr, + [CAM_CC_CSID_CLK] = &cam_cc_csid_clk.clkr, + [CAM_CC_CSID_CLK_SRC] = &cam_cc_csid_clk_src.clkr, + [CAM_CC_CSID_CSIPHY_RX_CLK] = &cam_cc_csid_csiphy_rx_clk.clkr, + [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr, + [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr, + [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr, + [CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr, + [CAM_CC_CSIPHY4_CLK] = &cam_cc_csiphy4_clk.clkr, + [CAM_CC_CSIPHY5_CLK] = &cam_cc_csiphy5_clk.clkr, + [CAM_CC_CSIPHY6_CLK] = &cam_cc_csiphy6_clk.clkr, + [CAM_CC_CSIPHY7_CLK] = &cam_cc_csiphy7_clk.clkr, + [CAM_CC_DRV_AHB_CLK] = &cam_cc_drv_ahb_clk.clkr, + [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr, + [CAM_CC_ICP_AHB_CLK] = &cam_cc_icp_ahb_clk.clkr, + [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr, + [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr, + [CAM_CC_IFE_0_CLK] = &cam_cc_ife_0_clk.clkr, + [CAM_CC_IFE_0_CLK_SRC] = &cam_cc_ife_0_clk_src.clkr, + [CAM_CC_IFE_0_DSP_CLK] = &cam_cc_ife_0_dsp_clk.clkr, + [CAM_CC_IFE_0_DSP_CLK_SRC] = &cam_cc_ife_0_dsp_clk_src.clkr, + [CAM_CC_IFE_0_FAST_AHB_CLK] = &cam_cc_ife_0_fast_ahb_clk.clkr, + [CAM_CC_IFE_1_CLK] = &cam_cc_ife_1_clk.clkr, + [CAM_CC_IFE_1_CLK_SRC] = &cam_cc_ife_1_clk_src.clkr, + [CAM_CC_IFE_1_DSP_CLK] = &cam_cc_ife_1_dsp_clk.clkr, + [CAM_CC_IFE_1_DSP_CLK_SRC] = &cam_cc_ife_1_dsp_clk_src.clkr, + [CAM_CC_IFE_1_FAST_AHB_CLK] = &cam_cc_ife_1_fast_ahb_clk.clkr, + [CAM_CC_IFE_2_CLK] = &cam_cc_ife_2_clk.clkr, + [CAM_CC_IFE_2_CLK_SRC] = &cam_cc_ife_2_clk_src.clkr, + [CAM_CC_IFE_2_DSP_CLK] = &cam_cc_ife_2_dsp_clk.clkr, + [CAM_CC_IFE_2_DSP_CLK_SRC] = &cam_cc_ife_2_dsp_clk_src.clkr, + [CAM_CC_IFE_2_FAST_AHB_CLK] = &cam_cc_ife_2_fast_ahb_clk.clkr, + [CAM_CC_IFE_LITE_AHB_CLK] = &cam_cc_ife_lite_ahb_clk.clkr, + [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr, + [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr, + [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr, + [CAM_CC_IPE_NPS_AHB_CLK] = &cam_cc_ipe_nps_ahb_clk.clkr, + [CAM_CC_IPE_NPS_CLK] = &cam_cc_ipe_nps_clk.clkr, + [CAM_CC_IPE_NPS_CLK_SRC] = &cam_cc_ipe_nps_clk_src.clkr, + [CAM_CC_IPE_NPS_FAST_AHB_CLK] = &cam_cc_ipe_nps_fast_ahb_clk.clkr, + [CAM_CC_IPE_PPS_CLK] = &cam_cc_ipe_pps_clk.clkr, + [CAM_CC_IPE_PPS_FAST_AHB_CLK] = &cam_cc_ipe_pps_fast_ahb_clk.clkr, + [CAM_CC_JPEG_1_CLK] = &cam_cc_jpeg_1_clk.clkr, + [CAM_CC_JPEG_CLK] = &cam_cc_jpeg_clk.clkr, + [CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr, + [CAM_CC_MCLK0_CLK] = &cam_cc_mclk0_clk.clkr, + [CAM_CC_MCLK0_CLK_SRC] = &cam_cc_mclk0_clk_src.clkr, + [CAM_CC_MCLK1_CLK] = &cam_cc_mclk1_clk.clkr, + [CAM_CC_MCLK1_CLK_SRC] = &cam_cc_mclk1_clk_src.clkr, + [CAM_CC_MCLK2_CLK] = &cam_cc_mclk2_clk.clkr, + [CAM_CC_MCLK2_CLK_SRC] = &cam_cc_mclk2_clk_src.clkr, + [CAM_CC_MCLK3_CLK] = &cam_cc_mclk3_clk.clkr, + [CAM_CC_MCLK3_CLK_SRC] = &cam_cc_mclk3_clk_src.clkr, + [CAM_CC_MCLK4_CLK] = &cam_cc_mclk4_clk.clkr, + [CAM_CC_MCLK4_CLK_SRC] = &cam_cc_mclk4_clk_src.clkr, + [CAM_CC_MCLK5_CLK] = &cam_cc_mclk5_clk.clkr, + [CAM_CC_MCLK5_CLK_SRC] = &cam_cc_mclk5_clk_src.clkr, + [CAM_CC_MCLK6_CLK] = &cam_cc_mclk6_clk.clkr, + [CAM_CC_MCLK6_CLK_SRC] = &cam_cc_mclk6_clk_src.clkr, + [CAM_CC_MCLK7_CLK] = &cam_cc_mclk7_clk.clkr, + [CAM_CC_MCLK7_CLK_SRC] = &cam_cc_mclk7_clk_src.clkr, + [CAM_CC_PLL0] = &cam_cc_pll0.clkr, + [CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.clkr, + [CAM_CC_PLL0_OUT_ODD] = &cam_cc_pll0_out_odd.clkr, + [CAM_CC_PLL1] = &cam_cc_pll1.clkr, + [CAM_CC_PLL1_OUT_EVEN] = &cam_cc_pll1_out_even.clkr, + [CAM_CC_PLL2] = &cam_cc_pll2.clkr, + [CAM_CC_PLL3] = &cam_cc_pll3.clkr, + [CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr, + [CAM_CC_PLL4] = &cam_cc_pll4.clkr, + [CAM_CC_PLL4_OUT_EVEN] = &cam_cc_pll4_out_even.clkr, + [CAM_CC_PLL5] = &cam_cc_pll5.clkr, + [CAM_CC_PLL5_OUT_EVEN] = &cam_cc_pll5_out_even.clkr, + [CAM_CC_PLL6] = &cam_cc_pll6.clkr, + [CAM_CC_PLL6_OUT_EVEN] = &cam_cc_pll6_out_even.clkr, + [CAM_CC_PLL7] = &cam_cc_pll7.clkr, + [CAM_CC_PLL7_OUT_EVEN] = &cam_cc_pll7_out_even.clkr, + [CAM_CC_PLL8] = &cam_cc_pll8.clkr, + [CAM_CC_PLL8_OUT_EVEN] = &cam_cc_pll8_out_even.clkr, + [CAM_CC_PLL9] = &cam_cc_pll9.clkr, + [CAM_CC_PLL9_OUT_EVEN] = &cam_cc_pll9_out_even.clkr, + [CAM_CC_PLL10] = &cam_cc_pll10.clkr, + [CAM_CC_PLL10_OUT_EVEN] = &cam_cc_pll10_out_even.clkr, + [CAM_CC_PLL11] = &cam_cc_pll11.clkr, + [CAM_CC_PLL11_OUT_EVEN] = &cam_cc_pll11_out_even.clkr, + [CAM_CC_PLL12] = &cam_cc_pll12.clkr, + [CAM_CC_PLL12_OUT_EVEN] = &cam_cc_pll12_out_even.clkr, + [CAM_CC_SBI_CLK] = &cam_cc_sbi_clk.clkr, + [CAM_CC_SBI_FAST_AHB_CLK] = &cam_cc_sbi_fast_ahb_clk.clkr, + [CAM_CC_SFE_0_CLK] = &cam_cc_sfe_0_clk.clkr, + [CAM_CC_SFE_0_CLK_SRC] = &cam_cc_sfe_0_clk_src.clkr, + [CAM_CC_SFE_0_FAST_AHB_CLK] = &cam_cc_sfe_0_fast_ahb_clk.clkr, + [CAM_CC_SFE_1_CLK] = &cam_cc_sfe_1_clk.clkr, + [CAM_CC_SFE_1_CLK_SRC] = &cam_cc_sfe_1_clk_src.clkr, + [CAM_CC_SFE_1_FAST_AHB_CLK] = &cam_cc_sfe_1_fast_ahb_clk.clkr, + [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr, +}; + +static struct gdsc *cam_cc_sm8550_gdscs[] = { + [CAM_CC_BPS_GDSC] = &cam_cc_bps_gdsc, + [CAM_CC_IFE_0_GDSC] = &cam_cc_ife_0_gdsc, + [CAM_CC_IFE_1_GDSC] = &cam_cc_ife_1_gdsc, + [CAM_CC_IFE_2_GDSC] = &cam_cc_ife_2_gdsc, + [CAM_CC_IPE_0_GDSC] = &cam_cc_ipe_0_gdsc, + [CAM_CC_SBI_GDSC] = &cam_cc_sbi_gdsc, + [CAM_CC_SFE_0_GDSC] = &cam_cc_sfe_0_gdsc, + [CAM_CC_SFE_1_GDSC] = &cam_cc_sfe_1_gdsc, + [CAM_CC_TITAN_TOP_GDSC] = &cam_cc_titan_top_gdsc, +}; + +static const struct qcom_reset_map cam_cc_sm8550_resets[] = { + [CAM_CC_BPS_BCR] = { 0x10000 }, + [CAM_CC_DRV_BCR] = { 0x142d0 }, + [CAM_CC_ICP_BCR] = { 0x137c0 }, + [CAM_CC_IFE_0_BCR] = { 0x11000 }, + [CAM_CC_IFE_1_BCR] = { 0x12000 }, + [CAM_CC_IFE_2_BCR] = { 0x12290 }, + [CAM_CC_IPE_0_BCR] = { 0x103b4 }, + [CAM_CC_QDSS_DEBUG_BCR] = { 0x13f20 }, + [CAM_CC_SBI_BCR] = { 0x10528 }, + [CAM_CC_SFE_0_BCR] = { 0x1327c }, + [CAM_CC_SFE_1_BCR] = { 0x133dc }, +}; + +static const struct regmap_config cam_cc_sm8550_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x16320, + .fast_io = true, +}; + +static struct qcom_cc_desc cam_cc_sm8550_desc = { + .config = &cam_cc_sm8550_regmap_config, + .clks = cam_cc_sm8550_clocks, + .num_clks = ARRAY_SIZE(cam_cc_sm8550_clocks), + .resets = cam_cc_sm8550_resets, + .num_resets = ARRAY_SIZE(cam_cc_sm8550_resets), + .gdscs = cam_cc_sm8550_gdscs, + .num_gdscs = ARRAY_SIZE(cam_cc_sm8550_gdscs), +}; + +static const struct of_device_id cam_cc_sm8550_match_table[] = { + { .compatible = "qcom,sm8550-camcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, cam_cc_sm8550_match_table); + +static int cam_cc_sm8550_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) + return ret; + + regmap = qcom_cc_map(pdev, &cam_cc_sm8550_desc); + if (IS_ERR(regmap)) { + pm_runtime_put(&pdev->dev); + return PTR_ERR(regmap); + } + + clk_lucid_ole_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config); + clk_lucid_ole_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config); + clk_rivian_evo_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config); + clk_lucid_ole_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config); + clk_lucid_ole_pll_configure(&cam_cc_pll4, regmap, &cam_cc_pll4_config); + clk_lucid_ole_pll_configure(&cam_cc_pll5, regmap, &cam_cc_pll5_config); + clk_lucid_ole_pll_configure(&cam_cc_pll6, regmap, &cam_cc_pll6_config); + clk_lucid_ole_pll_configure(&cam_cc_pll7, regmap, &cam_cc_pll7_config); + clk_lucid_ole_pll_configure(&cam_cc_pll8, regmap, &cam_cc_pll8_config); + clk_lucid_ole_pll_configure(&cam_cc_pll9, regmap, &cam_cc_pll9_config); + clk_lucid_ole_pll_configure(&cam_cc_pll10, regmap, &cam_cc_pll10_config); + clk_lucid_ole_pll_configure(&cam_cc_pll11, regmap, &cam_cc_pll11_config); + clk_lucid_ole_pll_configure(&cam_cc_pll12, regmap, &cam_cc_pll12_config); + + /* + * Keep clocks always enabled: + * cam_cc_gdsc_clk + * cam_cc_sleep_clk + */ + regmap_update_bits(regmap, 0x1419c, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x142cc, BIT(0), BIT(0)); + + ret = qcom_cc_really_probe(pdev, &cam_cc_sm8550_desc, regmap); + + pm_runtime_put(&pdev->dev); + + return ret; +} + +static struct platform_driver cam_cc_sm8550_driver = { + .probe = cam_cc_sm8550_probe, + .driver = { + .name = "cam_cc-sm8550", + .of_match_table = cam_cc_sm8550_match_table, + }, +}; + +module_platform_driver(cam_cc_sm8550_driver); + +MODULE_DESCRIPTION("QTI CAMCC SM8550 Driver"); +MODULE_LICENSE("GPL"); From a209cf9cc8ae436c227e28c3e6a36fc1894b2dea Mon Sep 17 00:00:00 2001 From: Jagadeesh Kona Date: Fri, 7 Jul 2023 09:27:43 +0530 Subject: [PATCH 088/396] clk: qcom: camcc-sm8550: Add support for qdss, sleep and xo clocks Add support for camera qdss, sleep and xo clocks. Co-developed-by: Taniya Das Signed-off-by: Taniya Das Signed-off-by: Jagadeesh Kona Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230707035744.22245-5-quic_jkona@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/camcc-sm8550.c | 181 ++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/drivers/clk/qcom/camcc-sm8550.c b/drivers/clk/qcom/camcc-sm8550.c index 075bea32087c..2133e768b891 100644 --- a/drivers/clk/qcom/camcc-sm8550.c +++ b/drivers/clk/qcom/camcc-sm8550.c @@ -22,10 +22,13 @@ enum { DT_IFACE, DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, }; enum { P_BI_TCXO, + P_BI_TCXO_AO, P_CAM_CC_PLL0_OUT_EVEN, P_CAM_CC_PLL0_OUT_MAIN, P_CAM_CC_PLL0_OUT_ODD, @@ -43,6 +46,7 @@ enum { P_CAM_CC_PLL10_OUT_EVEN, P_CAM_CC_PLL11_OUT_EVEN, P_CAM_CC_PLL12_OUT_EVEN, + P_SLEEP_CLK, }; static const struct pll_vco lucid_ole_vco[] = { @@ -881,6 +885,22 @@ static const struct clk_parent_data cam_cc_parent_data_11[] = { { .hw = &cam_cc_pll7_out_even.clkr.hw }, }; +static const struct parent_map cam_cc_parent_map_12[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_12[] = { + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map cam_cc_parent_map_13_ao[] = { + { P_BI_TCXO_AO, 0 }, +}; + +static const struct clk_parent_data cam_cc_parent_data_13_ao[] = { + { .index = DT_BI_TCXO_AO }, +}; + static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = { F(19200000, P_BI_TCXO, 1, 0, 0), F(200000000, P_CAM_CC_PLL8_OUT_EVEN, 1, 0, 0), @@ -1565,6 +1585,29 @@ static struct clk_rcg2 cam_cc_mclk7_clk_src = { }, }; +static const struct freq_tbl ftbl_cam_cc_qdss_debug_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(75000000, P_CAM_CC_PLL0_OUT_EVEN, 8, 0, 0), + F(150000000, P_CAM_CC_PLL0_OUT_EVEN, 4, 0, 0), + F(300000000, P_CAM_CC_PLL0_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_qdss_debug_clk_src = { + .cmd_rcgr = 0x13f24, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_qdss_debug_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_qdss_debug_clk_src", + .parent_data = cam_cc_parent_data_0, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + static const struct freq_tbl ftbl_cam_cc_sfe_0_clk_src[] = { F(466000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0), F(594000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0), @@ -1611,6 +1654,26 @@ static struct clk_rcg2 cam_cc_sfe_1_clk_src = { }, }; +static const struct freq_tbl ftbl_cam_cc_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_sleep_clk_src = { + .cmd_rcgr = 0x141a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_12, + .freq_tbl = ftbl_cam_cc_sleep_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_sleep_clk_src", + .parent_data = cam_cc_parent_data_12, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_12), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = { F(19200000, P_BI_TCXO, 1, 0, 0), F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0), @@ -1632,6 +1695,26 @@ static struct clk_rcg2 cam_cc_slow_ahb_clk_src = { }, }; +static const struct freq_tbl ftbl_cam_cc_xo_clk_src[] = { + F(19200000, P_BI_TCXO_AO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_xo_clk_src = { + .cmd_rcgr = 0x14070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_13_ao, + .freq_tbl = ftbl_cam_cc_xo_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "cam_cc_xo_clk_src", + .parent_data = cam_cc_parent_data_13_ao, + .num_parents = ARRAY_SIZE(cam_cc_parent_data_13_ao), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + static struct clk_branch cam_cc_bps_ahb_clk = { .halt_reg = 0x10274, .halt_check = BRANCH_HALT, @@ -1704,6 +1787,42 @@ static struct clk_branch cam_cc_camnoc_axi_clk = { }, }; +static struct clk_branch cam_cc_camnoc_dcd_xo_clk = { + .halt_reg = 0x13f18, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13f18, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_camnoc_dcd_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_camnoc_xo_clk = { + .halt_reg = 0x13f1c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13f1c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_camnoc_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch cam_cc_cci_0_clk = { .halt_reg = 0x13a2c, .halt_check = BRANCH_HALT, @@ -2370,6 +2489,24 @@ static struct clk_branch cam_cc_drv_ahb_clk = { }, }; +static struct clk_branch cam_cc_drv_xo_clk = { + .halt_reg = 0x142d4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x142d4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_drv_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch cam_cc_icp_ahb_clk = { .halt_reg = 0x138fc, .halt_check = BRANCH_HALT, @@ -2910,6 +3047,42 @@ static struct clk_branch cam_cc_mclk7_clk = { }, }; +static struct clk_branch cam_cc_qdss_debug_clk = { + .halt_reg = 0x14050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_qdss_debug_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_qdss_debug_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_qdss_debug_xo_clk = { + .halt_reg = 0x14054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "cam_cc_qdss_debug_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &cam_cc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch cam_cc_sbi_clk = { .halt_reg = 0x10540, .halt_check = BRANCH_HALT, @@ -3133,6 +3306,8 @@ static struct clk_regmap *cam_cc_sm8550_clocks[] = { [CAM_CC_BPS_FAST_AHB_CLK] = &cam_cc_bps_fast_ahb_clk.clkr, [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr, [CAM_CC_CAMNOC_AXI_CLK_SRC] = &cam_cc_camnoc_axi_clk_src.clkr, + [CAM_CC_CAMNOC_DCD_XO_CLK] = &cam_cc_camnoc_dcd_xo_clk.clkr, + [CAM_CC_CAMNOC_XO_CLK] = &cam_cc_camnoc_xo_clk.clkr, [CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr, [CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr, [CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr, @@ -3184,6 +3359,7 @@ static struct clk_regmap *cam_cc_sm8550_clocks[] = { [CAM_CC_CSIPHY6_CLK] = &cam_cc_csiphy6_clk.clkr, [CAM_CC_CSIPHY7_CLK] = &cam_cc_csiphy7_clk.clkr, [CAM_CC_DRV_AHB_CLK] = &cam_cc_drv_ahb_clk.clkr, + [CAM_CC_DRV_XO_CLK] = &cam_cc_drv_xo_clk.clkr, [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr, [CAM_CC_ICP_AHB_CLK] = &cam_cc_icp_ahb_clk.clkr, [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr, @@ -3260,6 +3436,9 @@ static struct clk_regmap *cam_cc_sm8550_clocks[] = { [CAM_CC_PLL11_OUT_EVEN] = &cam_cc_pll11_out_even.clkr, [CAM_CC_PLL12] = &cam_cc_pll12.clkr, [CAM_CC_PLL12_OUT_EVEN] = &cam_cc_pll12_out_even.clkr, + [CAM_CC_QDSS_DEBUG_CLK] = &cam_cc_qdss_debug_clk.clkr, + [CAM_CC_QDSS_DEBUG_CLK_SRC] = &cam_cc_qdss_debug_clk_src.clkr, + [CAM_CC_QDSS_DEBUG_XO_CLK] = &cam_cc_qdss_debug_xo_clk.clkr, [CAM_CC_SBI_CLK] = &cam_cc_sbi_clk.clkr, [CAM_CC_SBI_FAST_AHB_CLK] = &cam_cc_sbi_fast_ahb_clk.clkr, [CAM_CC_SFE_0_CLK] = &cam_cc_sfe_0_clk.clkr, @@ -3268,7 +3447,9 @@ static struct clk_regmap *cam_cc_sm8550_clocks[] = { [CAM_CC_SFE_1_CLK] = &cam_cc_sfe_1_clk.clkr, [CAM_CC_SFE_1_CLK_SRC] = &cam_cc_sfe_1_clk_src.clkr, [CAM_CC_SFE_1_FAST_AHB_CLK] = &cam_cc_sfe_1_fast_ahb_clk.clkr, + [CAM_CC_SLEEP_CLK_SRC] = &cam_cc_sleep_clk_src.clkr, [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr, + [CAM_CC_XO_CLK_SRC] = &cam_cc_xo_clk_src.clkr, }; static struct gdsc *cam_cc_sm8550_gdscs[] = { From ccd8ab030643040600a663edde56b434b6f4fb6c Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 31 Aug 2023 14:58:53 +0530 Subject: [PATCH 089/396] clk: qcom: ipq5332: Drop set rate parent from gpll0 dependent clocks IPQ5332's GPLL0's nominal/turbo frequency is 800MHz. This must not be scaled based on the requirement of dependent clocks. Hence remove the CLK_SET_RATE_PARENT flag. Fixes: 3d89d52970fd ("clk: qcom: add Global Clock controller (GCC) driver for IPQ5332 SoC") Signed-off-by: Varadarajan Narayanan Reviewed-by: Kathiravan T Link: https://lore.kernel.org/r/1693474133-10467-1-git-send-email-quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-ipq5332.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clk/qcom/gcc-ipq5332.c b/drivers/clk/qcom/gcc-ipq5332.c index b02026f8549b..b836159fbdef 100644 --- a/drivers/clk/qcom/gcc-ipq5332.c +++ b/drivers/clk/qcom/gcc-ipq5332.c @@ -71,7 +71,6 @@ static struct clk_fixed_factor gpll0_div2 = { &gpll0_main.clkr.hw }, .num_parents = 1, .ops = &clk_fixed_factor_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -85,7 +84,6 @@ static struct clk_alpha_pll_postdiv gpll0 = { &gpll0_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; From 4afda5f6bcdf673ef2556fcfa458daf3a5a648d8 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Thu, 31 Aug 2023 11:39:14 +0200 Subject: [PATCH 090/396] clk: qcom: gcc-msm8996: Remove RPM bus clocks The GCC driver contains clocks that are owned (meaning configured and scaled) by the RPM core. Remove them from Linux to stop interjecting the RPM's logic. Fixes: b1e010c0730a ("clk: qcom: Add MSM8996 Global Clock Control (GCC) driver") Signed-off-by: Konrad Dybcio Reviewed-by: Dmitry Baryshkov Tested-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230830-topic-rpmbusclocks8996gcc-v1-1-9e99bedcdc3b@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-msm8996.c | 237 +-------------------------------- 1 file changed, 5 insertions(+), 232 deletions(-) diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 14dcc3f03668..e7b03a17514a 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -244,71 +244,6 @@ static const struct clk_parent_data gcc_xo_gpll0_gpll4_gpll0_early_div[] = { { .hw = &gpll0_early_div.hw } }; -static const struct freq_tbl ftbl_system_noc_clk_src[] = { - F(19200000, P_XO, 1, 0, 0), - F(50000000, P_GPLL0_EARLY_DIV, 6, 0, 0), - F(100000000, P_GPLL0, 6, 0, 0), - F(150000000, P_GPLL0, 4, 0, 0), - F(200000000, P_GPLL0, 3, 0, 0), - F(240000000, P_GPLL0, 2.5, 0, 0), - { } -}; - -static struct clk_rcg2 system_noc_clk_src = { - .cmd_rcgr = 0x0401c, - .hid_width = 5, - .parent_map = gcc_xo_gpll0_gpll0_early_div_map, - .freq_tbl = ftbl_system_noc_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "system_noc_clk_src", - .parent_data = gcc_xo_gpll0_gpll0_early_div, - .num_parents = ARRAY_SIZE(gcc_xo_gpll0_gpll0_early_div), - .ops = &clk_rcg2_ops, - }, -}; - -static const struct freq_tbl ftbl_config_noc_clk_src[] = { - F(19200000, P_XO, 1, 0, 0), - F(37500000, P_GPLL0, 16, 0, 0), - F(75000000, P_GPLL0, 8, 0, 0), - { } -}; - -static struct clk_rcg2 config_noc_clk_src = { - .cmd_rcgr = 0x0500c, - .hid_width = 5, - .parent_map = gcc_xo_gpll0_map, - .freq_tbl = ftbl_config_noc_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "config_noc_clk_src", - .parent_data = gcc_xo_gpll0, - .num_parents = ARRAY_SIZE(gcc_xo_gpll0), - .ops = &clk_rcg2_ops, - }, -}; - -static const struct freq_tbl ftbl_periph_noc_clk_src[] = { - F(19200000, P_XO, 1, 0, 0), - F(37500000, P_GPLL0, 16, 0, 0), - F(50000000, P_GPLL0, 12, 0, 0), - F(75000000, P_GPLL0, 8, 0, 0), - F(100000000, P_GPLL0, 6, 0, 0), - { } -}; - -static struct clk_rcg2 periph_noc_clk_src = { - .cmd_rcgr = 0x06014, - .hid_width = 5, - .parent_map = gcc_xo_gpll0_map, - .freq_tbl = ftbl_periph_noc_clk_src, - .clkr.hw.init = &(struct clk_init_data){ - .name = "periph_noc_clk_src", - .parent_data = gcc_xo_gpll0, - .num_parents = ARRAY_SIZE(gcc_xo_gpll0), - .ops = &clk_rcg2_ops, - }, -}; - static const struct freq_tbl ftbl_usb30_master_clk_src[] = { F(19200000, P_XO, 1, 0, 0), F(120000000, P_GPLL0, 5, 0, 0), @@ -1297,11 +1232,7 @@ static struct clk_branch gcc_mmss_noc_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_mmss_noc_cfg_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + .flags = CLK_IGNORE_UNUSED, .ops = &clk_branch2_ops, }, }, @@ -1464,11 +1395,6 @@ static struct clk_branch gcc_usb_phy_cfg_ahb2phy_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_usb_phy_cfg_ahb2phy_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1498,11 +1424,6 @@ static struct clk_branch gcc_sdcc1_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_sdcc1_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1549,11 +1470,6 @@ static struct clk_branch gcc_sdcc2_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_sdcc2_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1583,11 +1499,6 @@ static struct clk_branch gcc_sdcc3_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_sdcc3_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1617,11 +1528,6 @@ static struct clk_branch gcc_sdcc4_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_sdcc4_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1635,11 +1541,6 @@ static struct clk_branch gcc_blsp1_ahb_clk = { .enable_mask = BIT(17), .hw.init = &(struct clk_init_data){ .name = "gcc_blsp1_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -1977,11 +1878,6 @@ static struct clk_branch gcc_blsp2_ahb_clk = { .enable_mask = BIT(15), .hw.init = &(struct clk_init_data){ .name = "gcc_blsp2_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2318,11 +2214,6 @@ static struct clk_branch gcc_pdm_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pdm_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2353,11 +2244,6 @@ static struct clk_branch gcc_prng_ahb_clk = { .enable_mask = BIT(13), .hw.init = &(struct clk_init_data){ .name = "gcc_prng_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2370,11 +2256,6 @@ static struct clk_branch gcc_tsif_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_tsif_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2422,11 +2303,6 @@ static struct clk_branch gcc_boot_rom_ahb_clk = { .enable_mask = BIT(10), .hw.init = &(struct clk_init_data){ .name = "gcc_boot_rom_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2520,11 +2396,6 @@ static struct clk_branch gcc_pcie_0_slv_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_0_slv_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2537,11 +2408,6 @@ static struct clk_branch gcc_pcie_0_mstr_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_0_mstr_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2554,11 +2420,6 @@ static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_0_cfg_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2606,11 +2467,6 @@ static struct clk_branch gcc_pcie_1_slv_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_1_slv_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2623,11 +2479,6 @@ static struct clk_branch gcc_pcie_1_mstr_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_1_mstr_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2640,11 +2491,6 @@ static struct clk_branch gcc_pcie_1_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_1_cfg_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2692,11 +2538,6 @@ static struct clk_branch gcc_pcie_2_slv_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_2_slv_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2709,11 +2550,6 @@ static struct clk_branch gcc_pcie_2_mstr_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_2_mstr_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2726,11 +2562,6 @@ static struct clk_branch gcc_pcie_2_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_2_cfg_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2778,11 +2609,6 @@ static struct clk_branch gcc_pcie_phy_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_pcie_phy_cfg_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -2829,11 +2655,6 @@ static struct clk_branch gcc_ufs_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_ufs_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -3060,11 +2881,7 @@ static struct clk_branch gcc_aggre0_snoc_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_aggre0_snoc_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3077,11 +2894,7 @@ static struct clk_branch gcc_aggre0_cnoc_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_aggre0_cnoc_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3094,11 +2907,7 @@ static struct clk_branch gcc_smmu_aggre0_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_smmu_aggre0_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3111,11 +2920,7 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_smmu_aggre0_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .flags = CLK_IS_CRITICAL, .ops = &clk_branch2_ops, }, }, @@ -3162,10 +2967,6 @@ static struct clk_branch gcc_dcc_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_dcc_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, .ops = &clk_branch2_ops, }, }, @@ -3178,10 +2979,6 @@ static struct clk_branch gcc_aggre0_noc_mpu_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_aggre0_noc_mpu_cfg_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, .ops = &clk_branch2_ops, }, }, @@ -3194,11 +2991,6 @@ static struct clk_branch gcc_qspi_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_qspi_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &periph_noc_clk_src.clkr.hw, - }, - .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, @@ -3347,10 +3139,6 @@ static struct clk_branch gcc_mss_cfg_ahb_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_mss_cfg_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &config_noc_clk_src.clkr.hw, - }, - .num_parents = 1, .ops = &clk_branch2_ops, }, }, @@ -3363,10 +3151,6 @@ static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_mss_mnoc_bimc_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, .ops = &clk_branch2_ops, }, }, @@ -3379,10 +3163,6 @@ static struct clk_branch gcc_mss_snoc_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_mss_snoc_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, .ops = &clk_branch2_ops, }, }, @@ -3395,10 +3175,6 @@ static struct clk_branch gcc_mss_q6_bimc_axi_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_mss_q6_bimc_axi_clk", - .parent_hws = (const struct clk_hw*[]){ - &system_noc_clk_src.clkr.hw, - }, - .num_parents = 1, .ops = &clk_branch2_ops, }, }, @@ -3495,9 +3271,6 @@ static struct clk_regmap *gcc_msm8996_clocks[] = { [GPLL0] = &gpll0.clkr, [GPLL4_EARLY] = &gpll4_early.clkr, [GPLL4] = &gpll4.clkr, - [SYSTEM_NOC_CLK_SRC] = &system_noc_clk_src.clkr, - [CONFIG_NOC_CLK_SRC] = &config_noc_clk_src.clkr, - [PERIPH_NOC_CLK_SRC] = &periph_noc_clk_src.clkr, [USB30_MASTER_CLK_SRC] = &usb30_master_clk_src.clkr, [USB30_MOCK_UTMI_CLK_SRC] = &usb30_mock_utmi_clk_src.clkr, [USB3_PHY_AUX_CLK_SRC] = &usb3_phy_aux_clk_src.clkr, From f7b7d30158cff246667273bd2a62fc93ee0725d2 Mon Sep 17 00:00:00 2001 From: Devi Priya Date: Fri, 1 Sep 2023 13:06:40 +0530 Subject: [PATCH 091/396] clk: qcom: clk-rcg2: Fix clock rate overflow for high parent frequencies If the parent clock rate is greater than unsigned long max/2 then integer overflow happens when calculating the clock rate on 32-bit systems. As RCG2 uses half integer dividers, the clock rate is first being multiplied by 2 which will overflow the unsigned long max value. Hence, replace the common pattern of doing 64-bit multiplication and then a do_div() call with simpler mult_frac call. Fixes: bcd61c0f535a ("clk: qcom: Add support for root clock generators (RCGs)") Signed-off-by: Devi Priya Reviewed-by: Marijn Suijten Link: https://lore.kernel.org/r/20230901073640.4973-1-quic_devipriy@quicinc.com [bjorn: Also drop unnecessary {} around single statements] Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-rcg2.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index e22baf3a7112..5183c74b074f 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -158,17 +158,11 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) static unsigned long calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div) { - if (hid_div) { - rate *= 2; - rate /= hid_div + 1; - } + if (hid_div) + rate = mult_frac(rate, 2, hid_div + 1); - if (mode) { - u64 tmp = rate; - tmp *= m; - do_div(tmp, n); - rate = tmp; - } + if (mode) + rate = mult_frac(rate, m, n); return rate; } From 9906c4140897bbdbff7bb71c6ae67903cb9954ce Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 9 Aug 2023 21:20:27 +0200 Subject: [PATCH 092/396] clk: qcom: mmcc-msm8998: Don't check halt bit on some branch clks Some branch clocks are governed externally and we're only supposed to send a request concerning their shutdown, not actually ensure it happens. Use the BRANCH_HALT_SKIP define to skip checking the halt bit. Fixes: d14b15b5931c ("clk: qcom: Add MSM8998 Multimedia Clock Controller (MMCC) driver") Reviewed-by: Jeffrey Hugo Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230531-topic-8998_mmssclk-v3-4-ba1b1fd9ee75@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/mmcc-msm8998.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/qcom/mmcc-msm8998.c b/drivers/clk/qcom/mmcc-msm8998.c index a023c4374be9..b0b51adb73a5 100644 --- a/drivers/clk/qcom/mmcc-msm8998.c +++ b/drivers/clk/qcom/mmcc-msm8998.c @@ -2439,6 +2439,7 @@ static struct clk_branch fd_ahb_clk = { static struct clk_branch mnoc_ahb_clk = { .halt_reg = 0x5024, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x5024, .enable_mask = BIT(0), @@ -2454,6 +2455,7 @@ static struct clk_branch mnoc_ahb_clk = { static struct clk_branch bimc_smmu_ahb_clk = { .halt_reg = 0xe004, + .halt_check = BRANCH_HALT_SKIP, .hwcg_reg = 0xe004, .hwcg_bit = 1, .clkr = { @@ -2471,6 +2473,7 @@ static struct clk_branch bimc_smmu_ahb_clk = { static struct clk_branch bimc_smmu_axi_clk = { .halt_reg = 0xe008, + .halt_check = BRANCH_HALT_SKIP, .hwcg_reg = 0xe008, .hwcg_bit = 1, .clkr = { From 1fc62c8347397faf4e18249e88ecd4470c0a5357 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 9 Aug 2023 21:20:28 +0200 Subject: [PATCH 093/396] clk: qcom: mmcc-msm8998: Fix the SMMU GDSC The SMMU GDSC doesn't have to be ALWAYS-ON and shouldn't feature the HW_CTRL flag (it's separate from hw_ctrl_addr). In addition to that, it should feature a cxc entry for bimc_smmu_axi_clk and be marked as votable. Fix all of these issues. Fixes: d14b15b5931c ("clk: qcom: Add MSM8998 Multimedia Clock Controller (MMCC) driver") Signed-off-by: Konrad Dybcio Reviewed-by: Jeffrey Hugo Link: https://lore.kernel.org/r/20230531-topic-8998_mmssclk-v3-5-ba1b1fd9ee75@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/mmcc-msm8998.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/mmcc-msm8998.c b/drivers/clk/qcom/mmcc-msm8998.c index b0b51adb73a5..1180e48c687a 100644 --- a/drivers/clk/qcom/mmcc-msm8998.c +++ b/drivers/clk/qcom/mmcc-msm8998.c @@ -2610,11 +2610,13 @@ static struct gdsc camss_cpp_gdsc = { static struct gdsc bimc_smmu_gdsc = { .gdscr = 0xe020, .gds_hw_ctrl = 0xe024, + .cxcs = (unsigned int []){ 0xe008 }, + .cxc_count = 1, .pd = { .name = "bimc_smmu", }, .pwrsts = PWRSTS_OFF_ON, - .flags = HW_CTRL | ALWAYS_ON, + .flags = VOTABLE, }; static struct clk_regmap *mmcc_msm8998_clocks[] = { From 471e2875f8904539985e62220afd6c88e70779fa Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Sat, 2 Sep 2023 19:34:23 +0200 Subject: [PATCH 094/396] clk: qcom: mmcc-msm8974: remove ocmemcx_ahb_clk According to a commit in the 3.4 vendor kernel sources[0] the ocmemcx_ahb_clk clock "is controlled by RPM and should not be touched by APPS.". [0] https://git.codelinaro.org/clo/la/kernel/msm/-/commit/37df5f2d91b4d5768b37fcaacaeea958dd683ebc And indeed, when using MDSS+GPU+OCMEM on MSM8226 and not using clk_ignore_unused, when Linux tries to disable the clock the device crashes and reboots. And since there's also no evidence of this clock in msm8974 vendor kernel sources, remove the clock for msm8226 and msm8974. Fixes: d8b212014e69 ("clk: qcom: Add support for MSM8974's multimedia clock controller (MMCC)") Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230902-msm8226-ocmemcx_ahb_clk-remove-v1-1-8124dbde83b9@z3ntu.xyz Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/mmcc-msm8974.c | 18 ------------------ include/dt-bindings/clock/qcom,mmcc-msm8974.h | 1 - 2 files changed, 19 deletions(-) diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index 1f3bd302fe6e..a31f6cf0c4e0 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -2170,22 +2170,6 @@ static struct clk_branch mmss_s0_axi_clk = { }, }; -static struct clk_branch ocmemcx_ahb_clk = { - .halt_reg = 0x405c, - .clkr = { - .enable_reg = 0x405c, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "ocmemcx_ahb_clk", - .parent_hws = (const struct clk_hw*[]){ - &mmss_ahb_clk_src.clkr.hw - }, - .num_parents = 1, - .ops = &clk_branch2_ops, - }, - }, -}; - static struct clk_branch ocmemcx_ocmemnoc_clk = { .halt_reg = 0x4058, .clkr = { @@ -2503,7 +2487,6 @@ static struct clk_regmap *mmcc_msm8226_clocks[] = { [MMSS_MMSSNOC_BTO_AHB_CLK] = &mmss_mmssnoc_bto_ahb_clk.clkr, [MMSS_MMSSNOC_AXI_CLK] = &mmss_mmssnoc_axi_clk.clkr, [MMSS_S0_AXI_CLK] = &mmss_s0_axi_clk.clkr, - [OCMEMCX_AHB_CLK] = &ocmemcx_ahb_clk.clkr, [OXILI_GFX3D_CLK] = &oxili_gfx3d_clk.clkr, [OXILICX_AHB_CLK] = &oxilicx_ahb_clk.clkr, [OXILICX_AXI_CLK] = &oxilicx_axi_clk.clkr, @@ -2660,7 +2643,6 @@ static struct clk_regmap *mmcc_msm8974_clocks[] = { [MMSS_MMSSNOC_BTO_AHB_CLK] = &mmss_mmssnoc_bto_ahb_clk.clkr, [MMSS_MMSSNOC_AXI_CLK] = &mmss_mmssnoc_axi_clk.clkr, [MMSS_S0_AXI_CLK] = &mmss_s0_axi_clk.clkr, - [OCMEMCX_AHB_CLK] = &ocmemcx_ahb_clk.clkr, [OCMEMCX_OCMEMNOC_CLK] = &ocmemcx_ocmemnoc_clk.clkr, [OCMEMNOC_CLK] = &ocmemnoc_clk.clkr, [OXILI_GFX3D_CLK] = &oxili_gfx3d_clk.clkr, diff --git a/include/dt-bindings/clock/qcom,mmcc-msm8974.h b/include/dt-bindings/clock/qcom,mmcc-msm8974.h index a62cb0629a7a..743ee60632eb 100644 --- a/include/dt-bindings/clock/qcom,mmcc-msm8974.h +++ b/include/dt-bindings/clock/qcom,mmcc-msm8974.h @@ -121,7 +121,6 @@ #define MMSS_MMSSNOC_BTO_AHB_CLK 112 #define MMSS_MMSSNOC_AXI_CLK 113 #define MMSS_S0_AXI_CLK 114 -#define OCMEMCX_AHB_CLK 115 #define OCMEMCX_OCMEMNOC_CLK 116 #define OXILI_OCMEMGX_CLK 117 #define OCMEMNOC_CLK 118 From 0b8aae7ed8eaf24d5f59d390325e9b2ebf1c78bd Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Sat, 9 Sep 2023 18:04:28 +0530 Subject: [PATCH 095/396] dt-bindings: clock: qcom: Add RPMHCC for SM4450 Add compatible string for qcom RPMHCC for SM4450 platform. Signed-off-by: Ajit Pandey Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230909123431.1725728-2-quic_ajipan@quicinc.com Signed-off-by: Bjorn Andersson --- Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index fd14d18309a8..4eb5e59f6772 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -28,6 +28,7 @@ properties: - qcom,sdx55-rpmh-clk - qcom,sdx65-rpmh-clk - qcom,sdx75-rpmh-clk + - qcom,sm4450-rpmh-clk - qcom,sm6350-rpmh-clk - qcom,sm8150-rpmh-clk - qcom,sm8250-rpmh-clk From 5a6eabf3268f91ce3cb5350210d0a876fa65b481 Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Sat, 9 Sep 2023 18:04:29 +0530 Subject: [PATCH 096/396] clk: qcom: rpmh: Add RPMH clocks support for SM4450 Add support for RPMH clocks for SM4450 platform. Signed-off-by: Ajit Pandey Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230909123431.1725728-3-quic_ajipan@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-rpmh.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 4c5b552b47b6..5d853fd43294 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -350,6 +350,7 @@ DEFINE_CLK_RPMH_VRM(ln_bb_clk3, _a2, "lnbclka3", 2); DEFINE_CLK_RPMH_VRM(ln_bb_clk1, _a4, "lnbclka1", 4); DEFINE_CLK_RPMH_VRM(ln_bb_clk2, _a4, "lnbclka2", 4); +DEFINE_CLK_RPMH_VRM(ln_bb_clk3, _a4, "lnbclka3", 4); DEFINE_CLK_RPMH_VRM(ln_bb_clk2, _g4, "lnbclkg2", 4); DEFINE_CLK_RPMH_VRM(ln_bb_clk3, _g4, "lnbclkg3", 4); @@ -717,6 +718,25 @@ static const struct clk_rpmh_desc clk_rpmh_sdx75 = { .num_clks = ARRAY_SIZE(sdx75_rpmh_clocks), }; +static struct clk_hw *sm4450_rpmh_clocks[] = { + [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div4.hw, + [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div4_ao.hw, + [RPMH_LN_BB_CLK2] = &clk_rpmh_ln_bb_clk2_a4.hw, + [RPMH_LN_BB_CLK2_A] = &clk_rpmh_ln_bb_clk2_a4_ao.hw, + [RPMH_LN_BB_CLK3] = &clk_rpmh_ln_bb_clk3_a4.hw, + [RPMH_LN_BB_CLK3_A] = &clk_rpmh_ln_bb_clk3_a4_ao.hw, + [RPMH_RF_CLK1] = &clk_rpmh_rf_clk1_a.hw, + [RPMH_RF_CLK1_A] = &clk_rpmh_rf_clk1_a_ao.hw, + [RPMH_RF_CLK5] = &clk_rpmh_rf_clk5_a.hw, + [RPMH_RF_CLK5_A] = &clk_rpmh_rf_clk5_a_ao.hw, + [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_sm4450 = { + .clks = sm4450_rpmh_clocks, + .num_clks = ARRAY_SIZE(sm4450_rpmh_clocks), +}; + static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, void *data) { @@ -810,6 +830,7 @@ static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,sdx55-rpmh-clk", .data = &clk_rpmh_sdx55}, { .compatible = "qcom,sdx65-rpmh-clk", .data = &clk_rpmh_sdx65}, { .compatible = "qcom,sdx75-rpmh-clk", .data = &clk_rpmh_sdx75}, + { .compatible = "qcom,sm4450-rpmh-clk", .data = &clk_rpmh_sm4450}, { .compatible = "qcom,sm6350-rpmh-clk", .data = &clk_rpmh_sm6350}, { .compatible = "qcom,sm8150-rpmh-clk", .data = &clk_rpmh_sm8150}, { .compatible = "qcom,sm8250-rpmh-clk", .data = &clk_rpmh_sm8250}, From d2d04deb5566b82aeb795f24014f5b3bdb8315ed Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Sat, 9 Sep 2023 18:04:30 +0530 Subject: [PATCH 097/396] dt-bindings: clock: qcom: Add GCC clocks for SM4450 Add support for qcom global clock controller bindings for SM4450 platform. Signed-off-by: Ajit Pandey Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230909123431.1725728-4-quic_ajipan@quicinc.com Signed-off-by: Bjorn Andersson --- .../bindings/clock/qcom,sm4450-gcc.yaml | 55 +++++ include/dt-bindings/clock/qcom,sm4450-gcc.h | 197 ++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sm4450-gcc.yaml create mode 100644 include/dt-bindings/clock/qcom,sm4450-gcc.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sm4450-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm4450-gcc.yaml new file mode 100644 index 000000000000..5953c8d92436 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm4450-gcc.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm4450-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on SM4450 + +maintainers: + - Ajit Pandey + - Taniya Das + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on SM4450 + + See also:: include/dt-bindings/clock/qcom,sm4450-gcc.h + +properties: + compatible: + const: qcom,sm4450-gcc + + clocks: + items: + - description: Board XO source + - description: Sleep clock source + - description: UFS Phy Rx symbol 0 clock source + - description: UFS Phy Rx symbol 1 clock source + - description: UFS Phy Tx symbol 0 clock source + - description: USB3 Phy wrapper pipe clock source + +required: + - compatible + - clocks + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,sm4450-gcc"; + reg = <0x00100000 0x001f4200>; + clocks = <&rpmhcc RPMH_CXO_CLK>, <&sleep_clk>, + <&ufs_mem_phy 0>, <&ufs_mem_phy 1>, + <&ufs_mem_phy 2>, <&usb_1_qmpphy>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/qcom,sm4450-gcc.h b/include/dt-bindings/clock/qcom,sm4450-gcc.h new file mode 100644 index 000000000000..c18e47a86f40 --- /dev/null +++ b/include/dt-bindings/clock/qcom,sm4450-gcc.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_QCOM_GCC_SM4450_H +#define _DT_BINDINGS_CLK_QCOM_GCC_SM4450_H + +/* GCC clocks */ +#define GCC_AGGRE_NOC_PCIE_0_AXI_CLK 0 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 1 +#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 2 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 3 +#define GCC_BOOT_ROM_AHB_CLK 4 +#define GCC_CAMERA_AHB_CLK 5 +#define GCC_CAMERA_HF_AXI_CLK 6 +#define GCC_CAMERA_SF_AXI_CLK 7 +#define GCC_CAMERA_SLEEP_CLK 8 +#define GCC_CAMERA_XO_CLK 9 +#define GCC_CFG_NOC_PCIE_ANOC_AHB_CLK 10 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 11 +#define GCC_DDRSS_GPU_AXI_CLK 12 +#define GCC_DDRSS_PCIE_SF_TBU_CLK 13 +#define GCC_DISP_AHB_CLK 14 +#define GCC_DISP_HF_AXI_CLK 15 +#define GCC_DISP_XO_CLK 16 +#define GCC_EUSB3_0_CLKREF_EN 17 +#define GCC_GP1_CLK 18 +#define GCC_GP1_CLK_SRC 19 +#define GCC_GP2_CLK 20 +#define GCC_GP2_CLK_SRC 21 +#define GCC_GP3_CLK 22 +#define GCC_GP3_CLK_SRC 23 +#define GCC_GPLL0 24 +#define GCC_GPLL0_OUT_EVEN 25 +#define GCC_GPLL0_OUT_ODD 26 +#define GCC_GPLL1 27 +#define GCC_GPLL3 28 +#define GCC_GPLL4 29 +#define GCC_GPLL9 30 +#define GCC_GPLL10 31 +#define GCC_GPU_CFG_AHB_CLK 32 +#define GCC_GPU_GPLL0_CLK_SRC 33 +#define GCC_GPU_GPLL0_DIV_CLK_SRC 34 +#define GCC_GPU_MEMNOC_GFX_CLK 35 +#define GCC_GPU_SNOC_DVM_GFX_CLK 36 +#define GCC_HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_CLK 37 +#define GCC_HLOS1_VOTE_AGGRE_NOC_MMU_PCIE_TBU_CLK 38 +#define GCC_HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_CLK 39 +#define GCC_HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_CLK 40 +#define GCC_HLOS1_VOTE_MMNOC_MMU_TBU_HF0_CLK 41 +#define GCC_HLOS1_VOTE_MMNOC_MMU_TBU_HF1_CLK 42 +#define GCC_HLOS1_VOTE_MMNOC_MMU_TBU_SF0_CLK 43 +#define GCC_HLOS1_VOTE_MMU_TCU_CLK 44 +#define GCC_PCIE_0_AUX_CLK 45 +#define GCC_PCIE_0_AUX_CLK_SRC 46 +#define GCC_PCIE_0_CFG_AHB_CLK 47 +#define GCC_PCIE_0_CLKREF_EN 48 +#define GCC_PCIE_0_MSTR_AXI_CLK 49 +#define GCC_PCIE_0_PHY_RCHNG_CLK 50 +#define GCC_PCIE_0_PHY_RCHNG_CLK_SRC 51 +#define GCC_PCIE_0_PIPE_CLK 52 +#define GCC_PCIE_0_PIPE_CLK_SRC 53 +#define GCC_PCIE_0_PIPE_DIV2_CLK 54 +#define GCC_PCIE_0_PIPE_DIV2_CLK_SRC 55 +#define GCC_PCIE_0_SLV_AXI_CLK 56 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 57 +#define GCC_PDM2_CLK 58 +#define GCC_PDM2_CLK_SRC 59 +#define GCC_PDM_AHB_CLK 60 +#define GCC_PDM_XO4_CLK 61 +#define GCC_QMIP_CAMERA_NRT_AHB_CLK 62 +#define GCC_QMIP_CAMERA_RT_AHB_CLK 63 +#define GCC_QMIP_DISP_AHB_CLK 64 +#define GCC_QMIP_GPU_AHB_CLK 65 +#define GCC_QMIP_PCIE_AHB_CLK 66 +#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 67 +#define GCC_QUPV3_WRAP0_CORE_2X_CLK 68 +#define GCC_QUPV3_WRAP0_CORE_CLK 69 +#define GCC_QUPV3_WRAP0_S0_CLK 70 +#define GCC_QUPV3_WRAP0_S0_CLK_SRC 71 +#define GCC_QUPV3_WRAP0_S1_CLK 72 +#define GCC_QUPV3_WRAP0_S1_CLK_SRC 73 +#define GCC_QUPV3_WRAP0_S2_CLK 74 +#define GCC_QUPV3_WRAP0_S2_CLK_SRC 75 +#define GCC_QUPV3_WRAP0_S3_CLK 76 +#define GCC_QUPV3_WRAP0_S3_CLK_SRC 77 +#define GCC_QUPV3_WRAP0_S4_CLK 78 +#define GCC_QUPV3_WRAP0_S4_CLK_SRC 79 +#define GCC_QUPV3_WRAP1_CORE_2X_CLK 80 +#define GCC_QUPV3_WRAP1_CORE_CLK 81 +#define GCC_QUPV3_WRAP1_S0_CLK 82 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 83 +#define GCC_QUPV3_WRAP1_S1_CLK 84 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 85 +#define GCC_QUPV3_WRAP1_S2_CLK 86 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 87 +#define GCC_QUPV3_WRAP1_S3_CLK 88 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 89 +#define GCC_QUPV3_WRAP1_S4_CLK 90 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 91 +#define GCC_QUPV3_WRAP_0_M_AHB_CLK 92 +#define GCC_QUPV3_WRAP_0_S_AHB_CLK 93 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 94 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 95 +#define GCC_SDCC1_AHB_CLK 96 +#define GCC_SDCC1_APPS_CLK 97 +#define GCC_SDCC1_APPS_CLK_SRC 98 +#define GCC_SDCC1_ICE_CORE_CLK 99 +#define GCC_SDCC1_ICE_CORE_CLK_SRC 100 +#define GCC_SDCC2_AHB_CLK 101 +#define GCC_SDCC2_APPS_CLK 102 +#define GCC_SDCC2_APPS_CLK_SRC 103 +#define GCC_UFS_0_CLKREF_EN 104 +#define GCC_UFS_PAD_CLKREF_EN 105 +#define GCC_UFS_PHY_AHB_CLK 106 +#define GCC_UFS_PHY_AXI_CLK 107 +#define GCC_UFS_PHY_AXI_CLK_SRC 108 +#define GCC_UFS_PHY_AXI_HW_CTL_CLK 109 +#define GCC_UFS_PHY_ICE_CORE_CLK 110 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 111 +#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 112 +#define GCC_UFS_PHY_PHY_AUX_CLK 113 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 114 +#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 115 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 116 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC 117 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 118 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC 119 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 120 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC 121 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 122 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 123 +#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 124 +#define GCC_USB30_PRIM_MASTER_CLK 125 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 126 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 127 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 128 +#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 129 +#define GCC_USB30_PRIM_SLEEP_CLK 130 +#define GCC_USB3_0_CLKREF_EN 131 +#define GCC_USB3_PRIM_PHY_AUX_CLK 132 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 133 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 134 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 135 +#define GCC_USB3_PRIM_PHY_PIPE_CLK_SRC 136 +#define GCC_VCODEC0_AXI_CLK 137 +#define GCC_VENUS_CTL_AXI_CLK 138 +#define GCC_VIDEO_AHB_CLK 139 +#define GCC_VIDEO_THROTTLE_CORE_CLK 140 +#define GCC_VIDEO_VCODEC0_SYS_CLK 141 +#define GCC_VIDEO_VENUS_CLK_SRC 142 +#define GCC_VIDEO_VENUS_CTL_CLK 143 +#define GCC_VIDEO_XO_CLK 144 + +/* GCC power domains */ +#define GCC_PCIE_0_GDSC 0 +#define GCC_UFS_PHY_GDSC 1 +#define GCC_USB30_PRIM_GDSC 2 +#define GCC_VCODEC0_GDSC 3 +#define GCC_VENUS_GDSC 4 + +/* GCC resets */ +#define GCC_CAMERA_BCR 0 +#define GCC_DISPLAY_BCR 1 +#define GCC_GPU_BCR 2 +#define GCC_PCIE_0_BCR 3 +#define GCC_PCIE_0_LINK_DOWN_BCR 4 +#define GCC_PCIE_0_NOCSR_COM_PHY_BCR 5 +#define GCC_PCIE_0_PHY_BCR 6 +#define GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR 7 +#define GCC_PCIE_PHY_BCR 8 +#define GCC_PCIE_PHY_CFG_AHB_BCR 9 +#define GCC_PCIE_PHY_COM_BCR 10 +#define GCC_PDM_BCR 11 +#define GCC_QUPV3_WRAPPER_0_BCR 12 +#define GCC_QUPV3_WRAPPER_1_BCR 13 +#define GCC_QUSB2PHY_PRIM_BCR 14 +#define GCC_QUSB2PHY_SEC_BCR 15 +#define GCC_SDCC1_BCR 16 +#define GCC_SDCC2_BCR 17 +#define GCC_UFS_PHY_BCR 18 +#define GCC_USB30_PRIM_BCR 19 +#define GCC_USB3_DP_PHY_PRIM_BCR 20 +#define GCC_USB3_DP_PHY_SEC_BCR 21 +#define GCC_USB3_PHY_PRIM_BCR 22 +#define GCC_USB3_PHY_SEC_BCR 23 +#define GCC_USB3PHY_PHY_PRIM_BCR 24 +#define GCC_USB3PHY_PHY_SEC_BCR 25 +#define GCC_VCODEC0_BCR 26 +#define GCC_VENUS_BCR 27 +#define GCC_VIDEO_BCR 28 +#define GCC_VIDEO_VENUS_BCR 29 +#define GCC_VENUS_CTL_AXI_CLK_ARES 30 +#define GCC_VIDEO_VENUS_CTL_CLK_ARES 31 + +#endif From c32c4ef98baca6dfedbddace1e0bbcae0ca65050 Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Sat, 9 Sep 2023 18:04:31 +0530 Subject: [PATCH 098/396] clk: qcom: Add GCC driver support for SM4450 Add Global Clock Controller (GCC) support for SM4450 platform. Signed-off-by: Ajit Pandey Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20230909123431.1725728-5-quic_ajipan@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-sm4450.c | 2897 +++++++++++++++++++++++++++++++++ 3 files changed, 2907 insertions(+) create mode 100644 drivers/clk/qcom/gcc-sm4450.c diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 865db5202e4c..0f7aa00ea33d 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -834,6 +834,15 @@ config SM_DISPCC_8550 Say Y if you want to support display devices and functionality such as splash screen. +config SM_GCC_4450 + tristate "SM4450 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on SM4450 devices. + Say Y if you want to use peripheral devices such as UART, SPI, + I2C, USB, SD/UFS, PCIe, etc. + config SM_GCC_6115 tristate "SM6115 and SM4250 Global Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 4790c8cca426..74d3a7724c91 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -109,6 +109,7 @@ obj-$(CONFIG_SM_DISPCC_6375) += dispcc-sm6375.o obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o obj-$(CONFIG_SM_DISPCC_8450) += dispcc-sm8450.o obj-$(CONFIG_SM_DISPCC_8550) += dispcc-sm8550.o +obj-$(CONFIG_SM_GCC_4450) += gcc-sm4450.o obj-$(CONFIG_SM_GCC_6115) += gcc-sm6115.o obj-$(CONFIG_SM_GCC_6125) += gcc-sm6125.o obj-$(CONFIG_SM_GCC_6350) += gcc-sm6350.o diff --git a/drivers/clk/qcom/gcc-sm4450.c b/drivers/clk/qcom/gcc-sm4450.c new file mode 100644 index 000000000000..41c6357d09bc --- /dev/null +++ b/drivers/clk/qcom/gcc-sm4450.c @@ -0,0 +1,2897 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" +#include "clk-regmap-phy-mux.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_SLEEP_CLK, + DT_PCIE_0_PIPE_CLK, + DT_UFS_PHY_RX_SYMBOL_0_CLK, + DT_UFS_PHY_RX_SYMBOL_1_CLK, + DT_UFS_PHY_TX_SYMBOL_0_CLK, + DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL0_OUT_ODD, + P_GCC_GPLL1_OUT_MAIN, + P_GCC_GPLL3_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL9_OUT_MAIN, + P_GCC_GPLL10_OUT_MAIN, + P_SLEEP_CLK, + P_UFS_PHY_RX_SYMBOL_0_CLK, + P_UFS_PHY_RX_SYMBOL_1_CLK, + P_UFS_PHY_TX_SYMBOL_0_CLK, + P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, +}; + +static const struct pll_vco lucid_evo_vco[] = { + { 249600000, 2020000000, 0 }, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = { + { 0x1, 2 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 10, + .post_div_table = post_div_table_gcc_gpll0_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_evo_ops, + }, +}; + +static const struct clk_div_table post_div_table_gcc_gpll0_out_odd[] = { + { 0x2, 3 }, + { } +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_odd = { + .offset = 0x0, + .post_div_shift = 14, + .post_div_table = post_div_table_gcc_gpll0_out_odd, + .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_odd), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_odd", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_evo_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll1 = { + .offset = 0x1000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static const struct alpha_pll_config gcc_gpll3_config = { + .l = 0x14, + .alpha = 0xd555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000805, +}; + +static struct clk_alpha_pll gcc_gpll3 = { + .offset = 0x3000, + .vco_table = lucid_evo_vco, + .num_vco = ARRAY_SIZE(lucid_evo_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll3", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll10 = { + .offset = 0xa000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x62018, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll10", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .index = DT_SLEEP_CLK }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL1_OUT_MAIN, 4 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll1.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL0_OUT_ODD, 2 }, + { P_GCC_GPLL10_OUT_MAIN, 3 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll0_out_odd.clkr.hw }, + { .hw = &gcc_gpll10.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL9_OUT_MAIN, 2 }, + { P_GCC_GPLL4_OUT_MAIN, 5 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll9.clkr.hw }, + { .hw = &gcc_gpll4.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { P_UFS_PHY_RX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_7[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_8[] = { + { P_UFS_PHY_RX_SYMBOL_1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_1_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_9[] = { + { P_UFS_PHY_TX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_9[] = { + { .index = DT_UFS_PHY_TX_SYMBOL_0_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_10[] = { + { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_11[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL3_OUT_MAIN, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_11[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll3.clkr.hw }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = { + .reg = 0x7b060, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk_src", + .parent_data = &(const struct clk_parent_data) { + .index = DT_PCIE_0_PIPE_CLK, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_0_clk_src = { + .reg = 0x87060, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_7, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk_src", + .parent_data = gcc_parent_data_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_1_clk_src = { + .reg = 0x870d0, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_8, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_tx_symbol_0_clk_src = { + .reg = 0x87050, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_9, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x49068, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_10, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x74004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x75004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x76004, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { + .cmd_rcgr = 0x7b064, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0x7b048, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x43010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GCC_GPLL0_OUT_EVEN, 2.5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = { + .name = "gcc_qupv3_wrap0_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { + .cmd_rcgr = 0x27014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s1_clk_src[] = { + F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75), + F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = { + .name = "gcc_qupv3_wrap0_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { + .cmd_rcgr = 0x27148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = { + .name = "gcc_qupv3_wrap0_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { + .cmd_rcgr = 0x2727c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = { + .name = "gcc_qupv3_wrap0_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { + .cmd_rcgr = 0x273b0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = { + .name = "gcc_qupv3_wrap0_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { + .cmd_rcgr = 0x274e4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { + .name = "gcc_qupv3_wrap1_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x28014, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { + .name = "gcc_qupv3_wrap1_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x28148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { + .cmd_rcgr = 0x2827c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = { + .name = "gcc_qupv3_wrap1_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x283b0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { + .name = "gcc_qupv3_wrap1_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x284e4, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s1_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { + F(144000, P_BI_TCXO, 16, 3, 25), + F(400000, P_BI_TCXO, 12, 1, 4), + F(20000000, P_GCC_GPLL0_OUT_EVEN, 5, 1, 3), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_ODD, 2, 0, 0), + F(192000000, P_GCC_GPLL10_OUT_MAIN, 2, 0, 0), + F(384000000, P_GCC_GPLL10_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0xb3010, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_apps_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_ODD, 2, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0xb3030, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0x24014, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x8702c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x87074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x870a8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0), + F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x8708c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_unipro_core_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0), + F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0), + F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0x49028, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x49040, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x4906c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_video_venus_clk_src[] = { + F(133333333, P_GCC_GPLL3_OUT_MAIN, 3, 0, 0), + F(240000000, P_GCC_GPLL3_OUT_MAIN, 2, 0, 0), + F(365000000, P_GCC_GPLL3_OUT_MAIN, 2, 0, 0), + F(384000000, P_GCC_GPLL3_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_video_venus_clk_src = { + .cmd_rcgr = 0xb6004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_11, + .freq_tbl = ftbl_gcc_video_venus_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_video_venus_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div gcc_pcie_0_pipe_div2_clk_src = { + .reg = 0x7b084, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_div2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = { + .reg = 0x49058, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gcc_aggre_noc_pcie_0_axi_clk = { + .halt_reg = 0x7b08c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x7b08c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x870d4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x870d4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x870d4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x870d4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x870d4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x870d4, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { + .halt_reg = 0x49088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x49088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x49088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x48004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x48004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_boot_rom_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_hf_axi_clk = { + .halt_reg = 0x36010, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x36010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x36010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camera_sf_axi_clk = { + .halt_reg = 0x36014, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x36014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x36014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_camera_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = { + .halt_reg = 0x20030, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x20030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x49084, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x49084, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x49084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_prim_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_gpu_axi_clk = { + .halt_reg = 0x81154, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x81154, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x81154, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_gpu_axi_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_pcie_sf_tbu_clk = { + .halt_reg = 0x7b090, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x7b090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_pcie_sf_tbu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x3700c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x3700c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3700c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_hf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eusb3_0_clkref_en = { + .halt_reg = 0x9c00c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x9c00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_eusb3_0_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x74000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x74000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp2_clk = { + .halt_reg = 0x75000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x75000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp3_clk = { + .halt_reg = 0x76000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x76000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gp3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gp3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_div_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_out_even.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_memnoc_gfx_clk = { + .halt_reg = 0x81010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x81010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x81010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { + .halt_reg = 0x81018, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x81018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_aggre_noc_mmu_audio_tbu_clk = { + .halt_reg = 0x8d004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gcc_hlos1_vote_aggre_noc_mmu_audio_tbu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_aggre_noc_mmu_pcie_tbu_clk = { + .halt_reg = 0x8d010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gcc_hlos1_vote_aggre_noc_mmu_pcie_tbu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_aggre_noc_mmu_tbu1_clk = { + .halt_reg = 0x8d008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gcc_hlos1_vote_aggre_noc_mmu_tbu1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_aggre_noc_mmu_tbu2_clk = { + .halt_reg = 0x8d00c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gcc_hlos1_vote_aggre_noc_mmu_tbu2_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_mmnoc_mmu_tbu_hf0_clk = { + .halt_reg = 0x8d018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gcc_hlos1_vote_mmnoc_mmu_tbu_hf0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_mmnoc_mmu_tbu_hf1_clk = { + .halt_reg = 0x8d01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gcc_hlos1_vote_mmnoc_mmu_tbu_hf1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_mmnoc_mmu_tbu_sf0_clk = { + .halt_reg = 0x8d014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gcc_hlos1_vote_mmnoc_mmu_tbu_sf0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_hlos1_vote_mmu_tcu_clk = { + .halt_reg = 0x8d02c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x8d02c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gcc_hlos1_vote_mmu_tcu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x7b034, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_cfg_ahb_clk = { + .halt_reg = 0x7b030, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7b030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_clkref_en = { + .halt_reg = 0x9c004, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x9c004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_mstr_axi_clk = { + .halt_reg = 0x7b028, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_phy_rchng_clk = { + .halt_reg = 0x7b044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62000, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_clk = { + .halt_reg = 0x7b03c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_pipe_div2_clk = { + .halt_reg = 0x7b094, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x62010, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_0_pipe_div2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0x7b020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7b020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = { + .halt_reg = 0x7b01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x4300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4300c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pdm2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_ahb_clk = { + .halt_reg = 0x43004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x43004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x43004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm_xo4_clk = { + .halt_reg = 0x43008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x43008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = { + .halt_reg = 0x36008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x36008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x36008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_nrt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_rt_ahb_clk = { + .halt_reg = 0x3600c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3600c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3600c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_camera_rt_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_disp_ahb_clk = { + .halt_reg = 0x37008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x37008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x37008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_disp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_gpu_ahb_clk = { + .halt_reg = 0x81008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x81008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x81008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_gpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_ahb_clk = { + .halt_reg = 0x7b018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x7b018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7b018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = { + .halt_reg = 0x42008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x42008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_core_clk = { + .halt_reg = 0x33000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s0_clk = { + .halt_reg = 0x2700c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s1_clk = { + .halt_reg = 0x27140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s2_clk = { + .halt_reg = 0x27274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s3_clk = { + .halt_reg = 0x273a8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap0_s4_clk = { + .halt_reg = 0x274dc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = { + .halt_reg = 0x3314c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_2x_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_clk = { + .halt_reg = 0x33140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s0_clk = { + .halt_reg = 0x2800c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s1_clk = { + .halt_reg = 0x28140, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s2_clk = { + .halt_reg = 0x28274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s3_clk = { + .halt_reg = 0x283a8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s4_clk = { + .halt_reg = 0x284dc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = { + .halt_reg = 0x27004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x27004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_0_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = { + .halt_reg = 0x27008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x27008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_0_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = { + .halt_reg = 0x28004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x28004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_m_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { + .halt_reg = 0x28008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x28008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x62008, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_1_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0xb3004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb3004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0xb3008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb3008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc1_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ice_core_clk = { + .halt_reg = 0xb3028, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb3028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb3028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc1_ice_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc1_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x2400c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2400c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x24004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x24004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_0_clkref_en = { + .halt_reg = 0x9c000, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x9c000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_0_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_pad_clkref_en = { + .halt_reg = 0x9c024, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x9c024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_pad_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0x87020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x87020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x87020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_clk = { + .halt_reg = 0x87018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x87018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x87018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x87018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x87018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x87018, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_clk = { + .halt_reg = 0x8706c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8706c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x8706c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = { + .halt_reg = 0x8706c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8706c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x8706c, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_ice_core_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_ice_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_clk = { + .halt_reg = 0x870a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x870a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x870a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = { + .halt_reg = 0x870a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x870a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x870a4, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_phy_aux_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { + .halt_reg = 0x87028, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x87028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { + .halt_reg = 0x870c0, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x870c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x87024, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x87024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_clk = { + .halt_reg = 0x87064, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x87064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x87064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = { + .halt_reg = 0x87064, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x87064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x87064, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_unipro_core_hw_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_ufs_phy_unipro_core_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0x49018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_mock_utmi_clk = { + .halt_reg = 0x49024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_sleep_clk = { + .halt_reg = 0x49020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_prim_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_0_clkref_en = { + .halt_reg = 0x9c010, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x9c010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_0_clkref_en", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0x4905c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4905c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { + .halt_reg = 0x49060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x49060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_reg = 0x49064, + .halt_check = BRANCH_HALT_DELAY, + .hwcg_reg = 0x49064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x49064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_vcodec0_axi_clk = { + .halt_reg = 0x42020, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x42020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_vcodec0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_venus_ctl_axi_clk = { + .halt_reg = 0x4201c, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x4201c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_venus_ctl_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_throttle_core_clk = { + .halt_reg = 0x42014, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x42014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x42014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_throttle_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_vcodec0_sys_clk = { + .halt_reg = 0xb6058, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xb6058, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xb6058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_vcodec0_sys_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_video_venus_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_venus_ctl_clk = { + .halt_reg = 0xb6038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb6038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_venus_ctl_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_video_venus_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gcc_pcie_0_gdsc = { + .gdscr = 0x7b004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_ufs_phy_gdsc = { + .gdscr = 0x87004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_prim_gdsc = { + .gdscr = 0x49004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_vcodec0_gdsc = { + .gdscr = 0xb6044, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_vcodec0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL, +}; + +static struct gdsc gcc_venus_gdsc = { + .gdscr = 0xb6020, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_venus_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *gcc_sm4450_clocks[] = { + [GCC_AGGRE_NOC_PCIE_0_AXI_CLK] = &gcc_aggre_noc_pcie_0_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_aggre_ufs_phy_axi_hw_ctl_clk.clkr, + [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr, + [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DDRSS_PCIE_SF_TBU_CLK] = &gcc_ddrss_pcie_sf_tbu_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_EUSB3_0_CLKREF_EN] = &gcc_eusb3_0_clkref_en.clkr, + [GCC_GP1_CLK] = &gcc_gp1_clk.clkr, + [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr, + [GCC_GP2_CLK] = &gcc_gp2_clk.clkr, + [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr, + [GCC_GP3_CLK] = &gcc_gp3_clk.clkr, + [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr, + [GCC_GPLL0] = &gcc_gpll0.clkr, + [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr, + [GCC_GPLL0_OUT_ODD] = &gcc_gpll0_out_odd.clkr, + [GCC_GPLL1] = &gcc_gpll1.clkr, + [GCC_GPLL3] = &gcc_gpll3.clkr, + [GCC_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL9] = &gcc_gpll9.clkr, + [GCC_GPLL10] = &gcc_gpll10.clkr, + [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr, + [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr, + [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr, + [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr, + [GCC_HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_CLK] = + &gcc_hlos1_vote_aggre_noc_mmu_audio_tbu_clk.clkr, + [GCC_HLOS1_VOTE_AGGRE_NOC_MMU_PCIE_TBU_CLK] = + &gcc_hlos1_vote_aggre_noc_mmu_pcie_tbu_clk.clkr, + [GCC_HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_CLK] = &gcc_hlos1_vote_aggre_noc_mmu_tbu1_clk.clkr, + [GCC_HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_CLK] = &gcc_hlos1_vote_aggre_noc_mmu_tbu2_clk.clkr, + [GCC_HLOS1_VOTE_MMNOC_MMU_TBU_HF0_CLK] = &gcc_hlos1_vote_mmnoc_mmu_tbu_hf0_clk.clkr, + [GCC_HLOS1_VOTE_MMNOC_MMU_TBU_HF1_CLK] = &gcc_hlos1_vote_mmnoc_mmu_tbu_hf1_clk.clkr, + [GCC_HLOS1_VOTE_MMNOC_MMU_TBU_SF0_CLK] = &gcc_hlos1_vote_mmnoc_mmu_tbu_sf0_clk.clkr, + [GCC_HLOS1_VOTE_MMU_TCU_CLK] = &gcc_hlos1_vote_mmu_tcu_clk.clkr, + [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr, + [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr, + [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr, + [GCC_PCIE_0_CLKREF_EN] = &gcc_pcie_0_clkref_en.clkr, + [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr, + [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr, + [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr, + [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr, + [GCC_PCIE_0_PIPE_DIV2_CLK] = &gcc_pcie_0_pipe_div2_clk.clkr, + [GCC_PCIE_0_PIPE_DIV2_CLK_SRC] = &gcc_pcie_0_pipe_div2_clk_src.clkr, + [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr, + [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr, + [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr, + [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr, + [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr, + [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr, + [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr, + [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr, + [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr, + [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr, + [GCC_QMIP_PCIE_AHB_CLK] = &gcc_qmip_pcie_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr, + [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr, + [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr, + [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr, + [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr, + [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr, + [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr, + [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr, + [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr, + [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr, + [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr, + [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr, + [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr, + [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr, + [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr, + [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr, + [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr, + [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr, + [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr, + [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr, + [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr, + [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr, + [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr, + [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr, + [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr, + [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr, + [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr, + [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr, + [GCC_SDCC1_ICE_CORE_CLK_SRC] = &gcc_sdcc1_ice_core_clk_src.clkr, + [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_UFS_0_CLKREF_EN] = &gcc_ufs_0_clkref_en.clkr, + [GCC_UFS_PAD_CLKREF_EN] = &gcc_ufs_pad_clkref_en.clkr, + [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, + [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, + [GCC_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_ufs_phy_axi_hw_ctl_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, + [GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK] = &gcc_ufs_phy_ice_core_hw_ctl_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, + [GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK] = &gcc_ufs_phy_phy_aux_hw_ctl_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK] = &gcc_ufs_phy_unipro_core_hw_ctl_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, + [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr, + [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr, + [GCC_USB3_0_CLKREF_EN] = &gcc_usb3_0_clkref_en.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr, + [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr, + [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr, + [GCC_VCODEC0_AXI_CLK] = &gcc_vcodec0_axi_clk.clkr, + [GCC_VENUS_CTL_AXI_CLK] = &gcc_venus_ctl_axi_clk.clkr, + [GCC_VIDEO_THROTTLE_CORE_CLK] = &gcc_video_throttle_core_clk.clkr, + [GCC_VIDEO_VCODEC0_SYS_CLK] = &gcc_video_vcodec0_sys_clk.clkr, + [GCC_VIDEO_VENUS_CLK_SRC] = &gcc_video_venus_clk_src.clkr, + [GCC_VIDEO_VENUS_CTL_CLK] = &gcc_video_venus_ctl_clk.clkr, +}; + +static struct gdsc *gcc_sm4450_gdscs[] = { + [GCC_PCIE_0_GDSC] = &gcc_pcie_0_gdsc, + [GCC_UFS_PHY_GDSC] = &gcc_ufs_phy_gdsc, + [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc, + [GCC_VCODEC0_GDSC] = &gcc_vcodec0_gdsc, + [GCC_VENUS_GDSC] = &gcc_venus_gdsc, +}; + +static const struct qcom_reset_map gcc_sm4450_resets[] = { + [GCC_CAMERA_BCR] = { 0x36000 }, + [GCC_DISPLAY_BCR] = { 0x37000 }, + [GCC_GPU_BCR] = { 0x81000 }, + [GCC_PCIE_0_BCR] = { 0x7b000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x7c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x7c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x7c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x7c028 }, + [GCC_PCIE_PHY_BCR] = { 0x7f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x7f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x7f010 }, + [GCC_PDM_BCR] = { 0x43000 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x27000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x28000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x22000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x22004 }, + [GCC_SDCC1_BCR] = { 0xb3000 }, + [GCC_SDCC2_BCR] = { 0x24000 }, + [GCC_UFS_PHY_BCR] = { 0x87000 }, + [GCC_USB30_PRIM_BCR] = { 0x49000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x60008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x60014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x60000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x6000c }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x60004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x60010 }, + [GCC_VCODEC0_BCR] = { 0xb6040 }, + [GCC_VENUS_BCR] = { 0xb601c }, + [GCC_VIDEO_BCR] = { 0x42000 }, + [GCC_VIDEO_VENUS_BCR] = { 0xb6000 }, + [GCC_VENUS_CTL_AXI_CLK_ARES] = { 0x4201c, 2 }, + [GCC_VIDEO_VENUS_CTL_CLK_ARES] = { 0xb6038, 2 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src), +}; + +static const struct regmap_config gcc_sm4450_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f41f0, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sm4450_desc = { + .config = &gcc_sm4450_regmap_config, + .clks = gcc_sm4450_clocks, + .num_clks = ARRAY_SIZE(gcc_sm4450_clocks), + .resets = gcc_sm4450_resets, + .num_resets = ARRAY_SIZE(gcc_sm4450_resets), + .gdscs = gcc_sm4450_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_sm4450_gdscs), +}; + +static const struct of_device_id gcc_sm4450_match_table[] = { + { .compatible = "qcom,sm4450-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sm4450_match_table); + +static int gcc_sm4450_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_sm4450_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_lucid_evo_pll_configure(&gcc_gpll3, regmap, &gcc_gpll3_config); + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) + return ret; + + qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); + + /* + * Keep clocks always enabled: + * gcc_camera_ahb_clk + * gcc_camera_sleep_clk + * gcc_camera_xo_clk + * gcc_disp_ahb_clk + * gcc_disp_xo_clk + * gcc_gpu_cfg_ahb_clk + * gcc_video_ahb_clk + * gcc_video_xo_clk + */ + regmap_update_bits(regmap, 0x36004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x36018, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x3601c, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x37004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x37014, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x81004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x42004, BIT(0), BIT(0)); + regmap_update_bits(regmap, 0x42018, BIT(0), BIT(0)); + + regmap_update_bits(regmap, 0x4201c, BIT(21), BIT(21)); + + return qcom_cc_really_probe(pdev, &gcc_sm4450_desc, regmap); +} + +static struct platform_driver gcc_sm4450_driver = { + .probe = gcc_sm4450_probe, + .driver = { + .name = "gcc-sm4450", + .of_match_table = gcc_sm4450_match_table, + }, +}; + +static int __init gcc_sm4450_init(void) +{ + return platform_driver_register(&gcc_sm4450_driver); +} +subsys_initcall(gcc_sm4450_init); + +static void __exit gcc_sm4450_exit(void) +{ + platform_driver_unregister(&gcc_sm4450_driver); +} +module_exit(gcc_sm4450_exit); + +MODULE_DESCRIPTION("QTI GCC SM4450 Driver"); +MODULE_LICENSE("GPL"); From 7138c244fb293f24ce8ab782961022eff00a10c4 Mon Sep 17 00:00:00 2001 From: Danila Tikhonov Date: Wed, 13 Sep 2023 20:56:11 +0300 Subject: [PATCH 099/396] clk: qcom: gcc-sm8150: Fix gcc_sdcc2_apps_clk_src Set .flags = CLK_OPS_PARENT_ENABLE to fix "gcc_sdcc2_apps_clk_src: rcg didn't update its configuration" error. Fixes: 2a1d7eb854bb ("clk: qcom: gcc: Add global clock controller driver for SM8150") Tested-by: Arseniy Velikanov Signed-off-by: Danila Tikhonov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913175612.8685-1-danila@jiaxyga.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-sm8150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/gcc-sm8150.c b/drivers/clk/qcom/gcc-sm8150.c index 41ab210875fb..05d115c52dfe 100644 --- a/drivers/clk/qcom/gcc-sm8150.c +++ b/drivers/clk/qcom/gcc-sm8150.c @@ -774,7 +774,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .name = "gcc_sdcc2_apps_clk_src", .parent_data = gcc_parents_6, .num_parents = ARRAY_SIZE(gcc_parents_6), - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_OPS_PARENT_ENABLE, .ops = &clk_rcg2_floor_ops, }, }; From 318d97849fc2cb45b2238fdb9eaa714b5d669df5 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Tue, 19 Sep 2023 10:15:26 -0400 Subject: [PATCH 100/396] platform/x86: think-lmi: Add bulk save feature On Lenovo platforms there is a limitation in the number of times an attribute can be saved. This is an architectural limitation and it limits the number of attributes that can be modified to 48. A solution for this is instead of the attribute being saved after every modification allow a user to bulk set the attributes and then trigger a final save. This allows unlimited attributes. This patch introduces a save_settings attribute that can be configured to either single or bulk mode by the user. Single mode is the default but customers who want to avoid the 48 attribute limit can enable bulk mode. Displaying the save_settings attribute will display the enabled mode. When in bulk mode writing 'save' to the save_settings attribute will trigger a save. Once this has been done a reboot is required before more attributes can be modified. Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20230919141530.4805-1-mpearson-lenovo@squebb.ca Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../testing/sysfs-class-firmware-attributes | 30 ++++ drivers/platform/x86/think-lmi.c | 152 ++++++++++++++++-- drivers/platform/x86/think-lmi.h | 16 ++ 3 files changed, 183 insertions(+), 15 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes index f205d39409a3..9c82c7b42ff8 100644 --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes @@ -383,6 +383,36 @@ Description: Note that any changes to this attribute requires a reboot for changes to take effect. +What: /sys/class/firmware-attributes/*/attributes/save_settings +Date: August 2023 +KernelVersion: 6.6 +Contact: Mark Pearson +Description: + On Lenovo platforms there is a limitation in the number of times an attribute can be + saved. This is an architectural limitation and it limits the number of attributes + that can be modified to 48. + A solution for this is instead of the attribute being saved after every modification, + to allow a user to bulk set the attributes, and then trigger a final save. This allows + unlimited attributes. + + Read the attribute to check what save mode is enabled (single or bulk). + E.g: + # cat /sys/class/firmware-attributes/thinklmi/attributes/save_settings + single + + Write the attribute with 'bulk' to enable bulk save mode. + Write the attribute with 'single' to enable saving, after every attribute set. + The default setting is single mode. + E.g: + # echo bulk > /sys/class/firmware-attributes/thinklmi/attributes/save_settings + + When in bulk mode write 'save' to trigger a save of all currently modified attributes. + Note, once a save has been triggered, in bulk mode, attributes can no longer be set and + will return a permissions error. This is to prevent users hitting the 48+ save limitation + (which requires entering the BIOS to clear the error condition) + E.g: + # echo save > /sys/class/firmware-attributes/thinklmi/attributes/save_settings + What: /sys/class/firmware-attributes/*/attributes/debug_cmd Date: July 2021 KernelVersion: 5.14 diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index 79346881cadb..d329626720df 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -985,6 +985,13 @@ static ssize_t current_value_store(struct kobject *kobj, if (!tlmi_priv.can_set_bios_settings) return -EOPNOTSUPP; + /* + * If we are using bulk saves a reboot should be done once save has + * been called + */ + if (tlmi_priv.save_mode == TLMI_SAVE_BULK && tlmi_priv.reboot_required) + return -EPERM; + new_setting = kstrdup(buf, GFP_KERNEL); if (!new_setting) return -ENOMEM; @@ -1011,10 +1018,11 @@ static ssize_t current_value_store(struct kobject *kobj, ret = tlmi_simple_call(LENOVO_SET_BIOS_SETTING_CERT_GUID, set_str); if (ret) goto out; - ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID, - tlmi_priv.pwd_admin->save_signature); - if (ret) - goto out; + if (tlmi_priv.save_mode == TLMI_SAVE_BULK) + tlmi_priv.save_required = true; + else + ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID, + tlmi_priv.pwd_admin->save_signature); } else if (tlmi_priv.opcode_support) { /* * If opcode support is present use that interface. @@ -1033,14 +1041,17 @@ static ssize_t current_value_store(struct kobject *kobj, if (ret) goto out; - if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { - ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", - tlmi_priv.pwd_admin->password); - if (ret) - goto out; + if (tlmi_priv.save_mode == TLMI_SAVE_BULK) { + tlmi_priv.save_required = true; + } else { + if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { + ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", + tlmi_priv.pwd_admin->password); + if (ret) + goto out; + } + ret = tlmi_save_bios_settings(""); } - - ret = tlmi_save_bios_settings(""); } else { /* old non-opcode based authentication method (deprecated) */ if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", @@ -1068,10 +1079,14 @@ static ssize_t current_value_store(struct kobject *kobj, if (ret) goto out; - if (auth_str) - ret = tlmi_save_bios_settings(auth_str); - else - ret = tlmi_save_bios_settings(""); + if (tlmi_priv.save_mode == TLMI_SAVE_BULK) { + tlmi_priv.save_required = true; + } else { + if (auth_str) + ret = tlmi_save_bios_settings(auth_str); + else + ret = tlmi_save_bios_settings(""); + } } if (!ret && !tlmi_priv.pending_changes) { tlmi_priv.pending_changes = true; @@ -1152,6 +1167,107 @@ static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute * static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); +static const char * const save_mode_strings[] = { + [TLMI_SAVE_SINGLE] = "single", + [TLMI_SAVE_BULK] = "bulk", + [TLMI_SAVE_SAVE] = "save" +}; + +static ssize_t save_settings_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + /* Check that setting is valid */ + if (WARN_ON(tlmi_priv.save_mode < TLMI_SAVE_SINGLE || + tlmi_priv.save_mode > TLMI_SAVE_BULK)) + return -EIO; + return sysfs_emit(buf, "%s\n", save_mode_strings[tlmi_priv.save_mode]); +} + +static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + char *auth_str = NULL; + int ret = 0; + int cmd; + + cmd = sysfs_match_string(save_mode_strings, buf); + if (cmd < 0) + return cmd; + + /* Use lock in case multiple WMI operations needed */ + mutex_lock(&tlmi_mutex); + + switch (cmd) { + case TLMI_SAVE_SINGLE: + case TLMI_SAVE_BULK: + tlmi_priv.save_mode = cmd; + goto out; + case TLMI_SAVE_SAVE: + /* Check if supported*/ + if (!tlmi_priv.can_set_bios_settings || + tlmi_priv.save_mode == TLMI_SAVE_SINGLE) { + ret = -EOPNOTSUPP; + goto out; + } + /* Check there is actually something to save */ + if (!tlmi_priv.save_required) { + ret = -ENOENT; + goto out; + } + /* Check if certificate authentication is enabled and active */ + if (tlmi_priv.certificate_support && tlmi_priv.pwd_admin->cert_installed) { + if (!tlmi_priv.pwd_admin->signature || + !tlmi_priv.pwd_admin->save_signature) { + ret = -EINVAL; + goto out; + } + ret = tlmi_simple_call(LENOVO_SAVE_BIOS_SETTING_CERT_GUID, + tlmi_priv.pwd_admin->save_signature); + if (ret) + goto out; + } else if (tlmi_priv.opcode_support) { + if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { + ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin", + tlmi_priv.pwd_admin->password); + if (ret) + goto out; + } + ret = tlmi_save_bios_settings(""); + } else { /* old non-opcode based authentication method (deprecated) */ + if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { + auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", + tlmi_priv.pwd_admin->password, + encoding_options[tlmi_priv.pwd_admin->encoding], + tlmi_priv.pwd_admin->kbdlang); + if (!auth_str) { + ret = -ENOMEM; + goto out; + } + } + + if (auth_str) + ret = tlmi_save_bios_settings(auth_str); + else + ret = tlmi_save_bios_settings(""); + } + tlmi_priv.save_required = false; + tlmi_priv.reboot_required = true; + + if (!ret && !tlmi_priv.pending_changes) { + tlmi_priv.pending_changes = true; + /* let userland know it may need to check reboot pending again */ + kobject_uevent(&tlmi_priv.class_dev->kobj, KOBJ_CHANGE); + } + break; + } +out: + mutex_unlock(&tlmi_mutex); + kfree(auth_str); + return ret ?: count; +} + +static struct kobj_attribute save_settings = __ATTR_RW(save_settings); + /* ---- Debug interface--------------------------------------------------------- */ static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) @@ -1221,6 +1337,8 @@ static void tlmi_release_attr(void) } } sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &pending_reboot.attr); + sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &save_settings.attr); + if (tlmi_priv.can_debug_cmd && debug_support) sysfs_remove_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr); @@ -1302,6 +1420,10 @@ static int tlmi_sysfs_init(void) if (ret) goto fail_create_attr; + ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &save_settings.attr); + if (ret) + goto fail_create_attr; + if (tlmi_priv.can_debug_cmd && debug_support) { ret = sysfs_create_file(&tlmi_priv.attribute_kset->kobj, &debug_cmd.attr); if (ret) diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h index 4daba6151cd6..e1975ffebeb4 100644 --- a/drivers/platform/x86/think-lmi.h +++ b/drivers/platform/x86/think-lmi.h @@ -27,6 +27,19 @@ enum level_option { TLMI_LEVEL_MASTER, }; +/* + * There are a limit on the number of WMI operations you can do if you use + * the default implementation of saving on every set. This is due to a + * limitation in EFI variable space used. + * Have a 'bulk save' mode where you can manually trigger the save, and can + * therefore set unlimited variables - for users that need it. + */ +enum save_mode { + TLMI_SAVE_SINGLE, + TLMI_SAVE_BULK, + TLMI_SAVE_SAVE, +}; + /* password configuration details */ struct tlmi_pwdcfg_core { uint32_t password_mode; @@ -86,6 +99,9 @@ struct think_lmi { bool can_debug_cmd; bool opcode_support; bool certificate_support; + enum save_mode save_mode; + bool save_required; + bool reboot_required; struct tlmi_attr_setting *setting[TLMI_SETTINGS_COUNT]; struct device *class_dev; From 45ae16ec3a3d63375cd95317af66b844661e86c4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 15 Sep 2023 23:49:33 +0200 Subject: [PATCH 101/396] platform/x86: x86-android-tablets: Fix Lenovo Yoga Tablet 2 830F/L vs 1050F/L detection gpio_crystalcove pin 10 is already in input mode and passing GPIOD_IN when requesting the GPIO changes its pull-up/-down settings causing the 830F/L to get misdetected as 1050F/L. Switch to using GPIOD_ASIS when requesting the GPIO to fix the misdetection. Fixes: 4014ae236b1d ("platform/x86: x86-android-tablets: Stop using gpiolib private APIs") Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20230915214933.62595-1-hdegoede@redhat.com --- drivers/platform/x86/x86-android-tablets/lenovo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 5c803cdb5586..c1e68211283f 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -436,7 +436,7 @@ static int __init lenovo_yoga_tab2_830_1050_init_touchscreen(void) /* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */ ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, "yoga_bootstrap", - false, GPIOD_IN, &gpiod); + false, GPIOD_ASIS, &gpiod); if (ret) return ret; From 8d53109dd66f20fe987206258d1371b163f48ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Sep 2023 22:37:59 +0200 Subject: [PATCH 102/396] platform/surface: surface3-wmi: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230917203805.1149595-2-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface3-wmi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c index ca4602bcc7de..c15ed7a12784 100644 --- a/drivers/platform/surface/surface3-wmi.c +++ b/drivers/platform/surface/surface3-wmi.c @@ -226,14 +226,13 @@ static int __init s3_wmi_probe(struct platform_device *pdev) return error; } -static int s3_wmi_remove(struct platform_device *device) +static void s3_wmi_remove(struct platform_device *device) { /* remove the hotplug context from the acpi device */ s3_wmi.touchscreen_adev->hp = NULL; /* reinstall the actual PNPC0C0D LID default handle */ acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle); - return 0; } static int __maybe_unused s3_wmi_resume(struct device *dev) @@ -248,7 +247,7 @@ static struct platform_driver s3_wmi_driver = { .name = "surface3-wmi", .pm = &s3_wmi_pm, }, - .remove = s3_wmi_remove, + .remove_new = s3_wmi_remove, }; static int __init s3_wmi_init(void) From 342d7dce2f12f31b3397043c2ddb6e2c84503b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Sep 2023 22:38:00 +0200 Subject: [PATCH 103/396] platform/surface: acpi-notify: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230917203805.1149595-3-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_acpi_notify.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index 897cdd9c3aae..2c091066b6a1 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -850,7 +850,7 @@ err_enable_events: return status; } -static int san_remove(struct platform_device *pdev) +static void san_remove(struct platform_device *pdev) { acpi_handle san = ACPI_HANDLE(&pdev->dev); @@ -864,8 +864,6 @@ static int san_remove(struct platform_device *pdev) * all delayed works they may have spawned are run to completion. */ flush_workqueue(san_wq); - - return 0; } static const struct acpi_device_id san_match[] = { @@ -876,7 +874,7 @@ MODULE_DEVICE_TABLE(acpi, san_match); static struct platform_driver surface_acpi_notify = { .probe = san_probe, - .remove = san_remove, + .remove_new = san_remove, .driver = { .name = "surface_acpi_notify", .acpi_match_table = san_match, From 1cc995a6e4e81cdef91628a929992f2142836ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Sep 2023 22:38:01 +0200 Subject: [PATCH 104/396] platform/surface: aggregator-cdev: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230917203805.1149595-4-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_cdev.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c index 07f0ed658369..07e065b9159f 100644 --- a/drivers/platform/surface/surface_aggregator_cdev.c +++ b/drivers/platform/surface/surface_aggregator_cdev.c @@ -714,7 +714,7 @@ static int ssam_dbg_device_probe(struct platform_device *pdev) return 0; } -static int ssam_dbg_device_remove(struct platform_device *pdev) +static void ssam_dbg_device_remove(struct platform_device *pdev) { struct ssam_cdev *cdev = platform_get_drvdata(pdev); struct ssam_cdev_client *client; @@ -757,14 +757,13 @@ static int ssam_dbg_device_remove(struct platform_device *pdev) misc_deregister(&cdev->mdev); ssam_cdev_put(cdev); - return 0; } static struct platform_device *ssam_cdev_device; static struct platform_driver ssam_cdev_driver = { .probe = ssam_dbg_device_probe, - .remove = ssam_dbg_device_remove, + .remove_new = ssam_dbg_device_remove, .driver = { .name = SSAM_CDEV_DEVICE_NAME, .probe_type = PROBE_PREFER_ASYNCHRONOUS, From 09416e0f88a96d4783c17cfc29b9c9fd6d0000b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Sep 2023 22:38:02 +0200 Subject: [PATCH 105/396] platform/surface: aggregator-registry: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230917203805.1149595-5-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 0fe5be539652..aeb3feae40ff 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -418,19 +418,18 @@ static int ssam_platform_hub_probe(struct platform_device *pdev) return status; } -static int ssam_platform_hub_remove(struct platform_device *pdev) +static void ssam_platform_hub_remove(struct platform_device *pdev) { const struct software_node **nodes = platform_get_drvdata(pdev); ssam_remove_clients(&pdev->dev); set_secondary_fwnode(&pdev->dev, NULL); software_node_unregister_node_group(nodes); - return 0; } static struct platform_driver ssam_platform_hub_driver = { .probe = ssam_platform_hub_probe, - .remove = ssam_platform_hub_remove, + .remove_new = ssam_platform_hub_remove, .driver = { .name = "surface_aggregator_platform_hub", .acpi_match_table = ssam_platform_hub_match, From 0c845611a20edcd803f9ab7fd2725922008fa178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Sep 2023 22:38:03 +0200 Subject: [PATCH 106/396] platform/surface: dtx: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230917203805.1149595-6-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_dtx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c index 30cbde278c59..2de843b7ea70 100644 --- a/drivers/platform/surface/surface_dtx.c +++ b/drivers/platform/surface/surface_dtx.c @@ -1168,10 +1168,9 @@ static int surface_dtx_platform_probe(struct platform_device *pdev) return 0; } -static int surface_dtx_platform_remove(struct platform_device *pdev) +static void surface_dtx_platform_remove(struct platform_device *pdev) { sdtx_device_destroy(platform_get_drvdata(pdev)); - return 0; } static const struct acpi_device_id surface_dtx_acpi_match[] = { @@ -1182,7 +1181,7 @@ MODULE_DEVICE_TABLE(acpi, surface_dtx_acpi_match); static struct platform_driver surface_dtx_platform_driver = { .probe = surface_dtx_platform_probe, - .remove = surface_dtx_platform_remove, + .remove_new = surface_dtx_platform_remove, .driver = { .name = "surface_dtx_pltf", .acpi_match_table = surface_dtx_acpi_match, From 52f8a4b63b0e289b2b83b55a65993b3a7997836e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Sep 2023 22:38:04 +0200 Subject: [PATCH 107/396] platform/surface: gpe: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230917203805.1149595-7-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_gpe.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c index c219b840d491..62fd4004db31 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -267,20 +267,18 @@ static int surface_gpe_probe(struct platform_device *pdev) return ret; } -static int surface_gpe_remove(struct platform_device *pdev) +static void surface_gpe_remove(struct platform_device *pdev) { struct surface_lid_device *lid = dev_get_drvdata(&pdev->dev); /* restore default behavior without this module */ surface_lid_enable_wakeup(&pdev->dev, false); acpi_disable_gpe(NULL, lid->gpe_number); - - return 0; } static struct platform_driver surface_gpe_driver = { .probe = surface_gpe_probe, - .remove = surface_gpe_remove, + .remove_new = surface_gpe_remove, .driver = { .name = "surface_gpe", .pm = &surface_gpe_pm, From d5e2c23366d8fb86d06a7d8eb949f0dffc41b50c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 17 Sep 2023 22:38:05 +0200 Subject: [PATCH 108/396] platform/surface: hotplug: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230917203805.1149595-8-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_hotplug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c index 7b6d887dccdb..a404f26cfae8 100644 --- a/drivers/platform/surface/surface_hotplug.c +++ b/drivers/platform/surface/surface_hotplug.c @@ -183,7 +183,7 @@ static int shps_setup_irq(struct platform_device *pdev, enum shps_irq_type type) return 0; } -static int surface_hotplug_remove(struct platform_device *pdev) +static void surface_hotplug_remove(struct platform_device *pdev) { struct shps_device *sdev = platform_get_drvdata(pdev); int i; @@ -195,8 +195,6 @@ static int surface_hotplug_remove(struct platform_device *pdev) mutex_destroy(&sdev->lock[i]); } - - return 0; } static int surface_hotplug_probe(struct platform_device *pdev) @@ -261,7 +259,7 @@ MODULE_DEVICE_TABLE(acpi, surface_hotplug_acpi_match); static struct platform_driver surface_hotplug_driver = { .probe = surface_hotplug_probe, - .remove = surface_hotplug_remove, + .remove_new = surface_hotplug_remove, .driver = { .name = "surface_hotplug", .acpi_match_table = surface_hotplug_acpi_match, From e621198016e99cddc097d32cd3b56b15cee27d91 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 18 Sep 2023 16:51:15 +0300 Subject: [PATCH 109/396] platform/x86: think-lmi: Replace kstrdup() + strreplace() with kstrdup_and_replace() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace open coded functionalify of kstrdup_and_replace() with a call. Reviewed-by: Ilpo Järvinen Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230918135116.1248560-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/think-lmi.c | 43 +++++++++++--------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index d329626720df..a5e87aa3395c 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -432,13 +432,11 @@ static ssize_t new_password_store(struct kobject *kobj, if (!tlmi_priv.can_set_bios_password) return -EOPNOTSUPP; - new_pwd = kstrdup(buf, GFP_KERNEL); + /* Strip out CR if one is present, setting password won't work if it is present */ + new_pwd = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_pwd) return -ENOMEM; - /* Strip out CR if one is present, setting password won't work if it is present */ - strip_cr(new_pwd); - /* Use lock in case multiple WMI operations needed */ mutex_lock(&tlmi_mutex); @@ -709,13 +707,11 @@ static ssize_t cert_to_password_store(struct kobject *kobj, if (!setting->signature || !setting->signature[0]) return -EACCES; - passwd = kstrdup(buf, GFP_KERNEL); + /* Strip out CR if one is present */ + passwd = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!passwd) return -ENOMEM; - /* Strip out CR if one is present */ - strip_cr(passwd); - /* Format: 'Password,Signature' */ auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature); if (!auth_str) { @@ -765,11 +761,10 @@ static ssize_t certificate_store(struct kobject *kobj, return ret ?: count; } - new_cert = kstrdup(buf, GFP_KERNEL); + /* Strip out CR if one is present */ + new_cert = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_cert) return -ENOMEM; - /* Strip out CR if one is present */ - strip_cr(new_cert); if (setting->cert_installed) { /* Certificate is installed so this is an update */ @@ -817,13 +812,11 @@ static ssize_t signature_store(struct kobject *kobj, if (!tlmi_priv.certificate_support) return -EOPNOTSUPP; - new_signature = kstrdup(buf, GFP_KERNEL); + /* Strip out CR if one is present */ + new_signature = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_signature) return -ENOMEM; - /* Strip out CR if one is present */ - strip_cr(new_signature); - /* Free any previous signature */ kfree(setting->signature); setting->signature = new_signature; @@ -846,13 +839,11 @@ static ssize_t save_signature_store(struct kobject *kobj, if (!tlmi_priv.certificate_support) return -EOPNOTSUPP; - new_signature = kstrdup(buf, GFP_KERNEL); + /* Strip out CR if one is present */ + new_signature = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_signature) return -ENOMEM; - /* Strip out CR if one is present */ - strip_cr(new_signature); - /* Free any previous signature */ kfree(setting->save_signature); setting->save_signature = new_signature; @@ -992,13 +983,11 @@ static ssize_t current_value_store(struct kobject *kobj, if (tlmi_priv.save_mode == TLMI_SAVE_BULK && tlmi_priv.reboot_required) return -EPERM; - new_setting = kstrdup(buf, GFP_KERNEL); + /* Strip out CR if one is present */ + new_setting = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_setting) return -ENOMEM; - /* Strip out CR if one is present */ - strip_cr(new_setting); - /* Use lock in case multiple WMI operations needed */ mutex_lock(&tlmi_mutex); @@ -1279,13 +1268,11 @@ static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr if (!tlmi_priv.can_debug_cmd) return -EOPNOTSUPP; - new_setting = kstrdup(buf, GFP_KERNEL); + /* Strip out CR if one is present */ + new_setting = kstrdup_and_replace(buf, '\n', '\0', GFP_KERNEL); if (!new_setting) return -ENOMEM; - /* Strip out CR if one is present */ - strip_cr(new_setting); - if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) { auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;", tlmi_priv.pwd_admin->password, From 6cb9c8637c672584d4915559001020237840acba Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 18 Sep 2023 16:51:16 +0300 Subject: [PATCH 110/396] platform/x86: think-lmi: Use strreplace() to replace a character by nul MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can replace p = strchrnul(str, '$OLD'); *p = '\0'; with strreplace(str, '$OLD', '\0'); that does the compatible modification without a need of the temporary variable. Reviewed-by: Ilpo Järvinen Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230918135116.1248560-2-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/think-lmi.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index a5e87aa3395c..4be6f28d4600 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -198,14 +198,6 @@ static struct think_lmi tlmi_priv; static struct class *fw_attr_class; static DEFINE_MUTEX(tlmi_mutex); -/* ------ Utility functions ------------*/ -/* Strip out CR if one is present */ -static void strip_cr(char *str) -{ - char *p = strchrnul(str, '\n'); - *p = '\0'; -} - /* Convert BIOS WMI error string to suitable error code */ static int tlmi_errstr_to_err(const char *errstr) { @@ -411,7 +403,7 @@ static ssize_t current_password_store(struct kobject *kobj, strscpy(setting->password, buf, setting->maxlen); /* Strip out CR if one is present, setting password won't work if it is present */ - strip_cr(setting->password); + strreplace(setting->password, '\n', '\0'); return count; } @@ -921,7 +913,7 @@ static ssize_t display_name_show(struct kobject *kobj, struct kobj_attribute *at static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct tlmi_attr_setting *setting = to_tlmi_attr_setting(kobj); - char *item, *value, *p; + char *item, *value; int ret; ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID); @@ -934,8 +926,7 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a ret = -EINVAL; else { /* On Workstations remove the Options part after the value */ - p = strchrnul(value, ';'); - *p = '\0'; + strreplace(value, ';', '\0'); ret = sysfs_emit(buf, "%s\n", value + 1); } kfree(item); @@ -1540,7 +1531,6 @@ static int tlmi_analyze(void) for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) { struct tlmi_attr_setting *setting; char *item = NULL; - char *p; tlmi_priv.setting[i] = NULL; ret = tlmi_setting(i, &item, LENOVO_BIOS_SETTING_GUID); @@ -1557,8 +1547,7 @@ static int tlmi_analyze(void) strreplace(item, '/', '\\'); /* Remove the value part */ - p = strchrnul(item, ','); - *p = '\0'; + strreplace(item, ',', '\0'); /* Create a setting entry */ setting = kzalloc(sizeof(*setting), GFP_KERNEL); From 7daa3bd4b0b4de1446cd4e6a66bba022101ae9ee Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:53:55 -0700 Subject: [PATCH 111/396] power: supply: axp20x_ac_power: Annotate struct axp20x_ac_power with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct axp20x_ac_power. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Chen-Yu Tsai Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20230922175355.work.006-kees@kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp20x_ac_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c index 19a118633115..e5733cb9e19e 100644 --- a/drivers/power/supply/axp20x_ac_power.c +++ b/drivers/power/supply/axp20x_ac_power.c @@ -45,7 +45,7 @@ struct axp20x_ac_power { struct iio_channel *acin_i; bool has_acin_path_sel; unsigned int num_irqs; - unsigned int irqs[]; + unsigned int irqs[] __counted_by(num_irqs); }; static irqreturn_t axp20x_ac_power_irq(int irq, void *devid) From de1ca06bc0364a58ba0889d97a7a094d87dd5477 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:53:58 -0700 Subject: [PATCH 112/396] power: supply: axp20x_usb_power: Annotate struct axp20x_usb_power with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct axp20x_usb_power. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Chen-Yu Tsai Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20230922175358.work.774-kees@kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp20x_usb_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index bde17406c130..e23308ad4cc7 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -73,7 +73,7 @@ struct axp20x_usb_power { unsigned int old_status; unsigned int online; unsigned int num_irqs; - unsigned int irqs[]; + unsigned int irqs[] __counted_by(num_irqs); }; static bool axp20x_usb_vbus_needs_polling(struct axp20x_usb_power *power) From 43ee22422db545800b8bf2c24ef53d040372fc7a Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Sat, 23 Sep 2023 04:48:06 -0700 Subject: [PATCH 113/396] power: supply: mm8013: Fix error code in mm8013_probe() The value of ret is zero when passed to dev_error_probe(), we are passing zero to dev_err_probe() is a success which is incorrect. Fix this by getting the error code using PTR_ERR(). Fixes: c75f4bf6800b ("power: supply: Introduce MM8013 fuel gauge driver") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202309190838.eu8WS6sz-lkp@intel.com/ Signed-off-by: Harshit Mogalapalli Link: https://lore.kernel.org/r/20230923114807.2829188-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/mm8013.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/mm8013.c b/drivers/power/supply/mm8013.c index ddac40ef9ae5..29fd65fe6545 100644 --- a/drivers/power/supply/mm8013.c +++ b/drivers/power/supply/mm8013.c @@ -273,8 +273,10 @@ static int mm8013_probe(struct i2c_client *client) chip->client = client; chip->regmap = devm_regmap_init_i2c(client, &mm8013_regmap_config); - if (IS_ERR(chip->regmap)) + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); return dev_err_probe(dev, ret, "Couldn't initialize regmap\n"); + } ret = mm8013_checkdevice(chip); if (ret) From 1aa8df90f4569acd36d2c94a9cfe1eee561575d6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:51:47 -0700 Subject: [PATCH 114/396] platform/chrome: wilco_ec: Annotate struct ec_event_queue with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct ec_event_queue. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Benson Leung Cc: Tzung-Bi Shih Cc: Dawei Li Cc: Dmitry Torokhov Cc: Maximilian Luz Cc: "Uwe Kleine-König" Cc: Greg Kroah-Hartman Cc: Jiang Jian Cc: chrome-platform@lists.linux.dev Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20230922175146.work.219-kees@kernel.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/wilco_ec/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/wilco_ec/event.c b/drivers/platform/chrome/wilco_ec/event.c index a40f60bcefb6..f80a7c83cfba 100644 --- a/drivers/platform/chrome/wilco_ec/event.c +++ b/drivers/platform/chrome/wilco_ec/event.c @@ -95,7 +95,7 @@ struct ec_event_queue { int capacity; int head; int tail; - struct ec_event *entries[]; + struct ec_event *entries[] __counted_by(capacity); }; /* Maximum number of events to store in ec_event_queue */ From 87882525e5ddae7ef6f1b1df5e1eda9bcbcd7720 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 17 Sep 2023 11:58:32 +0200 Subject: [PATCH 115/396] clk: renesas: r8a7795: Constify r8a7795_*_clks Make r8a7795_core_clks and r8a7795_mod_clks arrays const and align them with the other clock tables in other *cpg-mssr.c . No functional change. Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230917095832.39007-1-marek.vasut+renesas@mailbox.org Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a7795-cpg-mssr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index ad20b3301ef6..e47d9b1fcc0a 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -51,7 +51,7 @@ enum clk_ids { MOD_CLK_BASE }; -static struct cpg_core_clk r8a7795_core_clks[] __initdata = { +static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { /* External Clock Inputs */ DEF_INPUT("extal", CLK_EXTAL), DEF_INPUT("extalr", CLK_EXTALR), @@ -128,7 +128,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = { DEF_BASE("r", R8A7795_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT), }; -static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { +static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { DEF_MOD("3dge", 112, R8A7795_CLK_ZG), DEF_MOD("fdp1-1", 118, R8A7795_CLK_S0D1), DEF_MOD("fdp1-0", 119, R8A7795_CLK_S0D1), From 55ec81f7517fad09135f65552cea0a3ee84fff30 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:54:21 -0700 Subject: [PATCH 116/396] platform/x86: hp-bioscfg: Annotate struct bios_args with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct bios_args. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Jorge Lopez Cc: Hans de Goede Cc: Mark Gross Cc: Nathan Chancellor Cc: Nick Desaulniers Cc: Tom Rix Cc: platform-driver-x86@vger.kernel.org Cc: llvm@lists.linux.dev Signed-off-by: Kees Cook Reviewed-by: "Gustavo A. R. Silva" Link: https://lore.kernel.org/r/20230922175420.work.701-kees@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c b/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c index dea54f35b8b5..4da99cb7218d 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c +++ b/drivers/platform/x86/hp/hp-bioscfg/biosattr-interface.c @@ -19,7 +19,7 @@ struct bios_args { u32 command; u32 commandtype; u32 datasize; - u8 data[]; + u8 data[] __counted_by(datasize); }; /** From 9cf63f3a33e929f7eca36409914b8c12102b9984 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:54:37 -0700 Subject: [PATCH 117/396] platform/surface: aggregator: Annotate struct ssam_event with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct ssam_event. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Maximilian Luz Cc: platform-driver-x86@vger.kernel.org Signed-off-by: Kees Cook Reviewed-by: "Gustavo A. R. Silva" Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230922175436.work.031-kees@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- include/linux/surface_aggregator/controller.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index cb7980805920..5b67f0f47d80 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -44,7 +44,7 @@ struct ssam_event { u8 command_id; u8 instance_id; u16 length; - u8 data[]; + u8 data[] __counted_by(length); }; /** From 923a77a2e18001f290432b96cb71f68b3423296d Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Mon, 4 Sep 2023 15:55:01 +0800 Subject: [PATCH 118/396] dt-bindings: clock: document Amlogic S4 SoC PLL clock controller Add the S4 PLL clock controller dt-bindings in the S4 SoC family. Signed-off-by: Yu Tu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230904075504.23263-2-yu.tu@amlogic.com Signed-off-by: Jerome Brunet --- .../bindings/clock/amlogic,s4-pll-clkc.yaml | 49 +++++++++++++++++++ .../dt-bindings/clock/amlogic,s4-pll-clkc.h | 43 ++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/amlogic,s4-pll-clkc.yaml create mode 100644 include/dt-bindings/clock/amlogic,s4-pll-clkc.h diff --git a/Documentation/devicetree/bindings/clock/amlogic,s4-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,s4-pll-clkc.yaml new file mode 100644 index 000000000000..d8932ec26ca8 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/amlogic,s4-pll-clkc.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2022-2023 Amlogic, Inc. All rights reserved +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/amlogic,s4-pll-clkc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic S4 PLL Clock Controller + +maintainers: + - Yu Tu + +properties: + compatible: + const: amlogic,s4-pll-clkc + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: xtal + + "#clock-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - "#clock-cells" + +additionalProperties: false + +examples: + - | + clkc_pll: clock-controller@fe008000 { + compatible = "amlogic,s4-pll-clkc"; + reg = <0xfe008000 0x1e8>; + clocks = <&xtal>; + clock-names = "xtal"; + #clock-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/amlogic,s4-pll-clkc.h b/include/dt-bindings/clock/amlogic,s4-pll-clkc.h new file mode 100644 index 000000000000..af9f110f8b62 --- /dev/null +++ b/include/dt-bindings/clock/amlogic,s4-pll-clkc.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (c) 2022-2023 Amlogic, Inc. All rights reserved. + * Author: Yu Tu + */ + +#ifndef _DT_BINDINGS_CLOCK_AMLOGIC_S4_PLL_CLKC_H +#define _DT_BINDINGS_CLOCK_AMLOGIC_S4_PLL_CLKC_H + +#define CLKID_FIXED_PLL_DCO 0 +#define CLKID_FIXED_PLL 1 +#define CLKID_FCLK_DIV2_DIV 2 +#define CLKID_FCLK_DIV2 3 +#define CLKID_FCLK_DIV3_DIV 4 +#define CLKID_FCLK_DIV3 5 +#define CLKID_FCLK_DIV4_DIV 6 +#define CLKID_FCLK_DIV4 7 +#define CLKID_FCLK_DIV5_DIV 8 +#define CLKID_FCLK_DIV5 9 +#define CLKID_FCLK_DIV7_DIV 10 +#define CLKID_FCLK_DIV7 11 +#define CLKID_FCLK_DIV2P5_DIV 12 +#define CLKID_FCLK_DIV2P5 13 +#define CLKID_GP0_PLL_DCO 14 +#define CLKID_GP0_PLL 15 +#define CLKID_HIFI_PLL_DCO 16 +#define CLKID_HIFI_PLL 17 +#define CLKID_HDMI_PLL_DCO 18 +#define CLKID_HDMI_PLL_OD 19 +#define CLKID_HDMI_PLL 20 +#define CLKID_MPLL_50M_DIV 21 +#define CLKID_MPLL_50M 22 +#define CLKID_MPLL_PREDIV 23 +#define CLKID_MPLL0_DIV 24 +#define CLKID_MPLL0 25 +#define CLKID_MPLL1_DIV 26 +#define CLKID_MPLL1 27 +#define CLKID_MPLL2_DIV 28 +#define CLKID_MPLL2 29 +#define CLKID_MPLL3_DIV 30 +#define CLKID_MPLL3 31 + +#endif /* _DT_BINDINGS_CLOCK_AMLOGIC_S4_PLL_CLKC_H */ From 98949499169634263ed4a0bb21e9d9677301c17d Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Mon, 4 Sep 2023 15:55:02 +0800 Subject: [PATCH 119/396] dt-bindings: clock: document Amlogic S4 SoC peripherals clock controller Add the S4 peripherals clock controller dt-bindings in the S4 SoC family. Signed-off-by: Yu Tu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230904075504.23263-3-yu.tu@amlogic.com Signed-off-by: Jerome Brunet --- .../clock/amlogic,s4-peripherals-clkc.yaml | 96 +++++++ .../clock/amlogic,s4-peripherals-clkc.h | 236 ++++++++++++++++++ 2 files changed, 332 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/amlogic,s4-peripherals-clkc.yaml create mode 100644 include/dt-bindings/clock/amlogic,s4-peripherals-clkc.h diff --git a/Documentation/devicetree/bindings/clock/amlogic,s4-peripherals-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,s4-peripherals-clkc.yaml new file mode 100644 index 000000000000..c229e4f0c1d9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/amlogic,s4-peripherals-clkc.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2022-2023 Amlogic, Inc. All rights reserved +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/amlogic,s4-peripherals-clkc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Amlogic S4 Peripherals Clock Controller + +maintainers: + - Yu Tu + +properties: + compatible: + const: amlogic,s4-peripherals-clkc + + reg: + maxItems: 1 + + clocks: + minItems: 14 + items: + - description: input fixed pll div2 + - description: input fixed pll div2p5 + - description: input fixed pll div3 + - description: input fixed pll div4 + - description: input fixed pll div5 + - description: input fixed pll div7 + - description: input hifi pll + - description: input gp0 pll + - description: input mpll0 + - description: input mpll1 + - description: input mpll2 + - description: input mpll3 + - description: input hdmi pll + - description: input oscillator (usually at 24MHz) + - description: input external 32kHz reference (optional) + + clock-names: + minItems: 14 + items: + - const: fclk_div2 + - const: fclk_div2p5 + - const: fclk_div3 + - const: fclk_div4 + - const: fclk_div5 + - const: fclk_div7 + - const: hifi_pll + - const: gp0_pll + - const: mpll0 + - const: mpll1 + - const: mpll2 + - const: mpll3 + - const: hdmi_pll + - const: xtal + - const: ext_32k + + "#clock-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - "#clock-cells" + +additionalProperties: false + +examples: + - | + #include + + clkc_periphs: clock-controller@fe000000 { + compatible = "amlogic,s4-peripherals-clkc"; + reg = <0xfe000000 0x49c>; + clocks = <&clkc_pll 3>, + <&clkc_pll 13>, + <&clkc_pll 5>, + <&clkc_pll 7>, + <&clkc_pll 9>, + <&clkc_pll 11>, + <&clkc_pll 17>, + <&clkc_pll 15>, + <&clkc_pll 25>, + <&clkc_pll 27>, + <&clkc_pll 29>, + <&clkc_pll 31>, + <&clkc_pll 20>, + <&xtal>; + clock-names = "fclk_div2", "fclk_div2p5", "fclk_div3", "fclk_div4", + "fclk_div5", "fclk_div7", "hifi_pll", "gp0_pll", + "mpll0", "mpll1", "mpll2", "mpll3", "hdmi_pll", "xtal"; + #clock-cells = <1>; + }; +... diff --git a/include/dt-bindings/clock/amlogic,s4-peripherals-clkc.h b/include/dt-bindings/clock/amlogic,s4-peripherals-clkc.h new file mode 100644 index 000000000000..861a331963ac --- /dev/null +++ b/include/dt-bindings/clock/amlogic,s4-peripherals-clkc.h @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (c) 2022-2023 Amlogic, Inc. All rights reserved. + * Author: Yu Tu + */ + +#ifndef _DT_BINDINGS_CLOCK_AMLOGIC_S4_PERIPHERALS_CLKC_H +#define _DT_BINDINGS_CLOCK_AMLOGIC_S4_PERIPHERALS_CLKC_H + +#define CLKID_RTC_32K_CLKIN 0 +#define CLKID_RTC_32K_DIV 1 +#define CLKID_RTC_32K_SEL 2 +#define CLKID_RTC_32K_XATL 3 +#define CLKID_RTC 4 +#define CLKID_SYS_CLK_B_SEL 5 +#define CLKID_SYS_CLK_B_DIV 6 +#define CLKID_SYS_CLK_B 7 +#define CLKID_SYS_CLK_A_SEL 8 +#define CLKID_SYS_CLK_A_DIV 9 +#define CLKID_SYS_CLK_A 10 +#define CLKID_SYS 11 +#define CLKID_CECA_32K_CLKIN 12 +#define CLKID_CECA_32K_DIV 13 +#define CLKID_CECA_32K_SEL_PRE 14 +#define CLKID_CECA_32K_SEL 15 +#define CLKID_CECA_32K_CLKOUT 16 +#define CLKID_CECB_32K_CLKIN 17 +#define CLKID_CECB_32K_DIV 18 +#define CLKID_CECB_32K_SEL_PRE 19 +#define CLKID_CECB_32K_SEL 20 +#define CLKID_CECB_32K_CLKOUT 21 +#define CLKID_SC_CLK_SEL 22 +#define CLKID_SC_CLK_DIV 23 +#define CLKID_SC 24 +#define CLKID_12_24M 25 +#define CLKID_12M_CLK_DIV 26 +#define CLKID_12_24M_CLK_SEL 27 +#define CLKID_VID_PLL_DIV 28 +#define CLKID_VID_PLL_SEL 29 +#define CLKID_VID_PLL 30 +#define CLKID_VCLK_SEL 31 +#define CLKID_VCLK2_SEL 32 +#define CLKID_VCLK_INPUT 33 +#define CLKID_VCLK2_INPUT 34 +#define CLKID_VCLK_DIV 35 +#define CLKID_VCLK2_DIV 36 +#define CLKID_VCLK 37 +#define CLKID_VCLK2 38 +#define CLKID_VCLK_DIV1 39 +#define CLKID_VCLK_DIV2_EN 40 +#define CLKID_VCLK_DIV4_EN 41 +#define CLKID_VCLK_DIV6_EN 42 +#define CLKID_VCLK_DIV12_EN 43 +#define CLKID_VCLK2_DIV1 44 +#define CLKID_VCLK2_DIV2_EN 45 +#define CLKID_VCLK2_DIV4_EN 46 +#define CLKID_VCLK2_DIV6_EN 47 +#define CLKID_VCLK2_DIV12_EN 48 +#define CLKID_VCLK_DIV2 49 +#define CLKID_VCLK_DIV4 50 +#define CLKID_VCLK_DIV6 51 +#define CLKID_VCLK_DIV12 52 +#define CLKID_VCLK2_DIV2 53 +#define CLKID_VCLK2_DIV4 54 +#define CLKID_VCLK2_DIV6 55 +#define CLKID_VCLK2_DIV12 56 +#define CLKID_CTS_ENCI_SEL 57 +#define CLKID_CTS_ENCP_SEL 58 +#define CLKID_CTS_VDAC_SEL 59 +#define CLKID_HDMI_TX_SEL 60 +#define CLKID_CTS_ENCI 61 +#define CLKID_CTS_ENCP 62 +#define CLKID_CTS_VDAC 63 +#define CLKID_HDMI_TX 64 +#define CLKID_HDMI_SEL 65 +#define CLKID_HDMI_DIV 66 +#define CLKID_HDMI 67 +#define CLKID_TS_CLK_DIV 68 +#define CLKID_TS 69 +#define CLKID_MALI_0_SEL 70 +#define CLKID_MALI_0_DIV 71 +#define CLKID_MALI_0 72 +#define CLKID_MALI_1_SEL 73 +#define CLKID_MALI_1_DIV 74 +#define CLKID_MALI_1 75 +#define CLKID_MALI_SEL 76 +#define CLKID_VDEC_P0_SEL 77 +#define CLKID_VDEC_P0_DIV 78 +#define CLKID_VDEC_P0 79 +#define CLKID_VDEC_P1_SEL 80 +#define CLKID_VDEC_P1_DIV 81 +#define CLKID_VDEC_P1 82 +#define CLKID_VDEC_SEL 83 +#define CLKID_HEVCF_P0_SEL 84 +#define CLKID_HEVCF_P0_DIV 85 +#define CLKID_HEVCF_P0 86 +#define CLKID_HEVCF_P1_SEL 87 +#define CLKID_HEVCF_P1_DIV 88 +#define CLKID_HEVCF_P1 89 +#define CLKID_HEVCF_SEL 90 +#define CLKID_VPU_0_SEL 91 +#define CLKID_VPU_0_DIV 92 +#define CLKID_VPU_0 93 +#define CLKID_VPU_1_SEL 94 +#define CLKID_VPU_1_DIV 95 +#define CLKID_VPU_1 96 +#define CLKID_VPU 97 +#define CLKID_VPU_CLKB_TMP_SEL 98 +#define CLKID_VPU_CLKB_TMP_DIV 99 +#define CLKID_VPU_CLKB_TMP 100 +#define CLKID_VPU_CLKB_DIV 101 +#define CLKID_VPU_CLKB 102 +#define CLKID_VPU_CLKC_P0_SEL 103 +#define CLKID_VPU_CLKC_P0_DIV 104 +#define CLKID_VPU_CLKC_P0 105 +#define CLKID_VPU_CLKC_P1_SEL 106 +#define CLKID_VPU_CLKC_P1_DIV 107 +#define CLKID_VPU_CLKC_P1 108 +#define CLKID_VPU_CLKC_SEL 109 +#define CLKID_VAPB_0_SEL 110 +#define CLKID_VAPB_0_DIV 111 +#define CLKID_VAPB_0 112 +#define CLKID_VAPB_1_SEL 113 +#define CLKID_VAPB_1_DIV 114 +#define CLKID_VAPB_1 115 +#define CLKID_VAPB 116 +#define CLKID_GE2D 117 +#define CLKID_VDIN_MEAS_SEL 118 +#define CLKID_VDIN_MEAS_DIV 119 +#define CLKID_VDIN_MEAS 120 +#define CLKID_SD_EMMC_C_CLK_SEL 121 +#define CLKID_SD_EMMC_C_CLK_DIV 122 +#define CLKID_SD_EMMC_C 123 +#define CLKID_SD_EMMC_A_CLK_SEL 124 +#define CLKID_SD_EMMC_A_CLK_DIV 125 +#define CLKID_SD_EMMC_A 126 +#define CLKID_SD_EMMC_B_CLK_SEL 127 +#define CLKID_SD_EMMC_B_CLK_DIV 128 +#define CLKID_SD_EMMC_B 129 +#define CLKID_SPICC0_SEL 130 +#define CLKID_SPICC0_DIV 131 +#define CLKID_SPICC0_EN 132 +#define CLKID_PWM_A_SEL 133 +#define CLKID_PWM_A_DIV 134 +#define CLKID_PWM_A 135 +#define CLKID_PWM_B_SEL 136 +#define CLKID_PWM_B_DIV 137 +#define CLKID_PWM_B 138 +#define CLKID_PWM_C_SEL 139 +#define CLKID_PWM_C_DIV 140 +#define CLKID_PWM_C 141 +#define CLKID_PWM_D_SEL 142 +#define CLKID_PWM_D_DIV 143 +#define CLKID_PWM_D 144 +#define CLKID_PWM_E_SEL 145 +#define CLKID_PWM_E_DIV 146 +#define CLKID_PWM_E 147 +#define CLKID_PWM_F_SEL 148 +#define CLKID_PWM_F_DIV 149 +#define CLKID_PWM_F 150 +#define CLKID_PWM_G_SEL 151 +#define CLKID_PWM_G_DIV 152 +#define CLKID_PWM_G 153 +#define CLKID_PWM_H_SEL 154 +#define CLKID_PWM_H_DIV 155 +#define CLKID_PWM_H 156 +#define CLKID_PWM_I_SEL 157 +#define CLKID_PWM_I_DIV 158 +#define CLKID_PWM_I 159 +#define CLKID_PWM_J_SEL 160 +#define CLKID_PWM_J_DIV 161 +#define CLKID_PWM_J 162 +#define CLKID_SARADC_SEL 163 +#define CLKID_SARADC_DIV 164 +#define CLKID_SARADC 165 +#define CLKID_GEN_SEL 166 +#define CLKID_GEN_DIV 167 +#define CLKID_GEN 168 +#define CLKID_DDR 169 +#define CLKID_DOS 170 +#define CLKID_ETHPHY 171 +#define CLKID_MALI 172 +#define CLKID_AOCPU 173 +#define CLKID_AUCPU 174 +#define CLKID_CEC 175 +#define CLKID_SDEMMC_A 176 +#define CLKID_SDEMMC_B 177 +#define CLKID_NAND 178 +#define CLKID_SMARTCARD 179 +#define CLKID_ACODEC 180 +#define CLKID_SPIFC 181 +#define CLKID_MSR 182 +#define CLKID_IR_CTRL 183 +#define CLKID_AUDIO 184 +#define CLKID_ETH 185 +#define CLKID_UART_A 186 +#define CLKID_UART_B 187 +#define CLKID_UART_C 188 +#define CLKID_UART_D 189 +#define CLKID_UART_E 190 +#define CLKID_AIFIFO 191 +#define CLKID_TS_DDR 192 +#define CLKID_TS_PLL 193 +#define CLKID_G2D 194 +#define CLKID_SPICC0 195 +#define CLKID_SPICC1 196 +#define CLKID_USB 197 +#define CLKID_I2C_M_A 198 +#define CLKID_I2C_M_B 199 +#define CLKID_I2C_M_C 200 +#define CLKID_I2C_M_D 201 +#define CLKID_I2C_M_E 202 +#define CLKID_HDMITX_APB 203 +#define CLKID_I2C_S_A 204 +#define CLKID_USB1_TO_DDR 205 +#define CLKID_HDCP22 206 +#define CLKID_MMC_APB 207 +#define CLKID_RSA 208 +#define CLKID_CPU_DEBUG 209 +#define CLKID_VPU_INTR 210 +#define CLKID_DEMOD 211 +#define CLKID_SAR_ADC 212 +#define CLKID_GIC 213 +#define CLKID_PWM_AB 214 +#define CLKID_PWM_CD 215 +#define CLKID_PWM_EF 216 +#define CLKID_PWM_GH 217 +#define CLKID_PWM_IJ 218 +#define CLKID_HDCP22_ESMCLK_SEL 219 +#define CLKID_HDCP22_ESMCLK_DIV 220 +#define CLKID_HDCP22_ESMCLK 221 +#define CLKID_HDCP22_SKPCLK_SEL 222 +#define CLKID_HDCP22_SKPCLK_DIV 223 +#define CLKID_HDCP22_SKPCLK 224 + +#endif /* _DT_BINDINGS_CLOCK_AMLOGIC_S4_PERIPHERALS_CLKC_H */ From e787c9c55edadb5d9d6c75ce5080dd3c64bd996b Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Mon, 4 Sep 2023 15:55:03 +0800 Subject: [PATCH 120/396] clk: meson: S4: add support for Amlogic S4 SoC PLL clock driver Add the S4 PLL clock controller driver in the S4 SoC family. Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20230904075504.23263-4-yu.tu@amlogic.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 12 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/s4-pll.c | 867 +++++++++++++++++++++++++++++++++++++ drivers/clk/meson/s4-pll.h | 38 ++ 4 files changed, 918 insertions(+) create mode 100644 drivers/clk/meson/s4-pll.c create mode 100644 drivers/clk/meson/s4-pll.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 135da8f2d0b1..e90982d77598 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -144,4 +144,16 @@ config COMMON_CLK_G12A help Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 devices, aka g12a. Say Y if you want peripherals to work. + +config COMMON_CLK_S4_PLL + tristate "S4 SoC PLL clock controllers support" + depends on ARM64 + default y + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_REGMAP + help + Support for the PLL clock controller on Amlogic S805X2 and S905Y4 devices, + AKA S4. Say Y if you want the board to work, because PLLs are the parent of + most peripherals. endmenu diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index cd961cc4f4db..612cee923890 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o +obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o diff --git a/drivers/clk/meson/s4-pll.c b/drivers/clk/meson/s4-pll.c new file mode 100644 index 000000000000..8dfaeccaadc2 --- /dev/null +++ b/drivers/clk/meson/s4-pll.c @@ -0,0 +1,867 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Amlogic S4 PLL Clock Controller Driver + * + * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved + * Author: Yu Tu + */ + +#include +#include +#include + +#include "clk-mpll.h" +#include "clk-pll.h" +#include "clk-regmap.h" +#include "s4-pll.h" +#include "meson-clkc-utils.h" +#include + +static DEFINE_SPINLOCK(meson_clk_lock); + +/* + * These clock are a fixed value (fixed_pll is 2GHz) that is initialized by ROMcode. + * The chip was changed fixed pll for security reasons. Fixed PLL registers are not writable + * in the kernel phase. Write of fixed PLL-related register will cause the system to crash. + * Meanwhile, these clock won't ever change at runtime. + * For the above reasons, we can only use ro_ops for fixed PLL related clocks. + */ +static struct clk_regmap s4_fixed_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_FIXPLL_CTRL0, + .shift = 29, + .width = 1, + }, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll_dco", + .ops = &meson_clk_pll_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fixed_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_FIXPLL_CTRL0, + .shift = 16, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "fixed_pll", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents = 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_fixed_factor s4_fclk_div2_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div2_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div3_div = { + .mult = 1, + .div = 3, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 20, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div3", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div3_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div4_div = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div4 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 21, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div4", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div4_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div5_div = { + .mult = 1, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 22, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div5", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div5_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div7_div = { + .mult = 1, + .div = 7, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div7 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div7", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div7_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div2p5_div = { + .mult = 2, + .div = 5, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fixed_pll.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_fclk_div2p5 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_FIXPLL_CTRL1, + .bit_idx = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "fclk_div2p5", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fclk_div2p5_div.hw + }, + .num_parents = 1, + }, +}; + +static const struct pll_mult_range s4_gp0_pll_mult_range = { + .min = 125, + .max = 250, +}; + +/* + * Internal gp0 pll emulation configuration parameters + */ +static const struct reg_sequence s4_gp0_init_regs[] = { + { .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 }, + { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 }, + { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 }, + { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 }, + { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x39272000 }, + { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x56540000 } +}; + +static struct clk_regmap s4_gp0_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_GP0PLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &s4_gp0_pll_mult_range, + .init_regs = s4_gp0_init_regs, + .init_count = ARRAY_SIZE(s4_gp0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_gp0_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_GP0PLL_CTRL0, + .shift = 16, + .width = 3, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "gp0_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_gp0_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * Internal hifi pll emulation configuration parameters + */ +static const struct reg_sequence s4_hifi_init_regs[] = { + { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00010e56 }, + { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 }, + { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 }, + { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 }, + { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x39272000 }, + { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 } +}; + +static struct clk_regmap s4_hifi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_HIFIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &s4_gp0_pll_mult_range, + .init_regs = s4_hifi_init_regs, + .init_count = ARRAY_SIZE(s4_hifi_init_regs), + .flags = CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_hifi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_HIFIPLL_CTRL0, + .shift = 16, + .width = 2, + .flags = (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init = &(struct clk_init_data){ + .name = "hifi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hifi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 28, + .width = 1, + }, + .m = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 0, + .width = 8, + }, + .n = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 10, + .width = 5, + }, + .l = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 31, + .width = 1, + }, + .rst = { + .reg_off = ANACTRL_HDMIPLL_CTRL0, + .shift = 29, + .width = 1, + }, + .range = &s4_gp0_pll_mult_range, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_dco", + .ops = &meson_clk_pll_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_hdmi_pll_od = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_HDMIPLL_CTRL0, + .shift = 16, + .width = 4, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll_od", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdmi_pll_dco.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_pll = { + .data = &(struct clk_regmap_div_data){ + .offset = ANACTRL_HDMIPLL_CTRL0, + .shift = 20, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pll", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdmi_pll_od.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_mpll_50m_div = { + .mult = 1, + .div = 80, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m_div", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll_50m = { + .data = &(struct clk_regmap_mux_data){ + .offset = ANACTRL_FIXPLL_CTRL3, + .mask = 0x1, + .shift = 5, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll_50m", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &s4_mpll_50m_div.hw }, + }, + .num_parents = 2, + }, +}; + +static struct clk_fixed_factor s4_mpll_prediv = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "mpll_prediv", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents = 1, + }, +}; + +static const struct reg_sequence s4_mpll0_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 } +}; + +static struct clk_regmap s4_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = ANACTRL_MPLL_CTRL1, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = ANACTRL_MPLL_CTRL1, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = ANACTRL_MPLL_CTRL1, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = ANACTRL_MPLL_CTRL1, + .shift = 29, + .width = 1, + }, + .lock = &meson_clk_lock, + .init_regs = s4_mpll0_init_regs, + .init_count = ARRAY_SIZE(s4_mpll0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_MPLL_CTRL1, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_mpll0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll1_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL4, .def = 0x40000033 } +}; + +static struct clk_regmap s4_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = ANACTRL_MPLL_CTRL3, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = ANACTRL_MPLL_CTRL3, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = ANACTRL_MPLL_CTRL3, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = ANACTRL_MPLL_CTRL3, + .shift = 29, + .width = 1, + }, + .lock = &meson_clk_lock, + .init_regs = s4_mpll1_init_regs, + .init_count = ARRAY_SIZE(s4_mpll1_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_MPLL_CTRL3, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_mpll1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll2_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 } +}; + +static struct clk_regmap s4_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = ANACTRL_MPLL_CTRL5, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = ANACTRL_MPLL_CTRL5, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = ANACTRL_MPLL_CTRL5, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = ANACTRL_MPLL_CTRL5, + .shift = 29, + .width = 1, + }, + .lock = &meson_clk_lock, + .init_regs = s4_mpll2_init_regs, + .init_count = ARRAY_SIZE(s4_mpll2_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_MPLL_CTRL5, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_mpll2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll3_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 } +}; + +static struct clk_regmap s4_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = ANACTRL_MPLL_CTRL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = ANACTRL_MPLL_CTRL7, + .shift = 30, + .width = 1, + }, + .n2 = { + .reg_off = ANACTRL_MPLL_CTRL7, + .shift = 20, + .width = 9, + }, + .ssen = { + .reg_off = ANACTRL_MPLL_CTRL7, + .shift = 29, + .width = 1, + }, + .lock = &meson_clk_lock, + .init_regs = s4_mpll3_init_regs, + .init_count = ARRAY_SIZE(s4_mpll3_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_mpll3 = { + .data = &(struct clk_regmap_gate_data){ + .offset = ANACTRL_MPLL_CTRL7, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_mpll3_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Array of all clocks provided by this provider */ +static struct clk_hw *s4_pll_hw_clks[] = { + [CLKID_FIXED_PLL_DCO] = &s4_fixed_pll_dco.hw, + [CLKID_FIXED_PLL] = &s4_fixed_pll.hw, + [CLKID_FCLK_DIV2_DIV] = &s4_fclk_div2_div.hw, + [CLKID_FCLK_DIV2] = &s4_fclk_div2.hw, + [CLKID_FCLK_DIV3_DIV] = &s4_fclk_div3_div.hw, + [CLKID_FCLK_DIV3] = &s4_fclk_div3.hw, + [CLKID_FCLK_DIV4_DIV] = &s4_fclk_div4_div.hw, + [CLKID_FCLK_DIV4] = &s4_fclk_div4.hw, + [CLKID_FCLK_DIV5_DIV] = &s4_fclk_div5_div.hw, + [CLKID_FCLK_DIV5] = &s4_fclk_div5.hw, + [CLKID_FCLK_DIV7_DIV] = &s4_fclk_div7_div.hw, + [CLKID_FCLK_DIV7] = &s4_fclk_div7.hw, + [CLKID_FCLK_DIV2P5_DIV] = &s4_fclk_div2p5_div.hw, + [CLKID_FCLK_DIV2P5] = &s4_fclk_div2p5.hw, + [CLKID_GP0_PLL_DCO] = &s4_gp0_pll_dco.hw, + [CLKID_GP0_PLL] = &s4_gp0_pll.hw, + [CLKID_HIFI_PLL_DCO] = &s4_hifi_pll_dco.hw, + [CLKID_HIFI_PLL] = &s4_hifi_pll.hw, + [CLKID_HDMI_PLL_DCO] = &s4_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] = &s4_hdmi_pll_od.hw, + [CLKID_HDMI_PLL] = &s4_hdmi_pll.hw, + [CLKID_MPLL_50M_DIV] = &s4_mpll_50m_div.hw, + [CLKID_MPLL_50M] = &s4_mpll_50m.hw, + [CLKID_MPLL_PREDIV] = &s4_mpll_prediv.hw, + [CLKID_MPLL0_DIV] = &s4_mpll0_div.hw, + [CLKID_MPLL0] = &s4_mpll0.hw, + [CLKID_MPLL1_DIV] = &s4_mpll1_div.hw, + [CLKID_MPLL1] = &s4_mpll1.hw, + [CLKID_MPLL2_DIV] = &s4_mpll2_div.hw, + [CLKID_MPLL2] = &s4_mpll2.hw, + [CLKID_MPLL3_DIV] = &s4_mpll3_div.hw, + [CLKID_MPLL3] = &s4_mpll3.hw, +}; + +static struct clk_regmap *const s4_pll_clk_regmaps[] = { + &s4_fixed_pll_dco, + &s4_fixed_pll, + &s4_fclk_div2, + &s4_fclk_div3, + &s4_fclk_div4, + &s4_fclk_div5, + &s4_fclk_div7, + &s4_fclk_div2p5, + &s4_gp0_pll_dco, + &s4_gp0_pll, + &s4_hifi_pll_dco, + &s4_hifi_pll, + &s4_hdmi_pll_dco, + &s4_hdmi_pll_od, + &s4_hdmi_pll, + &s4_mpll_50m, + &s4_mpll0_div, + &s4_mpll0, + &s4_mpll1_div, + &s4_mpll1, + &s4_mpll2_div, + &s4_mpll2, + &s4_mpll3_div, + &s4_mpll3, +}; + +static const struct reg_sequence s4_init_regs[] = { + { .reg = ANACTRL_MPLL_CTRL0, .def = 0x00000543 }, +}; + +static struct regmap_config clkc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static struct meson_clk_hw_data s4_pll_clks = { + .hws = s4_pll_hw_clks, + .num = ARRAY_SIZE(s4_pll_hw_clks), +}; + +static int meson_s4_pll_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *regmap; + void __iomem *base; + int ret, i; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), + "can't ioremap resource\n"); + + regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "can't init regmap mmio region\n"); + + ret = regmap_multi_reg_write(regmap, s4_init_regs, ARRAY_SIZE(s4_init_regs)); + if (ret) + return dev_err_probe(dev, ret, + "Failed to init registers\n"); + + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(s4_pll_clk_regmaps); i++) + s4_pll_clk_regmaps[i]->map = regmap; + + /* Register clocks */ + for (i = 0; i < s4_pll_clks.num; i++) { + /* array might be sparse */ + if (!s4_pll_clks.hws[i]) + continue; + + ret = devm_clk_hw_register(dev, s4_pll_clks.hws[i]); + if (ret) + return dev_err_probe(dev, ret, + "clock[%d] registration failed\n", i); + } + + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, + &s4_pll_clks); +} + +static const struct of_device_id clkc_match_table[] = { + { + .compatible = "amlogic,s4-pll-clkc", + }, + {} +}; + +static struct platform_driver s4_driver = { + .probe = meson_s4_pll_probe, + .driver = { + .name = "s4-pll-clkc", + .of_match_table = clkc_match_table, + }, +}; + +module_platform_driver(s4_driver); +MODULE_AUTHOR("Yu Tu "); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/s4-pll.h b/drivers/clk/meson/s4-pll.h new file mode 100644 index 000000000000..ff7d58302f2a --- /dev/null +++ b/drivers/clk/meson/s4-pll.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved + * Author: Yu Tu + */ + +#ifndef __MESON_S4_PLL_H__ +#define __MESON_S4_PLL_H__ + +#define ANACTRL_FIXPLL_CTRL0 0x040 +#define ANACTRL_FIXPLL_CTRL1 0x044 +#define ANACTRL_FIXPLL_CTRL3 0x04c +#define ANACTRL_GP0PLL_CTRL0 0x080 +#define ANACTRL_GP0PLL_CTRL1 0x084 +#define ANACTRL_GP0PLL_CTRL2 0x088 +#define ANACTRL_GP0PLL_CTRL3 0x08c +#define ANACTRL_GP0PLL_CTRL4 0x090 +#define ANACTRL_GP0PLL_CTRL5 0x094 +#define ANACTRL_GP0PLL_CTRL6 0x098 +#define ANACTRL_HIFIPLL_CTRL0 0x100 +#define ANACTRL_HIFIPLL_CTRL1 0x104 +#define ANACTRL_HIFIPLL_CTRL2 0x108 +#define ANACTRL_HIFIPLL_CTRL3 0x10c +#define ANACTRL_HIFIPLL_CTRL4 0x110 +#define ANACTRL_HIFIPLL_CTRL5 0x114 +#define ANACTRL_HIFIPLL_CTRL6 0x118 +#define ANACTRL_MPLL_CTRL0 0x180 +#define ANACTRL_MPLL_CTRL1 0x184 +#define ANACTRL_MPLL_CTRL2 0x188 +#define ANACTRL_MPLL_CTRL3 0x18c +#define ANACTRL_MPLL_CTRL4 0x190 +#define ANACTRL_MPLL_CTRL5 0x194 +#define ANACTRL_MPLL_CTRL6 0x198 +#define ANACTRL_MPLL_CTRL7 0x19c +#define ANACTRL_MPLL_CTRL8 0x1a0 +#define ANACTRL_HDMIPLL_CTRL0 0x1c0 + +#endif /* __MESON_S4_PLL_H__ */ From 57b55c76aaf1ba50ecc6dcee5cd6843dc4d85239 Mon Sep 17 00:00:00 2001 From: Yu Tu Date: Mon, 4 Sep 2023 15:55:04 +0800 Subject: [PATCH 121/396] clk: meson: S4: add support for Amlogic S4 SoC peripheral clock controller Add the peripherals clock controller driver in the S4 SoC family. [jbrunet: remove extra new line at end of s4-peripherals.h] Signed-off-by: Yu Tu Link: https://lore.kernel.org/r/20230904075504.23263-5-yu.tu@amlogic.com Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 11 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/s4-peripherals.c | 3813 ++++++++++++++++++++++++++++ drivers/clk/meson/s4-peripherals.h | 56 + 4 files changed, 3881 insertions(+) create mode 100644 drivers/clk/meson/s4-peripherals.c create mode 100644 drivers/clk/meson/s4-peripherals.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index e90982d77598..c5303e4c1604 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -156,4 +156,15 @@ config COMMON_CLK_S4_PLL Support for the PLL clock controller on Amlogic S805X2 and S905Y4 devices, AKA S4. Say Y if you want the board to work, because PLLs are the parent of most peripherals. + +config COMMON_CLK_S4_PERIPHERALS + tristate "S4 SoC peripherals clock controllers support" + depends on ARM64 + default y + select COMMON_CLK_MESON_REGMAP + select COMMON_CLK_MESON_DUALDIV + select COMMON_CLK_MESON_VID_PLL_DIV + help + Support for the peripherals clock controller on Amlogic S805X2 and S905Y4 + devices, AKA S4. Say Y if you want S4 peripherals clock controller to work. endmenu diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 612cee923890..9ee4b954c896 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o +obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c new file mode 100644 index 000000000000..6c35de3d536f --- /dev/null +++ b/drivers/clk/meson/s4-peripherals.c @@ -0,0 +1,3813 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Amlogic S4 Peripherals Clock Controller Driver + * + * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved + * Author: Yu Tu + */ + +#include +#include +#include + +#include "clk-regmap.h" +#include "vid-pll-div.h" +#include "clk-dualdiv.h" +#include "s4-peripherals.h" +#include "meson-clkc-utils.h" +#include + +static struct clk_regmap s4_rtc_32k_by_oscin_clkin = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k_by_oscin_clkin", + .ops = &clk_regmap_gate_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static const struct meson_clk_dualdiv_param s4_32k_div_table[] = { + { + .dual = 1, + .n1 = 733, + .m1 = 8, + .n2 = 732, + .m2 = 11, + }, + {} +}; + +static struct clk_regmap s4_rtc_32k_by_oscin_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .shift = 28, + .width = 1, + }, + .table = s4_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_32k_by_oscin_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_rtc_32k_by_oscin_clkin.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_rtc_32k_by_oscin_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_32k_by_oscin_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_rtc_32k_by_oscin_div.hw, + &s4_rtc_32k_by_oscin_clkin.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_rtc_32k_by_oscin = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_RTC_BY_OSCIN_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "rtc_32k_by_oscin", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_rtc_32k_by_oscin_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_rtc_clk = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_RTC_CTRL, + .mask = 0x3, + .shift = 0, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "rtc_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_rtc_32k_by_oscin.hw, + &s4_rtc_32k_by_oscin_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* The index 5 is AXI_CLK, which is dedicated to AXI. So skip it. */ +static u32 mux_table_sys_ab_clk_sel[] = { 0, 1, 2, 3, 4, 6, 7 }; +static const struct clk_parent_data sys_ab_clk_parent_data[] = { + { .fw_name = "xtal" }, + { .fw_name = "fclk_div2" }, + { .fw_name = "fclk_div3" }, + { .fw_name = "fclk_div4" }, + { .fw_name = "fclk_div5" }, + { .fw_name = "fclk_div7" }, + { .hw = &s4_rtc_clk.hw } +}; + +/* + * This clock is initialized by ROMcode. + * The chip was changed SYS CLK for security reasons. SYS CLK registers are not writable + * in the kernel phase. Write of SYS related register will cause the system to crash. + * Meanwhile, these clock won't ever change at runtime. + * For the above reasons, we can only use ro_ops for SYS related clocks. + */ +static struct clk_regmap s4_sysclk_b_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .mask = 0x7, + .shift = 26, + .table = mux_table_sys_ab_clk_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "sysclk_b_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = sys_ab_clk_parent_data, + .num_parents = ARRAY_SIZE(sys_ab_clk_parent_data), + }, +}; + +static struct clk_regmap s4_sysclk_b_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .shift = 16, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "sysclk_b_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_b_sel.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_sysclk_b = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .bit_idx = 29, + }, + .hw.init = &(struct clk_init_data) { + .name = "sysclk_b", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_b_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_sysclk_a_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .mask = 0x7, + .shift = 10, + .table = mux_table_sys_ab_clk_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "sysclk_a_sel", + .ops = &clk_regmap_mux_ro_ops, + .parent_data = sys_ab_clk_parent_data, + .num_parents = ARRAY_SIZE(sys_ab_clk_parent_data), + }, +}; + +static struct clk_regmap s4_sysclk_a_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .shift = 0, + .width = 10, + }, + .hw.init = &(struct clk_init_data){ + .name = "sysclk_a_div", + .ops = &clk_regmap_divider_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_a_sel.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_sysclk_a = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .bit_idx = 13, + }, + .hw.init = &(struct clk_init_data) { + .name = "sysclk_a", + .ops = &clk_regmap_gate_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_a_div.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_sys_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SYS_CLK_CTRL0, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "sys_clk", + .ops = &clk_regmap_mux_ro_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sysclk_a.hw, + &s4_sysclk_b.hw + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap s4_ceca_32k_clkin = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CECA_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "ceca_32k_clkin", + .ops = &clk_regmap_gate_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_ceca_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CLKCTRL_CECA_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CLKCTRL_CECA_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CLKCTRL_CECA_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CLKCTRL_CECA_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CLKCTRL_CECA_CTRL0, + .shift = 28, + .width = 1, + }, + .table = s4_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ceca_32k_clkin.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_ceca_32k_sel_pre = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CECA_CTRL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_sel_pre", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ceca_32k_div.hw, + &s4_ceca_32k_clkin.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_ceca_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CECA_CTRL1, + .mask = 0x1, + .shift = 31, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ceca_32k_sel_pre.hw, + &s4_rtc_clk.hw + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap s4_ceca_32k_clkout = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CECA_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "ceca_32k_clkout", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ceca_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cecb_32k_clkin = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CECB_CTRL0, + .bit_idx = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "cecb_32k_clkin", + .ops = &clk_regmap_gate_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_cecb_32k_div = { + .data = &(struct meson_clk_dualdiv_data){ + .n1 = { + .reg_off = CLKCTRL_CECB_CTRL0, + .shift = 0, + .width = 12, + }, + .n2 = { + .reg_off = CLKCTRL_CECB_CTRL0, + .shift = 12, + .width = 12, + }, + .m1 = { + .reg_off = CLKCTRL_CECB_CTRL1, + .shift = 0, + .width = 12, + }, + .m2 = { + .reg_off = CLKCTRL_CECB_CTRL1, + .shift = 12, + .width = 12, + }, + .dual = { + .reg_off = CLKCTRL_CECB_CTRL0, + .shift = 28, + .width = 1, + }, + .table = s4_32k_div_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_div", + .ops = &meson_clk_dualdiv_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cecb_32k_clkin.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_cecb_32k_sel_pre = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CECB_CTRL1, + .mask = 0x1, + .shift = 24, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_sel_pre", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cecb_32k_div.hw, + &s4_cecb_32k_clkin.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cecb_32k_sel = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_CECB_CTRL1, + .mask = 0x1, + .shift = 31, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cecb_32k_sel_pre.hw, + &s4_rtc_clk.hw + }, + .num_parents = 2, + }, +}; + +static struct clk_regmap s4_cecb_32k_clkout = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CECB_CTRL0, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data){ + .name = "cecb_32k_clkout", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cecb_32k_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_sc_parent_data[] = { + { .fw_name = "fclk_div4" }, + { .fw_name = "fclk_div3" }, + { .fw_name = "fclk_div5" }, + { .fw_name = "xtal", } +}; + +static struct clk_regmap s4_sc_clk_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SC_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sc_clk_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_sc_parent_data, + .num_parents = ARRAY_SIZE(s4_sc_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sc_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SC_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "sc_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sc_clk_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sc_clk_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "sc_clk_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sc_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_12_24M_clk_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_CLK12_24_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "12_24m_gate", + .ops = &clk_regmap_gate_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", } + }, + .num_parents = 1, + }, +}; + +static struct clk_fixed_factor s4_12M_clk_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "12M", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_12_24M_clk_gate.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_12_24M_clk = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_CLK12_24_CTRL, + .mask = 0x1, + .shift = 10, + }, + .hw.init = &(struct clk_init_data) { + .name = "12_24m", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_12_24M_clk_gate.hw, + &s4_12M_clk_div.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* Video Clocks */ +static struct clk_regmap s4_vid_pll_div = { + .data = &(struct meson_vid_pll_div_data){ + .val = { + .reg_off = CLKCTRL_VID_PLL_CLK_DIV, + .shift = 0, + .width = 15, + }, + .sel = { + .reg_off = CLKCTRL_VID_PLL_CLK_DIV, + .shift = 16, + .width = 2, + }, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll_div", + /* + * TODO meson_vid_pll_div_ro_ops to meson_vid_pll_div_ops + */ + .ops = &meson_vid_pll_div_ro_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "hdmi_pll", } + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vid_pll_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VID_PLL_CLK_DIV, + .mask = 0x1, + .shift = 18, + }, + .hw.init = &(struct clk_init_data){ + .name = "vid_pll_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .hw = &s4_vid_pll_div.hw }, + { .fw_name = "hdmi_pll", } + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vid_pll = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_PLL_CLK_DIV, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vid_pll", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vid_pll_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_vclk_parent_data[] = { + { .hw = &s4_vid_pll.hw }, + { .fw_name = "gp0_pll", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "mpll1", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, +}; + +static struct clk_regmap s4_vclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vclk_parent_data, + .num_parents = ARRAY_SIZE(s4_vclk_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vclk2_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .mask = 0x7, + .shift = 16, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vclk_parent_data, + .num_parents = ARRAY_SIZE(s4_vclk_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vclk_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_input = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_DIV, + .bit_idx = 16, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_input", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_input.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VIID_CLK_DIV, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_input.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 19, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div2_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 1, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div2_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div4_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div4_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div6_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div6_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vclk2_div12_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VIID_CLK_CTRL, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vclk2_div12_en", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vclk2.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_div2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_div4_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_div6_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk_div12_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk2_div2 = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div2", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_div2_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk2_div4 = { + .mult = 1, + .div = 4, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div4", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_div4_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk2_div6 = { + .mult = 1, + .div = 6, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div6", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_div6_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_vclk2_div12 = { + .mult = 1, + .div = 12, + .hw.init = &(struct clk_init_data){ + .name = "vclk2_div12", + .ops = &clk_fixed_factor_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vclk2_div12_en.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* The 5,6,7 indexes corresponds to no real clock, so there are not used. */ +static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *s4_cts_parent_hws[] = { + &s4_vclk_div1.hw, + &s4_vclk_div2.hw, + &s4_vclk_div4.hw, + &s4_vclk_div6.hw, + &s4_vclk_div12.hw, + &s4_vclk2_div1.hw, + &s4_vclk2_div2.hw, + &s4_vclk2_div4.hw, + &s4_vclk2_div6.hw, + &s4_vclk2_div12.hw +}; + +static struct clk_regmap s4_cts_enci_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = mux_table_cts_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_enci_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_parent_hws, + .num_parents = ARRAY_SIZE(s4_cts_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cts_encp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VID_CLK_DIV, + .mask = 0xf, + .shift = 20, + .table = mux_table_cts_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encp_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_parent_hws, + .num_parents = ARRAY_SIZE(s4_cts_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cts_vdac_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VIID_CLK_DIV, + .mask = 0xf, + .shift = 28, + .table = mux_table_cts_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_vdac_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_parent_hws, + .num_parents = ARRAY_SIZE(s4_cts_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* The 5,6,7 indexes corresponds to no real clock, so there are not used. */ +static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 }; +static const struct clk_hw *s4_cts_hdmi_tx_parent_hws[] = { + &s4_vclk_div1.hw, + &s4_vclk_div2.hw, + &s4_vclk_div4.hw, + &s4_vclk_div6.hw, + &s4_vclk_div12.hw, + &s4_vclk2_div1.hw, + &s4_vclk2_div2.hw, + &s4_vclk2_div4.hw, + &s4_vclk2_div6.hw, + &s4_vclk2_div12.hw +}; + +static struct clk_regmap s4_hdmi_tx_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_HDMI_CLK_CTRL, + .mask = 0xf, + .shift = 16, + .table = mux_table_hdmi_tx_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_tx_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_cts_hdmi_tx_parent_hws, + .num_parents = ARRAY_SIZE(s4_cts_hdmi_tx_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cts_enci = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 0, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_enci", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cts_enci_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cts_encp = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 2, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cts_encp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_cts_vdac = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_vdac", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_cts_vdac_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_tx = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VID_CLK_CTRL2, + .bit_idx = 5, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi_tx", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdmi_tx_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* HDMI Clocks */ +static const struct clk_parent_data s4_hdmi_parent_data[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", } +}; + +static struct clk_regmap s4_hdmi_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_HDMI_CLK_CTRL, + .mask = 0x3, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_hdmi_parent_data, + .num_parents = ARRAY_SIZE(s4_hdmi_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_HDMI_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_hdmi_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_HDMI_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdmi", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_hdmi_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_ts_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_TS_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_ts_clk_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_TS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "ts_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_ts_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * The MALI IP is clocked by two identical clocks (mali_0 and mali_1) + * muxed by a glitch-free switch. The CCF can manage this glitch-free + * mux because it does top-to-bottom updates the each clock tree and + * switches to the "inactive" one when CLK_SET_RATE_GATE is set. + */ +static const struct clk_parent_data s4_mali_0_1_parent_data[] = { + { .fw_name = "xtal", }, + { .fw_name = "gp0_pll", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "fclk_div2p5", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", } +}; + +static struct clk_regmap s4_mali_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_mali_0_1_parent_data, + .num_parents = ARRAY_SIZE(s4_mali_0_1_parent_data), + /* + * Don't request the parent to change the rate because + * all GPU frequencies can be derived from the fclk_* + * clocks and one special GP0_PLL setting. This is + * important because we need the HIFI PLL clock for audio. + */ + .flags = 0, + }, +}; + +static struct clk_regmap s4_mali_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_mali_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_mali_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_mali_0_1_parent_data, + .num_parents = ARRAY_SIZE(s4_mali_0_1_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_mali_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_mali_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_mali_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *s4_mali_parent_hws[] = { + &s4_mali_0.hw, + &s4_mali_1.hw +}; + +static struct clk_regmap s4_mali_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_MALI_CLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "mali", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_mali_parent_hws, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VDEC clocks */ +static const struct clk_parent_data s4_dec_parent_data[] = { + { .fw_name = "fclk_div2p5", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "gp0_pll", }, + { .fw_name = "xtal", } +}; + +static struct clk_regmap s4_vdec_p0_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p0_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_dec_parent_data, + .num_parents = ARRAY_SIZE(s4_dec_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vdec_p0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDEC_CLK_CTRL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p0_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdec_p0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDEC_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdec_p1_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC3_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p1_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_dec_parent_data, + .num_parents = ARRAY_SIZE(s4_dec_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vdec_p1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDEC3_CLK_CTRL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p1_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdec_p1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDEC3_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdec_p1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *s4_vdec_mux_parent_hws[] = { + &s4_vdec_p0.hw, + &s4_vdec_p1.hw +}; + +static struct clk_regmap s4_vdec_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC3_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdec_mux", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_vdec_mux_parent_hws, + .num_parents = ARRAY_SIZE(s4_vdec_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_p0_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p0_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_dec_parent_data, + .num_parents = ARRAY_SIZE(s4_dec_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_hevcf_p0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p0_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_p0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDEC2_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_p0_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_p1_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .mask = 0x7, + .shift = 9, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p1_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_dec_parent_data, + .num_parents = ARRAY_SIZE(s4_dec_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_hevcf_p1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .shift = 0, + .width = 7, + .flags = CLK_DIVIDER_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p1_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hevcf_p1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_p1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hevcf_p1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *s4_hevcf_mux_parent_hws[] = { + &s4_hevcf_p0.hw, + &s4_hevcf_p1.hw +}; + +static struct clk_regmap s4_hevcf_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDEC4_CLK_CTRL, + .mask = 0x1, + .shift = 15, + }, + .hw.init = &(struct clk_init_data) { + .name = "hevcf", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_hevcf_mux_parent_hws, + .num_parents = ARRAY_SIZE(s4_hevcf_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VPU Clock */ +static const struct clk_parent_data s4_vpu_parent_data[] = { + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll1", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "hifi_pll", }, + { .fw_name = "gp0_pll", }, +}; + +static struct clk_regmap s4_vpu_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vpu_parent_data, + .num_parents = ARRAY_SIZE(s4_vpu_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vpu_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vpu_0_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vpu_0_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vpu_parent_data, + .num_parents = ARRAY_SIZE(s4_vpu_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vpu_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vpu_1_sel.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vpu_1_div.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_0.hw, + &s4_vpu_1.hw, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data vpu_clkb_tmp_parent_data[] = { + { .hw = &s4_vpu.hw }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", } +}; + +static struct clk_regmap s4_vpu_clkb_tmp_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .mask = 0x3, + .shift = 20, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkb_tmp_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = vpu_clkb_tmp_parent_data, + .num_parents = ARRAY_SIZE(vpu_clkb_tmp_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkb_tmp_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .shift = 16, + .width = 4, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkb_tmp_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkb_tmp_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkb_tmp = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_clkb_tmp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkb_tmp_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkb_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkb_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkb_tmp.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkb = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLKB_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_clkb", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkb_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_vpu_clkc_parent_data[] = { + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll1", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "mpll2", }, + { .fw_name = "gp0_pll", }, +}; + +static struct clk_regmap s4_vpu_clkc_p0_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_p0_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vpu_clkc_parent_data, + .num_parents = ARRAY_SIZE(s4_vpu_clkc_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_p0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p0_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_clkc_p0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p1_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_p1_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vpu_clkc_parent_data, + .num_parents = ARRAY_SIZE(s4_vpu_clkc_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_p1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p1_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vpu_clkc_p1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "vpu_clkc_p1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vpu_clkc_p1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_hw *s4_vpu_mux_parent_hws[] = { + &s4_vpu_clkc_p0.hw, + &s4_vpu_clkc_p1.hw +}; + +static struct clk_regmap s4_vpu_clkc_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VPU_CLKC_CTRL, + .mask = 0x1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data) { + .name = "vpu_clkc_mux", + .ops = &clk_regmap_mux_ops, + .parent_hws = s4_vpu_mux_parent_hws, + .num_parents = ARRAY_SIZE(s4_vpu_mux_parent_hws), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* VAPB Clock */ +static const struct clk_parent_data s4_vapb_parent_data[] = { + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll1", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "mpll2", }, + { .fw_name = "fclk_div2p5", }, +}; + +static struct clk_regmap s4_vapb_0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vapb_parent_data, + .num_parents = ARRAY_SIZE(s4_vapb_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vapb_0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vapb_0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vapb_1_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vapb_parent_data, + .num_parents = ARRAY_SIZE(s4_vapb_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_vapb_1_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_1_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vapb_1 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_1_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vapb = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .mask = 1, + .shift = 31, + }, + .hw.init = &(struct clk_init_data){ + .name = "vapb_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vapb_0.hw, + &s4_vapb_1.hw + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_ge2d_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VAPBCLK_CTRL, + .bit_idx = 30, + }, + .hw.init = &(struct clk_init_data) { + .name = "ge2d_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { &s4_vapb.hw }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_esmclk_parent_data[] = { + { .fw_name = "fclk_div7", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, +}; + +static struct clk_regmap s4_hdcp22_esmclk_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdcp22_esmclk_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_esmclk_parent_data, + .num_parents = ARRAY_SIZE(s4_esmclk_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdcp22_esmclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdcp22_esmclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdcp22_esmclk_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdcp22_esmclk_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdcp22_esmclk_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdcp22_esmclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_skpclk_parent_data[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, +}; + +static struct clk_regmap s4_hdcp22_skpclk_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdcp22_skpclk_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_skpclk_parent_data, + .num_parents = ARRAY_SIZE(s4_skpclk_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdcp22_skpclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "hdcp22_skpclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdcp22_skpclk_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdcp22_skpclk_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_HDCP22_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "hdcp22_skpclk_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_hdcp22_skpclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_vdin_parent_data[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .hw = &s4_vid_pll.hw } +}; + +static struct clk_regmap s4_vdin_meas_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_VDIN_MEAS_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdin_meas_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_vdin_parent_data, + .num_parents = ARRAY_SIZE(s4_vdin_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdin_meas_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_VDIN_MEAS_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "vdin_meas_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdin_meas_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_vdin_meas_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_VDIN_MEAS_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "vdin_meas_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_vdin_meas_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* EMMC/NAND clock */ +static const struct clk_parent_data s4_sd_emmc_clk0_parent_data[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "fclk_div2p5", }, + { .fw_name = "mpll2", }, + { .fw_name = "mpll3", }, + { .fw_name = "gp0_pll", }, +}; + +static struct clk_regmap s4_sd_emmc_c_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_NAND_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_sd_emmc_c_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_NAND_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_c_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_c_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_c_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_NAND_CLK_CTRL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_c_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_c_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_a_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .mask = 0x7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_sd_emmc_a_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_a_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_a_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_a_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .bit_idx = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_a_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_a_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_b_clk0_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_sd_emmc_clk0_parent_data, + .num_parents = ARRAY_SIZE(s4_sd_emmc_clk0_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_sd_emmc_b_clk0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "sd_emmc_b_clk0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_b_clk0_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_sd_emmc_b_clk0 = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SD_EMMC_CLK_CTRL, + .bit_idx = 23, + }, + .hw.init = &(struct clk_init_data){ + .name = "sd_emmc_b_clk0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_sd_emmc_b_clk0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* SPICC Clock */ +static const struct clk_parent_data s4_spicc_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &s4_sys_clk.hw }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, +}; + +static struct clk_regmap s4_spicc0_mux = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_SPICC_CLK_CTRL, + .mask = 0x7, + .shift = 7, + }, + .hw.init = &(struct clk_init_data) { + .name = "spicc0_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_spicc_parent_data, + .num_parents = ARRAY_SIZE(s4_spicc_parent_data), + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_spicc0_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_SPICC_CLK_CTRL, + .shift = 0, + .width = 6, + }, + .hw.init = &(struct clk_init_data) { + .name = "spicc0_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_spicc0_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_spicc0_gate = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_SPICC_CLK_CTRL, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "spicc0", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_spicc0_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* PWM Clock */ +static const struct clk_parent_data s4_pwm_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, +}; + +static struct clk_regmap s4_pwm_a_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_AB_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_a_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_a_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_AB_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_a_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_a_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_a_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_AB_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_a_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_a_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_b_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_AB_CTRL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_b_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_b_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_AB_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_b_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_b_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_b_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_AB_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_b_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_b_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_c_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_CD_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_c_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_c_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_CD_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_c_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_c_mux.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap s4_pwm_c_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_CD_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_c_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_c_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_d_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_CD_CTRL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_d_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_d_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_CD_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_d_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_d_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_d_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_CD_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_d_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_d_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_e_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_EF_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_e_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_e_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_EF_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_e_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_e_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_e_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_EF_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_e_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_e_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_f_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_EF_CTRL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_f_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_f_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_EF_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_f_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_f_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_f_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_EF_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_f_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_f_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_g_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_GH_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_g_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_g_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_GH_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_g_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_g_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_g_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_GH_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_g_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_g_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_h_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_GH_CTRL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_h_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_h_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_GH_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_h_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_h_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_h_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_GH_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_h_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_h_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_i_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_IJ_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_i_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_i_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_IJ_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_i_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_i_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_i_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_IJ_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_i_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_i_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_j_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_PWM_CLK_IJ_CTRL, + .mask = 0x3, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_j_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_pwm_parent_data, + .num_parents = ARRAY_SIZE(s4_pwm_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_pwm_j_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_PWM_CLK_IJ_CTRL, + .shift = 16, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_j_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_h_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_pwm_j_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_PWM_CLK_IJ_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "pwm_j_gate", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_pwm_j_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_saradc_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_SAR_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "saradc_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .hw = &s4_sys_clk.hw }, + }, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_saradc_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_SAR_CLK_CTRL, + .shift = 0, + .width = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "saradc_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_saradc_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_saradc_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_SAR_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "saradc_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_saradc_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* + * gen clk is designed for debug/monitor some internal clock quality. Some of the + * corresponding clock sources are not described in the clock tree and internal clock + * for debug, so they are skipped. + */ +static u32 s4_gen_clk_mux_table[] = { 0, 4, 5, 7, 19, 21, 22, + 23, 24, 25, 26, 27, 28 }; +static const struct clk_parent_data s4_gen_clk_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &s4_vid_pll.hw }, + { .fw_name = "gp0_pll", }, + { .fw_name = "hifi_pll", }, + { .fw_name = "fclk_div2", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll0", }, + { .fw_name = "mpll1", }, + { .fw_name = "mpll2", }, + { .fw_name = "mpll3", }, +}; + +static struct clk_regmap s4_gen_clk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = CLKCTRL_GEN_CLK_CTRL, + .mask = 0x1f, + .shift = 12, + .table = s4_gen_clk_mux_table, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_gen_clk_parent_data, + .num_parents = ARRAY_SIZE(s4_gen_clk_parent_data), + /* + * Because the GEN clock can be connected to an external pad + * and may be set up directly from the device tree. Don't + * really want to automatically reparent. + */ + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap s4_gen_clk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = CLKCTRL_GEN_CLK_CTRL, + .shift = 0, + .width = 11, + }, + .hw.init = &(struct clk_init_data){ + .name = "gen_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_gen_clk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_gen_clk = { + .data = &(struct clk_regmap_gate_data){ + .offset = CLKCTRL_GEN_CLK_CTRL, + .bit_idx = 11, + }, + .hw.init = &(struct clk_init_data) { + .name = "gen_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_gen_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static const struct clk_parent_data s4_adc_extclk_in_parent_data[] = { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div4", }, + { .fw_name = "fclk_div3", }, + { .fw_name = "fclk_div5", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "mpll2", }, + { .fw_name = "gp0_pll", }, + { .fw_name = "hifi_pll", }, +}; + +static struct clk_regmap s4_adc_extclk_in_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .mask = 0x7, + .shift = 25, + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = s4_adc_extclk_in_parent_data, + .num_parents = ARRAY_SIZE(s4_adc_extclk_in_parent_data), + .flags = 0, + }, +}; + +static struct clk_regmap s4_adc_extclk_in_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .shift = 16, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_adc_extclk_in_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_adc_extclk_in_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .bit_idx = 24, + }, + .hw.init = &(struct clk_init_data){ + .name = "adc_extclk_in", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_adc_extclk_in_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_demod_core_clk_mux = { + .data = &(struct clk_regmap_mux_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .mask = 0x3, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core_clk_mux", + .ops = &clk_regmap_mux_ops, + .parent_data = (const struct clk_parent_data []) { + { .fw_name = "xtal", }, + { .fw_name = "fclk_div7", }, + { .fw_name = "fclk_div4", }, + { .hw = &s4_adc_extclk_in_gate.hw } + }, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_demod_core_clk_div = { + .data = &(struct clk_regmap_div_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core_clk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_demod_core_clk_mux.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_demod_core_clk_gate = { + .data = &(struct clk_regmap_gate_data) { + .offset = CLKCTRL_DEMOD_CLK_CTRL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data){ + .name = "demod_core_clk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &s4_demod_core_clk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +#define MESON_GATE(_name, _reg, _bit) \ + MESON_PCLK(_name, _reg, _bit, &s4_sys_clk.hw) + +static MESON_GATE(s4_ddr, CLKCTRL_SYS_CLK_EN0_REG0, 0); +static MESON_GATE(s4_dos, CLKCTRL_SYS_CLK_EN0_REG0, 1); +static MESON_GATE(s4_ethphy, CLKCTRL_SYS_CLK_EN0_REG0, 4); +static MESON_GATE(s4_mali, CLKCTRL_SYS_CLK_EN0_REG0, 6); +static MESON_GATE(s4_aocpu, CLKCTRL_SYS_CLK_EN0_REG0, 13); +static MESON_GATE(s4_aucpu, CLKCTRL_SYS_CLK_EN0_REG0, 14); +static MESON_GATE(s4_cec, CLKCTRL_SYS_CLK_EN0_REG0, 16); +static MESON_GATE(s4_sdemmca, CLKCTRL_SYS_CLK_EN0_REG0, 24); +static MESON_GATE(s4_sdemmcb, CLKCTRL_SYS_CLK_EN0_REG0, 25); +static MESON_GATE(s4_nand, CLKCTRL_SYS_CLK_EN0_REG0, 26); +static MESON_GATE(s4_smartcard, CLKCTRL_SYS_CLK_EN0_REG0, 27); +static MESON_GATE(s4_acodec, CLKCTRL_SYS_CLK_EN0_REG0, 28); +static MESON_GATE(s4_spifc, CLKCTRL_SYS_CLK_EN0_REG0, 29); +static MESON_GATE(s4_msr_clk, CLKCTRL_SYS_CLK_EN0_REG0, 30); +static MESON_GATE(s4_ir_ctrl, CLKCTRL_SYS_CLK_EN0_REG0, 31); +static MESON_GATE(s4_audio, CLKCTRL_SYS_CLK_EN0_REG1, 0); +static MESON_GATE(s4_eth, CLKCTRL_SYS_CLK_EN0_REG1, 3); +static MESON_GATE(s4_uart_a, CLKCTRL_SYS_CLK_EN0_REG1, 5); +static MESON_GATE(s4_uart_b, CLKCTRL_SYS_CLK_EN0_REG1, 6); +static MESON_GATE(s4_uart_c, CLKCTRL_SYS_CLK_EN0_REG1, 7); +static MESON_GATE(s4_uart_d, CLKCTRL_SYS_CLK_EN0_REG1, 8); +static MESON_GATE(s4_uart_e, CLKCTRL_SYS_CLK_EN0_REG1, 9); +static MESON_GATE(s4_aififo, CLKCTRL_SYS_CLK_EN0_REG1, 11); +static MESON_GATE(s4_ts_ddr, CLKCTRL_SYS_CLK_EN0_REG1, 15); +static MESON_GATE(s4_ts_pll, CLKCTRL_SYS_CLK_EN0_REG1, 16); +static MESON_GATE(s4_g2d, CLKCTRL_SYS_CLK_EN0_REG1, 20); +static MESON_GATE(s4_spicc0, CLKCTRL_SYS_CLK_EN0_REG1, 21); +static MESON_GATE(s4_usb, CLKCTRL_SYS_CLK_EN0_REG1, 26); +static MESON_GATE(s4_i2c_m_a, CLKCTRL_SYS_CLK_EN0_REG1, 30); +static MESON_GATE(s4_i2c_m_b, CLKCTRL_SYS_CLK_EN0_REG1, 31); +static MESON_GATE(s4_i2c_m_c, CLKCTRL_SYS_CLK_EN0_REG2, 0); +static MESON_GATE(s4_i2c_m_d, CLKCTRL_SYS_CLK_EN0_REG2, 1); +static MESON_GATE(s4_i2c_m_e, CLKCTRL_SYS_CLK_EN0_REG2, 2); +static MESON_GATE(s4_hdmitx_apb, CLKCTRL_SYS_CLK_EN0_REG2, 4); +static MESON_GATE(s4_i2c_s_a, CLKCTRL_SYS_CLK_EN0_REG2, 5); +static MESON_GATE(s4_usb1_to_ddr, CLKCTRL_SYS_CLK_EN0_REG2, 8); +static MESON_GATE(s4_hdcp22, CLKCTRL_SYS_CLK_EN0_REG2, 10); +static MESON_GATE(s4_mmc_apb, CLKCTRL_SYS_CLK_EN0_REG2, 11); +static MESON_GATE(s4_rsa, CLKCTRL_SYS_CLK_EN0_REG2, 18); +static MESON_GATE(s4_cpu_debug, CLKCTRL_SYS_CLK_EN0_REG2, 19); +static MESON_GATE(s4_vpu_intr, CLKCTRL_SYS_CLK_EN0_REG2, 25); +static MESON_GATE(s4_demod, CLKCTRL_SYS_CLK_EN0_REG2, 27); +static MESON_GATE(s4_sar_adc, CLKCTRL_SYS_CLK_EN0_REG2, 28); +static MESON_GATE(s4_gic, CLKCTRL_SYS_CLK_EN0_REG2, 30); +static MESON_GATE(s4_pwm_ab, CLKCTRL_SYS_CLK_EN0_REG3, 7); +static MESON_GATE(s4_pwm_cd, CLKCTRL_SYS_CLK_EN0_REG3, 8); +static MESON_GATE(s4_pwm_ef, CLKCTRL_SYS_CLK_EN0_REG3, 9); +static MESON_GATE(s4_pwm_gh, CLKCTRL_SYS_CLK_EN0_REG3, 10); +static MESON_GATE(s4_pwm_ij, CLKCTRL_SYS_CLK_EN0_REG3, 11); + +/* Array of all clocks provided by this provider */ +static struct clk_hw *s4_periphs_hw_clks[] = { + [CLKID_RTC_32K_CLKIN] = &s4_rtc_32k_by_oscin_clkin.hw, + [CLKID_RTC_32K_DIV] = &s4_rtc_32k_by_oscin_div.hw, + [CLKID_RTC_32K_SEL] = &s4_rtc_32k_by_oscin_sel.hw, + [CLKID_RTC_32K_XATL] = &s4_rtc_32k_by_oscin.hw, + [CLKID_RTC] = &s4_rtc_clk.hw, + [CLKID_SYS_CLK_B_SEL] = &s4_sysclk_b_sel.hw, + [CLKID_SYS_CLK_B_DIV] = &s4_sysclk_b_div.hw, + [CLKID_SYS_CLK_B] = &s4_sysclk_b.hw, + [CLKID_SYS_CLK_A_SEL] = &s4_sysclk_a_sel.hw, + [CLKID_SYS_CLK_A_DIV] = &s4_sysclk_a_div.hw, + [CLKID_SYS_CLK_A] = &s4_sysclk_a.hw, + [CLKID_SYS] = &s4_sys_clk.hw, + [CLKID_CECA_32K_CLKIN] = &s4_ceca_32k_clkin.hw, + [CLKID_CECA_32K_DIV] = &s4_ceca_32k_div.hw, + [CLKID_CECA_32K_SEL_PRE] = &s4_ceca_32k_sel_pre.hw, + [CLKID_CECA_32K_SEL] = &s4_ceca_32k_sel.hw, + [CLKID_CECA_32K_CLKOUT] = &s4_ceca_32k_clkout.hw, + [CLKID_CECB_32K_CLKIN] = &s4_cecb_32k_clkin.hw, + [CLKID_CECB_32K_DIV] = &s4_cecb_32k_div.hw, + [CLKID_CECB_32K_SEL_PRE] = &s4_cecb_32k_sel_pre.hw, + [CLKID_CECB_32K_SEL] = &s4_cecb_32k_sel.hw, + [CLKID_CECB_32K_CLKOUT] = &s4_cecb_32k_clkout.hw, + [CLKID_SC_CLK_SEL] = &s4_sc_clk_mux.hw, + [CLKID_SC_CLK_DIV] = &s4_sc_clk_div.hw, + [CLKID_SC] = &s4_sc_clk_gate.hw, + [CLKID_12_24M] = &s4_12_24M_clk_gate.hw, + [CLKID_12M_CLK_DIV] = &s4_12M_clk_div.hw, + [CLKID_12_24M_CLK_SEL] = &s4_12_24M_clk.hw, + [CLKID_VID_PLL_DIV] = &s4_vid_pll_div.hw, + [CLKID_VID_PLL_SEL] = &s4_vid_pll_sel.hw, + [CLKID_VID_PLL] = &s4_vid_pll.hw, + [CLKID_VCLK_SEL] = &s4_vclk_sel.hw, + [CLKID_VCLK2_SEL] = &s4_vclk2_sel.hw, + [CLKID_VCLK_INPUT] = &s4_vclk_input.hw, + [CLKID_VCLK2_INPUT] = &s4_vclk2_input.hw, + [CLKID_VCLK_DIV] = &s4_vclk_div.hw, + [CLKID_VCLK2_DIV] = &s4_vclk2_div.hw, + [CLKID_VCLK] = &s4_vclk.hw, + [CLKID_VCLK2] = &s4_vclk2.hw, + [CLKID_VCLK_DIV1] = &s4_vclk_div1.hw, + [CLKID_VCLK_DIV2_EN] = &s4_vclk_div2_en.hw, + [CLKID_VCLK_DIV4_EN] = &s4_vclk_div4_en.hw, + [CLKID_VCLK_DIV6_EN] = &s4_vclk_div6_en.hw, + [CLKID_VCLK_DIV12_EN] = &s4_vclk_div12_en.hw, + [CLKID_VCLK2_DIV1] = &s4_vclk2_div1.hw, + [CLKID_VCLK2_DIV2_EN] = &s4_vclk2_div2_en.hw, + [CLKID_VCLK2_DIV4_EN] = &s4_vclk2_div4_en.hw, + [CLKID_VCLK2_DIV6_EN] = &s4_vclk2_div6_en.hw, + [CLKID_VCLK2_DIV12_EN] = &s4_vclk2_div12_en.hw, + [CLKID_VCLK_DIV2] = &s4_vclk_div2.hw, + [CLKID_VCLK_DIV4] = &s4_vclk_div4.hw, + [CLKID_VCLK_DIV6] = &s4_vclk_div6.hw, + [CLKID_VCLK_DIV12] = &s4_vclk_div12.hw, + [CLKID_VCLK2_DIV2] = &s4_vclk2_div2.hw, + [CLKID_VCLK2_DIV4] = &s4_vclk2_div4.hw, + [CLKID_VCLK2_DIV6] = &s4_vclk2_div6.hw, + [CLKID_VCLK2_DIV12] = &s4_vclk2_div12.hw, + [CLKID_CTS_ENCI_SEL] = &s4_cts_enci_sel.hw, + [CLKID_CTS_ENCP_SEL] = &s4_cts_encp_sel.hw, + [CLKID_CTS_VDAC_SEL] = &s4_cts_vdac_sel.hw, + [CLKID_HDMI_TX_SEL] = &s4_hdmi_tx_sel.hw, + [CLKID_CTS_ENCI] = &s4_cts_enci.hw, + [CLKID_CTS_ENCP] = &s4_cts_encp.hw, + [CLKID_CTS_VDAC] = &s4_cts_vdac.hw, + [CLKID_HDMI_TX] = &s4_hdmi_tx.hw, + [CLKID_HDMI_SEL] = &s4_hdmi_sel.hw, + [CLKID_HDMI_DIV] = &s4_hdmi_div.hw, + [CLKID_HDMI] = &s4_hdmi.hw, + [CLKID_TS_CLK_DIV] = &s4_ts_clk_div.hw, + [CLKID_TS] = &s4_ts_clk_gate.hw, + [CLKID_MALI_0_SEL] = &s4_mali_0_sel.hw, + [CLKID_MALI_0_DIV] = &s4_mali_0_div.hw, + [CLKID_MALI_0] = &s4_mali_0.hw, + [CLKID_MALI_1_SEL] = &s4_mali_1_sel.hw, + [CLKID_MALI_1_DIV] = &s4_mali_1_div.hw, + [CLKID_MALI_1] = &s4_mali_1.hw, + [CLKID_MALI_SEL] = &s4_mali_mux.hw, + [CLKID_VDEC_P0_SEL] = &s4_vdec_p0_mux.hw, + [CLKID_VDEC_P0_DIV] = &s4_vdec_p0_div.hw, + [CLKID_VDEC_P0] = &s4_vdec_p0.hw, + [CLKID_VDEC_P1_SEL] = &s4_vdec_p1_mux.hw, + [CLKID_VDEC_P1_DIV] = &s4_vdec_p1_div.hw, + [CLKID_VDEC_P1] = &s4_vdec_p1.hw, + [CLKID_VDEC_SEL] = &s4_vdec_mux.hw, + [CLKID_HEVCF_P0_SEL] = &s4_hevcf_p0_mux.hw, + [CLKID_HEVCF_P0_DIV] = &s4_hevcf_p0_div.hw, + [CLKID_HEVCF_P0] = &s4_hevcf_p0.hw, + [CLKID_HEVCF_P1_SEL] = &s4_hevcf_p1_mux.hw, + [CLKID_HEVCF_P1_DIV] = &s4_hevcf_p1_div.hw, + [CLKID_HEVCF_P1] = &s4_hevcf_p1.hw, + [CLKID_HEVCF_SEL] = &s4_hevcf_mux.hw, + [CLKID_VPU_0_SEL] = &s4_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &s4_vpu_0_div.hw, + [CLKID_VPU_0] = &s4_vpu_0.hw, + [CLKID_VPU_1_SEL] = &s4_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &s4_vpu_1_div.hw, + [CLKID_VPU_1] = &s4_vpu_1.hw, + [CLKID_VPU] = &s4_vpu.hw, + [CLKID_VPU_CLKB_TMP_SEL] = &s4_vpu_clkb_tmp_mux.hw, + [CLKID_VPU_CLKB_TMP_DIV] = &s4_vpu_clkb_tmp_div.hw, + [CLKID_VPU_CLKB_TMP] = &s4_vpu_clkb_tmp.hw, + [CLKID_VPU_CLKB_DIV] = &s4_vpu_clkb_div.hw, + [CLKID_VPU_CLKB] = &s4_vpu_clkb.hw, + [CLKID_VPU_CLKC_P0_SEL] = &s4_vpu_clkc_p0_mux.hw, + [CLKID_VPU_CLKC_P0_DIV] = &s4_vpu_clkc_p0_div.hw, + [CLKID_VPU_CLKC_P0] = &s4_vpu_clkc_p0.hw, + [CLKID_VPU_CLKC_P1_SEL] = &s4_vpu_clkc_p1_mux.hw, + [CLKID_VPU_CLKC_P1_DIV] = &s4_vpu_clkc_p1_div.hw, + [CLKID_VPU_CLKC_P1] = &s4_vpu_clkc_p1.hw, + [CLKID_VPU_CLKC_SEL] = &s4_vpu_clkc_mux.hw, + [CLKID_VAPB_0_SEL] = &s4_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &s4_vapb_0_div.hw, + [CLKID_VAPB_0] = &s4_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &s4_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &s4_vapb_1_div.hw, + [CLKID_VAPB_1] = &s4_vapb_1.hw, + [CLKID_VAPB] = &s4_vapb.hw, + [CLKID_GE2D] = &s4_ge2d_gate.hw, + [CLKID_VDIN_MEAS_SEL] = &s4_vdin_meas_mux.hw, + [CLKID_VDIN_MEAS_DIV] = &s4_vdin_meas_div.hw, + [CLKID_VDIN_MEAS] = &s4_vdin_meas_gate.hw, + [CLKID_SD_EMMC_C_CLK_SEL] = &s4_sd_emmc_c_clk0_sel.hw, + [CLKID_SD_EMMC_C_CLK_DIV] = &s4_sd_emmc_c_clk0_div.hw, + [CLKID_SD_EMMC_C] = &s4_sd_emmc_c_clk0.hw, + [CLKID_SD_EMMC_A_CLK_SEL] = &s4_sd_emmc_a_clk0_sel.hw, + [CLKID_SD_EMMC_A_CLK_DIV] = &s4_sd_emmc_a_clk0_div.hw, + [CLKID_SD_EMMC_A] = &s4_sd_emmc_a_clk0.hw, + [CLKID_SD_EMMC_B_CLK_SEL] = &s4_sd_emmc_b_clk0_sel.hw, + [CLKID_SD_EMMC_B_CLK_DIV] = &s4_sd_emmc_b_clk0_div.hw, + [CLKID_SD_EMMC_B] = &s4_sd_emmc_b_clk0.hw, + [CLKID_SPICC0_SEL] = &s4_spicc0_mux.hw, + [CLKID_SPICC0_DIV] = &s4_spicc0_div.hw, + [CLKID_SPICC0_EN] = &s4_spicc0_gate.hw, + [CLKID_PWM_A_SEL] = &s4_pwm_a_mux.hw, + [CLKID_PWM_A_DIV] = &s4_pwm_a_div.hw, + [CLKID_PWM_A] = &s4_pwm_a_gate.hw, + [CLKID_PWM_B_SEL] = &s4_pwm_b_mux.hw, + [CLKID_PWM_B_DIV] = &s4_pwm_b_div.hw, + [CLKID_PWM_B] = &s4_pwm_b_gate.hw, + [CLKID_PWM_C_SEL] = &s4_pwm_c_mux.hw, + [CLKID_PWM_C_DIV] = &s4_pwm_c_div.hw, + [CLKID_PWM_C] = &s4_pwm_c_gate.hw, + [CLKID_PWM_D_SEL] = &s4_pwm_d_mux.hw, + [CLKID_PWM_D_DIV] = &s4_pwm_d_div.hw, + [CLKID_PWM_D] = &s4_pwm_d_gate.hw, + [CLKID_PWM_E_SEL] = &s4_pwm_e_mux.hw, + [CLKID_PWM_E_DIV] = &s4_pwm_e_div.hw, + [CLKID_PWM_E] = &s4_pwm_e_gate.hw, + [CLKID_PWM_F_SEL] = &s4_pwm_f_mux.hw, + [CLKID_PWM_F_DIV] = &s4_pwm_f_div.hw, + [CLKID_PWM_F] = &s4_pwm_f_gate.hw, + [CLKID_PWM_G_SEL] = &s4_pwm_g_mux.hw, + [CLKID_PWM_G_DIV] = &s4_pwm_g_div.hw, + [CLKID_PWM_G] = &s4_pwm_g_gate.hw, + [CLKID_PWM_H_SEL] = &s4_pwm_h_mux.hw, + [CLKID_PWM_H_DIV] = &s4_pwm_h_div.hw, + [CLKID_PWM_H] = &s4_pwm_h_gate.hw, + [CLKID_PWM_I_SEL] = &s4_pwm_i_mux.hw, + [CLKID_PWM_I_DIV] = &s4_pwm_i_div.hw, + [CLKID_PWM_I] = &s4_pwm_i_gate.hw, + [CLKID_PWM_J_SEL] = &s4_pwm_j_mux.hw, + [CLKID_PWM_J_DIV] = &s4_pwm_j_div.hw, + [CLKID_PWM_J] = &s4_pwm_j_gate.hw, + [CLKID_SARADC_SEL] = &s4_saradc_mux.hw, + [CLKID_SARADC_DIV] = &s4_saradc_div.hw, + [CLKID_SARADC] = &s4_saradc_gate.hw, + [CLKID_GEN_SEL] = &s4_gen_clk_sel.hw, + [CLKID_GEN_DIV] = &s4_gen_clk_div.hw, + [CLKID_GEN] = &s4_gen_clk.hw, + [CLKID_DDR] = &s4_ddr.hw, + [CLKID_DOS] = &s4_dos.hw, + [CLKID_ETHPHY] = &s4_ethphy.hw, + [CLKID_MALI] = &s4_mali.hw, + [CLKID_AOCPU] = &s4_aocpu.hw, + [CLKID_AUCPU] = &s4_aucpu.hw, + [CLKID_CEC] = &s4_cec.hw, + [CLKID_SDEMMC_A] = &s4_sdemmca.hw, + [CLKID_SDEMMC_B] = &s4_sdemmcb.hw, + [CLKID_NAND] = &s4_nand.hw, + [CLKID_SMARTCARD] = &s4_smartcard.hw, + [CLKID_ACODEC] = &s4_acodec.hw, + [CLKID_SPIFC] = &s4_spifc.hw, + [CLKID_MSR] = &s4_msr_clk.hw, + [CLKID_IR_CTRL] = &s4_ir_ctrl.hw, + [CLKID_AUDIO] = &s4_audio.hw, + [CLKID_ETH] = &s4_eth.hw, + [CLKID_UART_A] = &s4_uart_a.hw, + [CLKID_UART_B] = &s4_uart_b.hw, + [CLKID_UART_C] = &s4_uart_c.hw, + [CLKID_UART_D] = &s4_uart_d.hw, + [CLKID_UART_E] = &s4_uart_e.hw, + [CLKID_AIFIFO] = &s4_aififo.hw, + [CLKID_TS_DDR] = &s4_ts_ddr.hw, + [CLKID_TS_PLL] = &s4_ts_pll.hw, + [CLKID_G2D] = &s4_g2d.hw, + [CLKID_SPICC0] = &s4_spicc0.hw, + [CLKID_USB] = &s4_usb.hw, + [CLKID_I2C_M_A] = &s4_i2c_m_a.hw, + [CLKID_I2C_M_B] = &s4_i2c_m_b.hw, + [CLKID_I2C_M_C] = &s4_i2c_m_c.hw, + [CLKID_I2C_M_D] = &s4_i2c_m_d.hw, + [CLKID_I2C_M_E] = &s4_i2c_m_e.hw, + [CLKID_HDMITX_APB] = &s4_hdmitx_apb.hw, + [CLKID_I2C_S_A] = &s4_i2c_s_a.hw, + [CLKID_USB1_TO_DDR] = &s4_usb1_to_ddr.hw, + [CLKID_HDCP22] = &s4_hdcp22.hw, + [CLKID_MMC_APB] = &s4_mmc_apb.hw, + [CLKID_RSA] = &s4_rsa.hw, + [CLKID_CPU_DEBUG] = &s4_cpu_debug.hw, + [CLKID_VPU_INTR] = &s4_vpu_intr.hw, + [CLKID_DEMOD] = &s4_demod.hw, + [CLKID_SAR_ADC] = &s4_sar_adc.hw, + [CLKID_GIC] = &s4_gic.hw, + [CLKID_PWM_AB] = &s4_pwm_ab.hw, + [CLKID_PWM_CD] = &s4_pwm_cd.hw, + [CLKID_PWM_EF] = &s4_pwm_ef.hw, + [CLKID_PWM_GH] = &s4_pwm_gh.hw, + [CLKID_PWM_IJ] = &s4_pwm_ij.hw, + [CLKID_HDCP22_ESMCLK_SEL] = &s4_hdcp22_esmclk_mux.hw, + [CLKID_HDCP22_ESMCLK_DIV] = &s4_hdcp22_esmclk_div.hw, + [CLKID_HDCP22_ESMCLK] = &s4_hdcp22_esmclk_gate.hw, + [CLKID_HDCP22_SKPCLK_SEL] = &s4_hdcp22_skpclk_mux.hw, + [CLKID_HDCP22_SKPCLK_DIV] = &s4_hdcp22_skpclk_div.hw, + [CLKID_HDCP22_SKPCLK] = &s4_hdcp22_skpclk_gate.hw, +}; + +/* Convenience table to populate regmap in .probe */ +static struct clk_regmap *const s4_periphs_clk_regmaps[] = { + &s4_rtc_32k_by_oscin_clkin, + &s4_rtc_32k_by_oscin_div, + &s4_rtc_32k_by_oscin_sel, + &s4_rtc_32k_by_oscin, + &s4_rtc_clk, + &s4_sysclk_b_sel, + &s4_sysclk_b_div, + &s4_sysclk_b, + &s4_sysclk_a_sel, + &s4_sysclk_a_div, + &s4_sysclk_a, + &s4_sys_clk, + &s4_ceca_32k_clkin, + &s4_ceca_32k_div, + &s4_ceca_32k_sel_pre, + &s4_ceca_32k_sel, + &s4_ceca_32k_clkout, + &s4_cecb_32k_clkin, + &s4_cecb_32k_div, + &s4_cecb_32k_sel_pre, + &s4_cecb_32k_sel, + &s4_cecb_32k_clkout, + &s4_sc_clk_mux, + &s4_sc_clk_div, + &s4_sc_clk_gate, + &s4_12_24M_clk_gate, + &s4_12_24M_clk, + &s4_vid_pll_div, + &s4_vid_pll_sel, + &s4_vid_pll, + &s4_vclk_sel, + &s4_vclk2_sel, + &s4_vclk_input, + &s4_vclk2_input, + &s4_vclk_div, + &s4_vclk2_div, + &s4_vclk, + &s4_vclk2, + &s4_vclk_div1, + &s4_vclk_div2_en, + &s4_vclk_div4_en, + &s4_vclk_div6_en, + &s4_vclk_div12_en, + &s4_vclk2_div1, + &s4_vclk2_div2_en, + &s4_vclk2_div4_en, + &s4_vclk2_div6_en, + &s4_vclk2_div12_en, + &s4_cts_enci_sel, + &s4_cts_encp_sel, + &s4_cts_vdac_sel, + &s4_hdmi_tx_sel, + &s4_cts_enci, + &s4_cts_encp, + &s4_cts_vdac, + &s4_hdmi_tx, + &s4_hdmi_sel, + &s4_hdmi_div, + &s4_hdmi, + &s4_ts_clk_div, + &s4_ts_clk_gate, + &s4_mali_0_sel, + &s4_mali_0_div, + &s4_mali_0, + &s4_mali_1_sel, + &s4_mali_1_div, + &s4_mali_1, + &s4_mali_mux, + &s4_vdec_p0_mux, + &s4_vdec_p0_div, + &s4_vdec_p0, + &s4_vdec_p1_mux, + &s4_vdec_p1_div, + &s4_vdec_p1, + &s4_vdec_mux, + &s4_hevcf_p0_mux, + &s4_hevcf_p0_div, + &s4_hevcf_p0, + &s4_hevcf_p1_mux, + &s4_hevcf_p1_div, + &s4_hevcf_p1, + &s4_hevcf_mux, + &s4_vpu_0_sel, + &s4_vpu_0_div, + &s4_vpu_0, + &s4_vpu_1_sel, + &s4_vpu_1_div, + &s4_vpu_1, + &s4_vpu, + &s4_vpu_clkb_tmp_mux, + &s4_vpu_clkb_tmp_div, + &s4_vpu_clkb_tmp, + &s4_vpu_clkb_div, + &s4_vpu_clkb, + &s4_vpu_clkc_p0_mux, + &s4_vpu_clkc_p0_div, + &s4_vpu_clkc_p0, + &s4_vpu_clkc_p1_mux, + &s4_vpu_clkc_p1_div, + &s4_vpu_clkc_p1, + &s4_vpu_clkc_mux, + &s4_vapb_0_sel, + &s4_vapb_0_div, + &s4_vapb_0, + &s4_vapb_1_sel, + &s4_vapb_1_div, + &s4_vapb_1, + &s4_vapb, + &s4_ge2d_gate, + &s4_hdcp22_esmclk_mux, + &s4_hdcp22_esmclk_div, + &s4_hdcp22_esmclk_gate, + &s4_hdcp22_skpclk_mux, + &s4_hdcp22_skpclk_div, + &s4_hdcp22_skpclk_gate, + &s4_vdin_meas_mux, + &s4_vdin_meas_div, + &s4_vdin_meas_gate, + &s4_sd_emmc_c_clk0_sel, + &s4_sd_emmc_c_clk0_div, + &s4_sd_emmc_c_clk0, + &s4_sd_emmc_a_clk0_sel, + &s4_sd_emmc_a_clk0_div, + &s4_sd_emmc_a_clk0, + &s4_sd_emmc_b_clk0_sel, + &s4_sd_emmc_b_clk0_div, + &s4_sd_emmc_b_clk0, + &s4_spicc0_mux, + &s4_spicc0_div, + &s4_spicc0_gate, + &s4_pwm_a_mux, + &s4_pwm_a_div, + &s4_pwm_a_gate, + &s4_pwm_b_mux, + &s4_pwm_b_div, + &s4_pwm_b_gate, + &s4_pwm_c_mux, + &s4_pwm_c_div, + &s4_pwm_c_gate, + &s4_pwm_d_mux, + &s4_pwm_d_div, + &s4_pwm_d_gate, + &s4_pwm_e_mux, + &s4_pwm_e_div, + &s4_pwm_e_gate, + &s4_pwm_f_mux, + &s4_pwm_f_div, + &s4_pwm_f_gate, + &s4_pwm_g_mux, + &s4_pwm_g_div, + &s4_pwm_g_gate, + &s4_pwm_h_mux, + &s4_pwm_h_div, + &s4_pwm_h_gate, + &s4_pwm_i_mux, + &s4_pwm_i_div, + &s4_pwm_i_gate, + &s4_pwm_j_mux, + &s4_pwm_j_div, + &s4_pwm_j_gate, + &s4_saradc_mux, + &s4_saradc_div, + &s4_saradc_gate, + &s4_gen_clk_sel, + &s4_gen_clk_div, + &s4_gen_clk, + &s4_ddr, + &s4_dos, + &s4_ethphy, + &s4_mali, + &s4_aocpu, + &s4_aucpu, + &s4_cec, + &s4_sdemmca, + &s4_sdemmcb, + &s4_nand, + &s4_smartcard, + &s4_acodec, + &s4_spifc, + &s4_msr_clk, + &s4_ir_ctrl, + &s4_audio, + &s4_eth, + &s4_uart_a, + &s4_uart_b, + &s4_uart_c, + &s4_uart_d, + &s4_uart_e, + &s4_aififo, + &s4_ts_ddr, + &s4_ts_pll, + &s4_g2d, + &s4_spicc0, + &s4_usb, + &s4_i2c_m_a, + &s4_i2c_m_b, + &s4_i2c_m_c, + &s4_i2c_m_d, + &s4_i2c_m_e, + &s4_hdmitx_apb, + &s4_i2c_s_a, + &s4_usb1_to_ddr, + &s4_hdcp22, + &s4_mmc_apb, + &s4_rsa, + &s4_cpu_debug, + &s4_vpu_intr, + &s4_demod, + &s4_sar_adc, + &s4_gic, + &s4_pwm_ab, + &s4_pwm_cd, + &s4_pwm_ef, + &s4_pwm_gh, + &s4_pwm_ij, + &s4_demod_core_clk_mux, + &s4_demod_core_clk_div, + &s4_demod_core_clk_gate, + &s4_adc_extclk_in_mux, + &s4_adc_extclk_in_div, + &s4_adc_extclk_in_gate, +}; + +static struct regmap_config clkc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static struct meson_clk_hw_data s4_periphs_clks = { + .hws = s4_periphs_hw_clks, + .num = ARRAY_SIZE(s4_periphs_hw_clks), +}; + +static int meson_s4_periphs_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct regmap *regmap; + void __iomem *base; + int ret, i; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), + "can't ioremap resource\n"); + + regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "can't init regmap mmio region\n"); + + /* Populate regmap for the regmap backed clocks */ + for (i = 0; i < ARRAY_SIZE(s4_periphs_clk_regmaps); i++) + s4_periphs_clk_regmaps[i]->map = regmap; + + for (i = 0; i < s4_periphs_clks.num; i++) { + /* array might be sparse */ + if (!s4_periphs_clks.hws[i]) + continue; + + ret = devm_clk_hw_register(dev, s4_periphs_clks.hws[i]); + if (ret) + return dev_err_probe(dev, ret, + "clock[%d] registration failed\n", i); + } + + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, &s4_periphs_clks); +} + +static const struct of_device_id clkc_match_table[] = { + { + .compatible = "amlogic,s4-peripherals-clkc", + }, + {} +}; + +static struct platform_driver s4_driver = { + .probe = meson_s4_periphs_probe, + .driver = { + .name = "s4-periphs-clkc", + .of_match_table = clkc_match_table, + }, +}; + +module_platform_driver(s4_driver); +MODULE_AUTHOR("Yu Tu "); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/s4-peripherals.h b/drivers/clk/meson/s4-peripherals.h new file mode 100644 index 000000000000..1e298713c2b2 --- /dev/null +++ b/drivers/clk/meson/s4-peripherals.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved + * Author: Yu Tu + */ + +#ifndef __MESON_S4_PERIPHERALS_H__ +#define __MESON_S4_PERIPHERALS_H__ + +#define CLKCTRL_RTC_BY_OSCIN_CTRL0 0x008 +#define CLKCTRL_RTC_BY_OSCIN_CTRL1 0x00c +#define CLKCTRL_RTC_CTRL 0x010 +#define CLKCTRL_SYS_CLK_CTRL0 0x040 +#define CLKCTRL_SYS_CLK_EN0_REG0 0x044 +#define CLKCTRL_SYS_CLK_EN0_REG1 0x048 +#define CLKCTRL_SYS_CLK_EN0_REG2 0x04c +#define CLKCTRL_SYS_CLK_EN0_REG3 0x050 +#define CLKCTRL_CECA_CTRL0 0x088 +#define CLKCTRL_CECA_CTRL1 0x08c +#define CLKCTRL_CECB_CTRL0 0x090 +#define CLKCTRL_CECB_CTRL1 0x094 +#define CLKCTRL_SC_CLK_CTRL 0x098 +#define CLKCTRL_CLK12_24_CTRL 0x0a8 +#define CLKCTRL_VID_CLK_CTRL 0x0c0 +#define CLKCTRL_VID_CLK_CTRL2 0x0c4 +#define CLKCTRL_VID_CLK_DIV 0x0c8 +#define CLKCTRL_VIID_CLK_DIV 0x0cc +#define CLKCTRL_VIID_CLK_CTRL 0x0d0 +#define CLKCTRL_HDMI_CLK_CTRL 0x0e0 +#define CLKCTRL_VID_PLL_CLK_DIV 0x0e4 +#define CLKCTRL_VPU_CLK_CTRL 0x0e8 +#define CLKCTRL_VPU_CLKB_CTRL 0x0ec +#define CLKCTRL_VPU_CLKC_CTRL 0x0f0 +#define CLKCTRL_VID_LOCK_CLK_CTRL 0x0f4 +#define CLKCTRL_VDIN_MEAS_CLK_CTRL 0x0f8 +#define CLKCTRL_VAPBCLK_CTRL 0x0fc +#define CLKCTRL_HDCP22_CTRL 0x100 +#define CLKCTRL_VDEC_CLK_CTRL 0x140 +#define CLKCTRL_VDEC2_CLK_CTRL 0x144 +#define CLKCTRL_VDEC3_CLK_CTRL 0x148 +#define CLKCTRL_VDEC4_CLK_CTRL 0x14c +#define CLKCTRL_TS_CLK_CTRL 0x158 +#define CLKCTRL_MALI_CLK_CTRL 0x15c +#define CLKCTRL_NAND_CLK_CTRL 0x168 +#define CLKCTRL_SD_EMMC_CLK_CTRL 0x16c +#define CLKCTRL_SPICC_CLK_CTRL 0x174 +#define CLKCTRL_GEN_CLK_CTRL 0x178 +#define CLKCTRL_SAR_CLK_CTRL 0x17c +#define CLKCTRL_PWM_CLK_AB_CTRL 0x180 +#define CLKCTRL_PWM_CLK_CD_CTRL 0x184 +#define CLKCTRL_PWM_CLK_EF_CTRL 0x188 +#define CLKCTRL_PWM_CLK_GH_CTRL 0x18c +#define CLKCTRL_PWM_CLK_IJ_CTRL 0x190 +#define CLKCTRL_DEMOD_CLK_CTRL 0x200 + +#endif /* __MESON_S4_PERIPHERALS_H__ */ From f04410e7be65f0d005238f286ee37572874c0d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:14 +0200 Subject: [PATCH 122/396] platform/chrome: cros_ec_chardev: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-2-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_chardev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c index d6de5a294128..81950bb2c6da 100644 --- a/drivers/platform/chrome/cros_ec_chardev.c +++ b/drivers/platform/chrome/cros_ec_chardev.c @@ -396,13 +396,11 @@ static int cros_ec_chardev_probe(struct platform_device *pdev) return misc_register(&data->misc); } -static int cros_ec_chardev_remove(struct platform_device *pdev) +static void cros_ec_chardev_remove(struct platform_device *pdev) { struct chardev_data *data = dev_get_drvdata(&pdev->dev); misc_deregister(&data->misc); - - return 0; } static struct platform_driver cros_ec_chardev_driver = { @@ -410,7 +408,7 @@ static struct platform_driver cros_ec_chardev_driver = { .name = DRV_NAME, }, .probe = cros_ec_chardev_probe, - .remove = cros_ec_chardev_remove, + .remove_new = cros_ec_chardev_remove, }; module_platform_driver(cros_ec_chardev_driver); From f366fa0064ef3f7dda4ed8d25b41f8c96f5b2d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:15 +0200 Subject: [PATCH 123/396] platform/chrome: cros_ec_debugfs: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-3-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_debugfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index c876120e0ebc..091fdc154d79 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -533,14 +533,12 @@ remove_debugfs: return ret; } -static int cros_ec_debugfs_remove(struct platform_device *pd) +static void cros_ec_debugfs_remove(struct platform_device *pd) { struct cros_ec_dev *ec = dev_get_drvdata(pd->dev.parent); debugfs_remove_recursive(ec->debug_info->dir); cros_ec_cleanup_console_log(ec->debug_info); - - return 0; } static int __maybe_unused cros_ec_debugfs_suspend(struct device *dev) @@ -573,7 +571,7 @@ static struct platform_driver cros_ec_debugfs_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = cros_ec_debugfs_probe, - .remove = cros_ec_debugfs_remove, + .remove_new = cros_ec_debugfs_remove, }; module_platform_driver(cros_ec_debugfs_driver); From fa45583c3133ed4c910216cae38c49c65af70c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:16 +0200 Subject: [PATCH 124/396] platform/chrome: cros_ec_lightbar: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-4-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_lightbar.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 376425bbd8ff..6677cc6c4984 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -560,7 +560,7 @@ static int cros_ec_lightbar_probe(struct platform_device *pd) return ret; } -static int cros_ec_lightbar_remove(struct platform_device *pd) +static void cros_ec_lightbar_remove(struct platform_device *pd) { struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent); @@ -569,8 +569,6 @@ static int cros_ec_lightbar_remove(struct platform_device *pd) /* Let the EC take over the lightbar again. */ lb_manual_suspend_ctrl(ec_dev, 0); - - return 0; } static int __maybe_unused cros_ec_lightbar_resume(struct device *dev) @@ -603,7 +601,7 @@ static struct platform_driver cros_ec_lightbar_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = cros_ec_lightbar_probe, - .remove = cros_ec_lightbar_remove, + .remove_new = cros_ec_lightbar_remove, }; module_platform_driver(cros_ec_lightbar_driver); From e02944e85169b0350ea12264e530858250991546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:17 +0200 Subject: [PATCH 125/396] platform/chrome: cros_ec_lpc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-5-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_lpc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 356572452898..897090f0f26e 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -460,7 +460,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev) return 0; } -static int cros_ec_lpc_remove(struct platform_device *pdev) +static void cros_ec_lpc_remove(struct platform_device *pdev) { struct cros_ec_device *ec_dev = platform_get_drvdata(pdev); struct acpi_device *adev; @@ -471,8 +471,6 @@ static int cros_ec_lpc_remove(struct platform_device *pdev) cros_ec_lpc_acpi_notify); cros_ec_unregister(ec_dev); - - return 0; } static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = { @@ -580,7 +578,7 @@ static struct platform_driver cros_ec_lpc_driver = { .probe_type = PROBE_FORCE_SYNCHRONOUS, }, .probe = cros_ec_lpc_probe, - .remove = cros_ec_lpc_remove, + .remove_new = cros_ec_lpc_remove, }; static struct platform_device cros_ec_lpc_device = { From 6478e302409a0377cd6382c05b0ece22fc05c308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:18 +0200 Subject: [PATCH 126/396] platform/chrome: cros_ec_sysfs: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-6-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_sysfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index 09e3bf5e8ec6..93e67ab4af06 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -340,13 +340,11 @@ static int cros_ec_sysfs_probe(struct platform_device *pd) return ret; } -static int cros_ec_sysfs_remove(struct platform_device *pd) +static void cros_ec_sysfs_remove(struct platform_device *pd) { struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent); sysfs_remove_group(&ec_dev->class_dev.kobj, &cros_ec_attr_group); - - return 0; } static struct platform_driver cros_ec_sysfs_driver = { @@ -354,7 +352,7 @@ static struct platform_driver cros_ec_sysfs_driver = { .name = DRV_NAME, }, .probe = cros_ec_sysfs_probe, - .remove = cros_ec_sysfs_remove, + .remove_new = cros_ec_sysfs_remove, }; module_platform_driver(cros_ec_sysfs_driver); From 58b15196b0ef1be58d331d47d7787c1baca85e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:19 +0200 Subject: [PATCH 127/396] platform/chrome: cros_ec_vbc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-7-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_vbc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c index c859c862d7ac..2e4af10c7679 100644 --- a/drivers/platform/chrome/cros_ec_vbc.c +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -121,14 +121,12 @@ static int cros_ec_vbc_probe(struct platform_device *pd) return ret; } -static int cros_ec_vbc_remove(struct platform_device *pd) +static void cros_ec_vbc_remove(struct platform_device *pd) { struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent); sysfs_remove_group(&ec_dev->class_dev.kobj, &cros_ec_vbc_attr_group); - - return 0; } static struct platform_driver cros_ec_vbc_driver = { @@ -136,7 +134,7 @@ static struct platform_driver cros_ec_vbc_driver = { .name = DRV_NAME, }, .probe = cros_ec_vbc_probe, - .remove = cros_ec_vbc_remove, + .remove_new = cros_ec_vbc_remove, }; module_platform_driver(cros_ec_vbc_driver); From ea4bad2badb704a64556116e831979a5761da1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:20 +0200 Subject: [PATCH 128/396] platform/chrome: cros_typec_switch: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-8-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_typec_switch.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index 0eefdcf14d63..07a19386dc4e 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -297,12 +297,11 @@ static int cros_typec_switch_probe(struct platform_device *pdev) return cros_typec_register_switches(sdata); } -static int cros_typec_switch_remove(struct platform_device *pdev) +static void cros_typec_switch_remove(struct platform_device *pdev) { struct cros_typec_switch_data *sdata = platform_get_drvdata(pdev); cros_typec_unregister_switches(sdata); - return 0; } #ifdef CONFIG_ACPI @@ -319,7 +318,7 @@ static struct platform_driver cros_typec_switch_driver = { .acpi_match_table = ACPI_PTR(cros_typec_switch_acpi_id), }, .probe = cros_typec_switch_probe, - .remove = cros_typec_switch_remove, + .remove_new = cros_typec_switch_remove, }; module_platform_driver(cros_typec_switch_driver); From b6c1fea8355045d13b888743cba5a2cf8627d845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:21 +0200 Subject: [PATCH 129/396] platform/chrome: cros_usbpd_logger: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-9-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_usbpd_logger.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_usbpd_logger.c b/drivers/platform/chrome/cros_usbpd_logger.c index d16931203d82..f618757f8b32 100644 --- a/drivers/platform/chrome/cros_usbpd_logger.c +++ b/drivers/platform/chrome/cros_usbpd_logger.c @@ -219,14 +219,12 @@ static int cros_usbpd_logger_probe(struct platform_device *pd) return 0; } -static int cros_usbpd_logger_remove(struct platform_device *pd) +static void cros_usbpd_logger_remove(struct platform_device *pd) { struct logger_data *logger = platform_get_drvdata(pd); cancel_delayed_work_sync(&logger->log_work); destroy_workqueue(logger->log_workqueue); - - return 0; } static int __maybe_unused cros_usbpd_logger_resume(struct device *dev) @@ -257,7 +255,7 @@ static struct platform_driver cros_usbpd_logger_driver = { .pm = &cros_usbpd_logger_pm_ops, }, .probe = cros_usbpd_logger_probe, - .remove = cros_usbpd_logger_remove, + .remove_new = cros_usbpd_logger_remove, }; module_platform_driver(cros_usbpd_logger_driver); From b98362be7c92003903c9feefddeab7ca30392aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:22 +0200 Subject: [PATCH 130/396] platform/chrome: cros_usbpd_notify: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-10-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_usbpd_notify.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index 10670b6588e3..aacad022f21d 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -134,15 +134,13 @@ static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev) return 0; } -static int cros_usbpd_notify_remove_acpi(struct platform_device *pdev) +static void cros_usbpd_notify_remove_acpi(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acpi_device *adev = ACPI_COMPANION(dev); acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, cros_usbpd_notify_acpi); - - return 0; } static const struct acpi_device_id cros_usbpd_notify_acpi_device_ids[] = { @@ -157,7 +155,7 @@ static struct platform_driver cros_usbpd_notify_acpi_driver = { .acpi_match_table = cros_usbpd_notify_acpi_device_ids, }, .probe = cros_usbpd_notify_probe_acpi, - .remove = cros_usbpd_notify_remove_acpi, + .remove_new = cros_usbpd_notify_remove_acpi, }; #endif /* CONFIG_ACPI */ @@ -209,7 +207,7 @@ static int cros_usbpd_notify_probe_plat(struct platform_device *pdev) return 0; } -static int cros_usbpd_notify_remove_plat(struct platform_device *pdev) +static void cros_usbpd_notify_remove_plat(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent); @@ -218,8 +216,6 @@ static int cros_usbpd_notify_remove_plat(struct platform_device *pdev) blocking_notifier_chain_unregister(&ecdev->ec_dev->event_notifier, &pdnotify->nb); - - return 0; } static struct platform_driver cros_usbpd_notify_plat_driver = { @@ -227,7 +223,7 @@ static struct platform_driver cros_usbpd_notify_plat_driver = { .name = DRV_NAME, }, .probe = cros_usbpd_notify_probe_plat, - .remove = cros_usbpd_notify_remove_plat, + .remove_new = cros_usbpd_notify_remove_plat, }; static int __init cros_usbpd_notify_init(void) From 48648504e488f9affbb2bbe8b48e4f5f724a89ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:23 +0200 Subject: [PATCH 131/396] platform/chrome/wilco_ec: core: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-11-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/wilco_ec/core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c index d6a994bdc182..9b59a1bed286 100644 --- a/drivers/platform/chrome/wilco_ec/core.c +++ b/drivers/platform/chrome/wilco_ec/core.c @@ -132,7 +132,7 @@ unregister_debugfs: return ret; } -static int wilco_ec_remove(struct platform_device *pdev) +static void wilco_ec_remove(struct platform_device *pdev) { struct wilco_ec_device *ec = platform_get_drvdata(pdev); @@ -142,7 +142,6 @@ static int wilco_ec_remove(struct platform_device *pdev) platform_device_unregister(ec->rtc_pdev); if (ec->debugfs_pdev) platform_device_unregister(ec->debugfs_pdev); - return 0; } static const struct acpi_device_id wilco_ec_acpi_device_ids[] = { @@ -157,7 +156,7 @@ static struct platform_driver wilco_ec_driver = { .acpi_match_table = wilco_ec_acpi_device_ids, }, .probe = wilco_ec_probe, - .remove = wilco_ec_remove, + .remove_new = wilco_ec_remove, }; module_platform_driver(wilco_ec_driver); From 1fca58f347d8a958bd708a98c0e478e65ab48408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:24 +0200 Subject: [PATCH 132/396] platform/chrome/wilco_ec: debugfs: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-12-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/wilco_ec/debugfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/wilco_ec/debugfs.c b/drivers/platform/chrome/wilco_ec/debugfs.c index 7a13f13b16cd..93c11f81ca45 100644 --- a/drivers/platform/chrome/wilco_ec/debugfs.c +++ b/drivers/platform/chrome/wilco_ec/debugfs.c @@ -260,11 +260,9 @@ static int wilco_ec_debugfs_probe(struct platform_device *pdev) return 0; } -static int wilco_ec_debugfs_remove(struct platform_device *pdev) +static void wilco_ec_debugfs_remove(struct platform_device *pdev) { debugfs_remove_recursive(debug_info->dir); - - return 0; } static struct platform_driver wilco_ec_debugfs_driver = { @@ -272,7 +270,7 @@ static struct platform_driver wilco_ec_debugfs_driver = { .name = DRV_NAME, }, .probe = wilco_ec_debugfs_probe, - .remove = wilco_ec_debugfs_remove, + .remove_new = wilco_ec_debugfs_remove, }; module_platform_driver(wilco_ec_debugfs_driver); From 7396a5b980fdeb2cb97136db45405b4fb5d21dfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:25 +0200 Subject: [PATCH 133/396] platform/chrome/wilco_ec: telemetry: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-13-u.kleine-koenig@pengutronix.de Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/wilco_ec/telemetry.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/wilco_ec/telemetry.c b/drivers/platform/chrome/wilco_ec/telemetry.c index 54708aa6c700..253098bace63 100644 --- a/drivers/platform/chrome/wilco_ec/telemetry.c +++ b/drivers/platform/chrome/wilco_ec/telemetry.c @@ -400,20 +400,18 @@ static int telem_device_probe(struct platform_device *pdev) return 0; } -static int telem_device_remove(struct platform_device *pdev) +static void telem_device_remove(struct platform_device *pdev) { struct telem_device_data *dev_data = platform_get_drvdata(pdev); cdev_device_del(&dev_data->cdev, &dev_data->dev); ida_simple_remove(&telem_ida, MINOR(dev_data->dev.devt)); put_device(&dev_data->dev); - - return 0; } static struct platform_driver telem_driver = { .probe = telem_device_probe, - .remove = telem_device_remove, + .remove_new = telem_device_remove, .driver = { .name = DRV_NAME, }, From 18801efed74a671f5c3bd1869739854cf2a5568f Mon Sep 17 00:00:00 2001 From: Fernando Eckhardt Valle Date: Tue, 26 Sep 2023 17:21:44 -0300 Subject: [PATCH 134/396] platform/x86: thinkpad_acpi: sysfs interface to auxmac MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer Thinkpads have a feature called MAC Address Pass-through. This patch provides a sysfs interface that userspace can use to get this auxiliary mac address. Signed-off-by: Fernando Eckhardt Valle Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20230926202144.5906-1-fevalle@ipt.br Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../admin-guide/laptops/thinkpad-acpi.rst | 20 +++++ drivers/platform/x86/thinkpad_acpi.c | 88 +++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst index e27a1c3f634e..98d304010170 100644 --- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst +++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst @@ -53,6 +53,7 @@ detailed description): - Lap mode sensor - Setting keyboard language - WWAN Antenna type + - Auxmac A compatibility table by model and feature is maintained on the web site, http://ibm-acpi.sf.net/. I appreciate any success or failure @@ -1511,6 +1512,25 @@ Currently 2 antenna types are supported as mentioned below: The property is read-only. If the platform doesn't have support the sysfs class is not created. +Auxmac +------ + +sysfs: auxmac + +Some newer Thinkpads have a feature called MAC Address Pass-through. This +feature is implemented by the system firmware to provide a system unique MAC, +that can override a dock or USB ethernet dongle MAC, when connected to a +network. This property enables user-space to easily determine the MAC address +if the feature is enabled. + +The values of this auxiliary MAC are: + + cat /sys/devices/platform/thinkpad_acpi/auxmac + +If the feature is disabled, the value will be 'disabled'. + +This property is read-only. + Adaptive keyboard ----------------- diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d70c89d32534..9c19624a7454 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10785,6 +10785,89 @@ static struct ibm_struct dprc_driver_data = { .name = "dprc", }; +/* + * Auxmac + * + * This auxiliary mac address is enabled in the bios through the + * MAC Address Pass-through feature. In most cases, there are three + * possibilities: Internal Mac, Second Mac, and disabled. + * + */ + +#define AUXMAC_LEN 12 +#define AUXMAC_START 9 +#define AUXMAC_STRLEN 22 +#define AUXMAC_BEGIN_MARKER 8 +#define AUXMAC_END_MARKER 21 + +static char auxmac[AUXMAC_LEN + 1]; + +static int auxmac_init(struct ibm_init_struct *iibm) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + + status = acpi_evaluate_object(NULL, "\\MACA", NULL, &buffer); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + obj = buffer.pointer; + + if (obj->type != ACPI_TYPE_STRING || obj->string.length != AUXMAC_STRLEN) { + pr_info("Invalid buffer for MAC address pass-through.\n"); + goto auxmacinvalid; + } + + if (obj->string.pointer[AUXMAC_BEGIN_MARKER] != '#' || + obj->string.pointer[AUXMAC_END_MARKER] != '#') { + pr_info("Invalid header for MAC address pass-through.\n"); + goto auxmacinvalid; + } + + if (strncmp(obj->string.pointer + AUXMAC_START, "XXXXXXXXXXXX", AUXMAC_LEN) != 0) + strscpy(auxmac, obj->string.pointer + AUXMAC_START, sizeof(auxmac)); + else + strscpy(auxmac, "disabled", sizeof(auxmac)); + +free: + kfree(obj); + return 0; + +auxmacinvalid: + strscpy(auxmac, "unavailable", sizeof(auxmac)); + goto free; +} + +static struct ibm_struct auxmac_data = { + .name = "auxmac", +}; + +static ssize_t auxmac_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%s\n", auxmac); +} +static DEVICE_ATTR_RO(auxmac); + +static umode_t auxmac_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + return auxmac[0] == 0 ? 0 : attr->mode; +} + +static struct attribute *auxmac_attributes[] = { + &dev_attr_auxmac.attr, + NULL +}; + +static const struct attribute_group auxmac_attr_group = { + .is_visible = auxmac_attr_is_visible, + .attrs = auxmac_attributes, +}; + /* --------------------------------------------------------------------- */ static struct attribute *tpacpi_driver_attributes[] = { @@ -10843,6 +10926,7 @@ static const struct attribute_group *tpacpi_groups[] = { &proxsensor_attr_group, &kbdlang_attr_group, &dprc_attr_group, + &auxmac_attr_group, NULL, }; @@ -11414,6 +11498,10 @@ static struct ibm_init_struct ibms_init[] __initdata = { .init = tpacpi_dprc_init, .data = &dprc_driver_data, }, + { + .init = auxmac_init, + .data = &auxmac_data, + }, }; static int __init set_ibm_param(const char *val, const struct kernel_param *kp) From a6cff4212984010c119263593c0a249e15ad5caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:27 +0200 Subject: [PATCH 135/396] platform/mellanox: mlxbf-bootctl: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-15-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/mellanox/mlxbf-bootctl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/mellanox/mlxbf-bootctl.c b/drivers/platform/mellanox/mlxbf-bootctl.c index 4ee7bb431b7c..1ac7dab22c63 100644 --- a/drivers/platform/mellanox/mlxbf-bootctl.c +++ b/drivers/platform/mellanox/mlxbf-bootctl.c @@ -1028,17 +1028,15 @@ static int mlxbf_bootctl_probe(struct platform_device *pdev) return ret; } -static int mlxbf_bootctl_remove(struct platform_device *pdev) +static void mlxbf_bootctl_remove(struct platform_device *pdev) { sysfs_remove_bin_file(&pdev->dev.kobj, &mlxbf_bootctl_bootfifo_sysfs_attr); - - return 0; } static struct platform_driver mlxbf_bootctl_driver = { .probe = mlxbf_bootctl_probe, - .remove = mlxbf_bootctl_remove, + .remove_new = mlxbf_bootctl_remove, .driver = { .name = "mlxbf-bootctl", .dev_groups = mlxbf_bootctl_groups, From db971cf26014948d642522dae9a01968d009751c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:28 +0200 Subject: [PATCH 136/396] platform/mellanox: mlxbf-tmfifo: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-16-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/mellanox/mlxbf-tmfifo.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index f3696a54a2bd..69729ba8f505 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -1361,13 +1361,11 @@ fail: } /* Device remove function. */ -static int mlxbf_tmfifo_remove(struct platform_device *pdev) +static void mlxbf_tmfifo_remove(struct platform_device *pdev) { struct mlxbf_tmfifo *fifo = platform_get_drvdata(pdev); mlxbf_tmfifo_cleanup(fifo); - - return 0; } static const struct acpi_device_id mlxbf_tmfifo_acpi_match[] = { @@ -1378,7 +1376,7 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_tmfifo_acpi_match); static struct platform_driver mlxbf_tmfifo_driver = { .probe = mlxbf_tmfifo_probe, - .remove = mlxbf_tmfifo_remove, + .remove_new = mlxbf_tmfifo_remove, .driver = { .name = "bf-tmfifo", .acpi_match_table = mlxbf_tmfifo_acpi_match, From a62507eb57124f4889b97de9917a164bf3109aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:29 +0200 Subject: [PATCH 137/396] platform/mellanox: mlxreg-hotplug: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-17-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/mellanox/mlxreg-hotplug.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index eb5ad35274dd..5c022b258f91 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -786,15 +786,13 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) return 0; } -static int mlxreg_hotplug_remove(struct platform_device *pdev) +static void mlxreg_hotplug_remove(struct platform_device *pdev) { struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev); /* Clean interrupts setup. */ mlxreg_hotplug_unset_irq(priv); devm_free_irq(&pdev->dev, priv->irq, priv); - - return 0; } static struct platform_driver mlxreg_hotplug_driver = { @@ -802,7 +800,7 @@ static struct platform_driver mlxreg_hotplug_driver = { .name = "mlxreg-hotplug", }, .probe = mlxreg_hotplug_probe, - .remove = mlxreg_hotplug_remove, + .remove_new = mlxreg_hotplug_remove, }; module_platform_driver(mlxreg_hotplug_driver); From e0489bb002ff581f9439de2d22b49e140e73e6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:30 +0200 Subject: [PATCH 138/396] platform/mellanox: mlxreg-io: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-18-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/mellanox/mlxreg-io.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c index 83ba037408cd..ee7bd623ba44 100644 --- a/drivers/platform/mellanox/mlxreg-io.c +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -263,13 +263,11 @@ static int mlxreg_io_probe(struct platform_device *pdev) return 0; } -static int mlxreg_io_remove(struct platform_device *pdev) +static void mlxreg_io_remove(struct platform_device *pdev) { struct mlxreg_io_priv_data *priv = dev_get_drvdata(&pdev->dev); mutex_destroy(&priv->io_lock); - - return 0; } static struct platform_driver mlxreg_io_driver = { @@ -277,7 +275,7 @@ static struct platform_driver mlxreg_io_driver = { .name = "mlxreg-io", }, .probe = mlxreg_io_probe, - .remove = mlxreg_io_remove, + .remove_new = mlxreg_io_remove, }; module_platform_driver(mlxreg_io_driver); From cfae9860ca990c5a642da85e01e0eb2e7dd9db35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:31 +0200 Subject: [PATCH 139/396] platform/mellanox: mlxreg-lc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-19-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/mellanox/mlxreg-lc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index 8d833836a6d3..43d119e3a473 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -907,7 +907,7 @@ i2c_get_adapter_fail: return err; } -static int mlxreg_lc_remove(struct platform_device *pdev) +static void mlxreg_lc_remove(struct platform_device *pdev) { struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev); struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev); @@ -921,7 +921,7 @@ static int mlxreg_lc_remove(struct platform_device *pdev) * is nothing to remove. */ if (!data->notifier || !data->notifier->handle) - return 0; + return; /* Clear event notification callback and handle. */ data->notifier->user_handler = NULL; @@ -940,13 +940,11 @@ static int mlxreg_lc_remove(struct platform_device *pdev) i2c_put_adapter(data->hpdev.adapter); data->hpdev.adapter = NULL; } - - return 0; } static struct platform_driver mlxreg_lc_driver = { .probe = mlxreg_lc_probe, - .remove = mlxreg_lc_remove, + .remove_new = mlxreg_lc_remove, .driver = { .name = "mlxreg-lc", }, From 61e2e9ee39d921756050dafeb91537284139f611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:32 +0200 Subject: [PATCH 140/396] platform/mellanox: nvsw-sn2201: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-20-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/mellanox/nvsw-sn2201.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/mellanox/nvsw-sn2201.c b/drivers/platform/mellanox/nvsw-sn2201.c index 75b699676ca6..3ef655591424 100644 --- a/drivers/platform/mellanox/nvsw-sn2201.c +++ b/drivers/platform/mellanox/nvsw-sn2201.c @@ -1217,7 +1217,7 @@ static int nvsw_sn2201_probe(struct platform_device *pdev) return nvsw_sn2201_config_pre_init(nvsw_sn2201); } -static int nvsw_sn2201_remove(struct platform_device *pdev) +static void nvsw_sn2201_remove(struct platform_device *pdev) { struct nvsw_sn2201 *nvsw_sn2201 = platform_get_drvdata(pdev); @@ -1239,8 +1239,6 @@ static int nvsw_sn2201_remove(struct platform_device *pdev) /* Unregister I2C controller. */ if (nvsw_sn2201->pdev_i2c) platform_device_unregister(nvsw_sn2201->pdev_i2c); - - return 0; } static const struct acpi_device_id nvsw_sn2201_acpi_ids[] = { @@ -1252,7 +1250,7 @@ MODULE_DEVICE_TABLE(acpi, nvsw_sn2201_acpi_ids); static struct platform_driver nvsw_sn2201_driver = { .probe = nvsw_sn2201_probe, - .remove = nvsw_sn2201_remove, + .remove_new = nvsw_sn2201_remove, .driver = { .name = "nvsw-sn2201", .acpi_match_table = nvsw_sn2201_acpi_ids, From 3e29812e6e172ba772761e6995753b729e8a6f77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:33 +0200 Subject: [PATCH 141/396] platform/x86/intel: bytcrc_pwrsrc: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-21-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/bytcrc_pwrsrc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/intel/bytcrc_pwrsrc.c b/drivers/platform/x86/intel/bytcrc_pwrsrc.c index 8a022b90d12d..418b71af27ff 100644 --- a/drivers/platform/x86/intel/bytcrc_pwrsrc.c +++ b/drivers/platform/x86/intel/bytcrc_pwrsrc.c @@ -158,17 +158,16 @@ static int crc_pwrsrc_probe(struct platform_device *pdev) return 0; } -static int crc_pwrsrc_remove(struct platform_device *pdev) +static void crc_pwrsrc_remove(struct platform_device *pdev) { struct crc_pwrsrc_data *data = platform_get_drvdata(pdev); debugfs_remove_recursive(data->debug_dentry); - return 0; } static struct platform_driver crc_pwrsrc_driver = { .probe = crc_pwrsrc_probe, - .remove = crc_pwrsrc_remove, + .remove_new = crc_pwrsrc_remove, .driver = { .name = "crystal_cove_pwrsrc", }, From 1348317db770681cde4c6ac04afd75a1b0a99098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:34 +0200 Subject: [PATCH 142/396] platform/x86: mlx-platform: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-22-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/mlx-platform.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 3d96dbf79a72..03ccadee35d0 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -6606,7 +6606,7 @@ fail_alloc: return err; } -static int mlxplat_remove(struct platform_device *pdev) +static void mlxplat_remove(struct platform_device *pdev) { struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); @@ -6617,7 +6617,6 @@ static int mlxplat_remove(struct platform_device *pdev) mlxplat_pre_exit(priv); mlxplat_i2c_main_exit(priv); mlxplat_post_exit(); - return 0; } static const struct acpi_device_id mlxplat_acpi_table[] = { @@ -6633,7 +6632,7 @@ static struct platform_driver mlxplat_driver = { .probe_type = PROBE_FORCE_SYNCHRONOUS, }, .probe = mlxplat_probe, - .remove = mlxplat_remove, + .remove_new = mlxplat_remove, }; static int __init mlxplat_init(void) From 9e6b44d43e31160bfba568244c785f439ac33d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:35 +0200 Subject: [PATCH 143/396] platform/x86: sel3350-platform: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-23-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/sel3350-platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/sel3350-platform.c b/drivers/platform/x86/sel3350-platform.c index fa267d0d3778..d09e976e7148 100644 --- a/drivers/platform/x86/sel3350-platform.c +++ b/drivers/platform/x86/sel3350-platform.c @@ -218,15 +218,13 @@ err_platform: return rs; } -static int sel3350_remove(struct platform_device *pdev) +static void sel3350_remove(struct platform_device *pdev) { struct sel3350_data *sel3350 = platform_get_drvdata(pdev); platform_device_unregister(sel3350->leds_pdev); gpiod_remove_lookup_table(&sel3350_gpios_table); gpiod_remove_lookup_table(&sel3350_leds_table); - - return 0; } static const struct acpi_device_id sel3350_device_ids[] = { @@ -237,7 +235,7 @@ MODULE_DEVICE_TABLE(acpi, sel3350_device_ids); static struct platform_driver sel3350_platform_driver = { .probe = sel3350_probe, - .remove = sel3350_remove, + .remove_new = sel3350_remove, .driver = { .name = "sel3350-platform", .acpi_match_table = sel3350_device_ids, From 0580422560e2b93fe2e343d8438823824729a574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:36 +0200 Subject: [PATCH 144/396] platform/x86/siemens: simatic-ipc-batt: Simplify simatic_ipc_batt_remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of unconditionally returning zero, let simatic_ipc_batt_remove() return no value. This is a preparation to convert the drivers using this function to struct platform_driver::remove_new(). Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-24-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c | 4 +++- .../platform/x86/siemens/simatic-ipc-batt-elkhartlake.c | 4 +++- drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c | 4 +++- drivers/platform/x86/siemens/simatic-ipc-batt.c | 7 ++++--- drivers/platform/x86/siemens/simatic-ipc-batt.h | 4 ++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c index 8a67979d8f96..3e22a6bc9118 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c @@ -27,7 +27,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_127e = { static int simatic_ipc_batt_apollolake_remove(struct platform_device *pdev) { - return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e); + simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e); + + return 0; } static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c index 607d033911a2..9e08c659f27d 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c @@ -27,7 +27,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_21a = { static int simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev) { - return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a); + simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a); + + return 0; } static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c index a66107e0fe1e..19c302a68911 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c @@ -47,7 +47,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_59a = { static int simatic_ipc_batt_f7188x_remove(struct platform_device *pdev) { - return simatic_ipc_batt_remove(pdev, batt_lookup_table); + simatic_ipc_batt_remove(pdev, batt_lookup_table); + + return 0; } static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.c b/drivers/platform/x86/siemens/simatic-ipc-batt.c index ef28c806b383..07cd4944de32 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt.c @@ -146,10 +146,9 @@ static const struct hwmon_chip_info simatic_ipc_batt_chip_info = { .info = simatic_ipc_batt_info, }; -int simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table) +void simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table) { gpiod_remove_lookup_table(table); - return 0; } EXPORT_SYMBOL_GPL(simatic_ipc_batt_remove); @@ -230,7 +229,9 @@ EXPORT_SYMBOL_GPL(simatic_ipc_batt_probe); static int simatic_ipc_batt_io_remove(struct platform_device *pdev) { - return simatic_ipc_batt_remove(pdev, NULL); + simatic_ipc_batt_remove(pdev, NULL); + + return 0; } static int simatic_ipc_batt_io_probe(struct platform_device *pdev) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.h b/drivers/platform/x86/siemens/simatic-ipc-batt.h index 4545cd3e3026..89891db26a2c 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt.h +++ b/drivers/platform/x86/siemens/simatic-ipc-batt.h @@ -14,7 +14,7 @@ int simatic_ipc_batt_probe(struct platform_device *pdev, struct gpiod_lookup_table *table); -int simatic_ipc_batt_remove(struct platform_device *pdev, - struct gpiod_lookup_table *table); +void simatic_ipc_batt_remove(struct platform_device *pdev, + struct gpiod_lookup_table *table); #endif /* _SIMATIC_IPC_BATT_H */ From 2f46e417384e0412c5e239fe6a84ace7d955b33e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:37 +0200 Subject: [PATCH 145/396] platform/x86/siemens: simatic-ipc-batt: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-25-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/siemens/simatic-ipc-batt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.c b/drivers/platform/x86/siemens/simatic-ipc-batt.c index 07cd4944de32..c6dd263b4ee3 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt.c @@ -227,11 +227,9 @@ out: } EXPORT_SYMBOL_GPL(simatic_ipc_batt_probe); -static int simatic_ipc_batt_io_remove(struct platform_device *pdev) +static void simatic_ipc_batt_io_remove(struct platform_device *pdev) { simatic_ipc_batt_remove(pdev, NULL); - - return 0; } static int simatic_ipc_batt_io_probe(struct platform_device *pdev) @@ -241,7 +239,7 @@ static int simatic_ipc_batt_io_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_io_probe, - .remove = simatic_ipc_batt_io_remove, + .remove_new = simatic_ipc_batt_io_remove, .driver = { .name = KBUILD_MODNAME, }, From e139d97f049a8d924f91700a9a5f28c8bfe676d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:38 +0200 Subject: [PATCH 146/396] platform/x86/siemens: simatic-ipc-batt-apollolake: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-26-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c index 3e22a6bc9118..31a139d87d9a 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c @@ -25,11 +25,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_127e = { }, }; -static int simatic_ipc_batt_apollolake_remove(struct platform_device *pdev) +static void simatic_ipc_batt_apollolake_remove(struct platform_device *pdev) { simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e); - - return 0; } static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev) @@ -39,7 +37,7 @@ static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_apollolake_probe, - .remove = simatic_ipc_batt_apollolake_remove, + .remove_new = simatic_ipc_batt_apollolake_remove, .driver = { .name = KBUILD_MODNAME, }, From 0d643dcd78423afad7204a280dc25dc67bcd85c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:39 +0200 Subject: [PATCH 147/396] platform/x86/siemens: simatic-ipc-batt-elkhartlake: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-27-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c index 9e08c659f27d..a7676f224075 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c @@ -25,11 +25,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_21a = { }, }; -static int simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev) +static void simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev) { simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a); - - return 0; } static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev) @@ -39,7 +37,7 @@ static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_elkhartlake_probe, - .remove = simatic_ipc_batt_elkhartlake_remove, + .remove_new = simatic_ipc_batt_elkhartlake_remove, .driver = { .name = KBUILD_MODNAME, }, From 49d371ab9d2c850867332b469fa6b3a2d5cf338c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 27 Sep 2023 10:10:40 +0200 Subject: [PATCH 148/396] platform/x86/siemens: simatic-ipc-batt-f7188x: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230927081040.2198742-28-u.kleine-koenig@pengutronix.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c index 19c302a68911..5e77e05fdb5d 100644 --- a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c @@ -45,11 +45,9 @@ static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_59a = { } }; -static int simatic_ipc_batt_f7188x_remove(struct platform_device *pdev) +static void simatic_ipc_batt_f7188x_remove(struct platform_device *pdev) { simatic_ipc_batt_remove(pdev, batt_lookup_table); - - return 0; } static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev) @@ -75,7 +73,7 @@ static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev) static struct platform_driver simatic_ipc_batt_driver = { .probe = simatic_ipc_batt_f7188x_probe, - .remove = simatic_ipc_batt_f7188x_remove, + .remove_new = simatic_ipc_batt_f7188x_remove, .driver = { .name = KBUILD_MODNAME, }, From 8f8e9b7388514d937843337140f18ceb0f3da6eb Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 27 Sep 2023 15:41:05 +0300 Subject: [PATCH 149/396] power: supply: mm8013: Fix an error checking issue in mm8013_checkdevice() There is a missing "ret = " assignment so this checks the same "ret" value twice. Fixes: c75f4bf6800b ("power: supply: Introduce MM8013 fuel gauge driver") Signed-off-by: Dan Carpenter Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/c46b4408-bf1d-408d-9e6b-16b0ad272532@moroto.mountain Signed-off-by: Sebastian Reichel --- drivers/power/supply/mm8013.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/mm8013.c b/drivers/power/supply/mm8013.c index 29fd65fe6545..caa272b03564 100644 --- a/drivers/power/supply/mm8013.c +++ b/drivers/power/supply/mm8013.c @@ -53,7 +53,7 @@ static int mm8013_checkdevice(struct mm8013_chip *chip) if (ret < 0) return ret; - regmap_read(chip->regmap, REG_BATID, &val); + ret = regmap_read(chip->regmap, REG_BATID, &val); if (ret < 0) return ret; From 15a4e422f3c9b041261b6810c90ce09d4ebe2a14 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 26 Sep 2023 11:44:42 -0500 Subject: [PATCH 150/396] dt-bindings: power: supply: sbs-manager: Add missing unevaluatedProperties on child node schemas Just as unevaluatedProperties or additionalProperties are required at the top level of schemas, they should (and will) also be required for child node schemas. That ensures only documented properties are present for any node. Add unevaluatedProperties as needed, and then add any missing properties flagged by the addition. Signed-off-by: Rob Herring Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20230926164446.101327-1-robh@kernel.org Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/supply/sbs,sbs-manager.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.yaml b/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.yaml index f255f3858d08..2e21846463ba 100644 --- a/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.yaml +++ b/Documentation/devicetree/bindings/power/supply/sbs,sbs-manager.yaml @@ -47,6 +47,12 @@ patternProperties: "^i2c@[1-4]$": type: object $ref: /schemas/i2c/i2c-controller.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 1 + maximum: 4 examples: - | From 0ce51459c8353b2b18ad3a430dbebf29af8b579c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 29 Sep 2023 19:39:00 +0200 Subject: [PATCH 151/396] power: supply: core: remove opencoded string_lower() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit string_lower from string_helpers.h can be used to modify the string in-place. Use it to get rid of the custom str_to_lower(). Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20230929-power_supply-string_lower-v1-1-3141a2634d53@weissschuh.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/power_supply_sysfs.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 06e5b6b0e255..09bf9a094c77 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "power_supply.h" @@ -398,14 +399,6 @@ static const struct attribute_group *power_supply_attr_groups[] = { NULL, }; -static void str_to_lower(char *str) -{ - while (*str) { - *str = tolower(*str); - str++; - } -} - void power_supply_init_attrs(struct device_type *dev_type) { int i; @@ -420,7 +413,8 @@ void power_supply_init_attrs(struct device_type *dev_type) __func__, i); sprintf(power_supply_attrs[i].attr_name, "_err_%d", i); } else { - str_to_lower(power_supply_attrs[i].attr_name); + string_lower(power_supply_attrs[i].attr_name, + power_supply_attrs[i].attr_name); } attr = &power_supply_attrs[i].dev_attr; From d484366854f535fa25a863a575c5b6a86f4f4bdc Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:53:45 -0700 Subject: [PATCH 152/396] hte: Annotate struct hte_device with __counted_by Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct hte_device. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Dipen Patel Cc: timestamp@lists.linux.dev Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Reviewed-by: Dipen Patel Reviewed-by: Justin Stitt Signed-off-by: Dipen Patel --- drivers/hte/hte.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hte/hte.c b/drivers/hte/hte.c index 598a716b7364..1fd8d2d4528b 100644 --- a/drivers/hte/hte.c +++ b/drivers/hte/hte.c @@ -88,7 +88,7 @@ struct hte_device { struct list_head list; struct hte_chip *chip; struct module *owner; - struct hte_ts_info ei[]; + struct hte_ts_info ei[] __counted_by(nlines); }; #ifdef CONFIG_DEBUG_FS From 63137bee5a7a45df82d948e39b3b4c07d8b1ce03 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Sep 2023 11:46:04 +0200 Subject: [PATCH 153/396] hte: allow building modules with COMPILE_TEST enabled Allow building all HTE modules with COMPILE_TEST Kconfig option enabled. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij Acked-by: Dipen Patel Signed-off-by: Dipen Patel --- drivers/hte/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hte/Kconfig b/drivers/hte/Kconfig index cf29e0218bae..083e67492bf2 100644 --- a/drivers/hte/Kconfig +++ b/drivers/hte/Kconfig @@ -16,7 +16,7 @@ if HTE config HTE_TEGRA194 tristate "NVIDIA Tegra194 HTE Support" - depends on ARCH_TEGRA_194_SOC + depends on (ARCH_TEGRA_194_SOC || COMPILE_TEST) help Enable this option for integrated hardware timestamping engine also known as generic timestamping engine (GTE) support on NVIDIA Tegra194 @@ -25,7 +25,7 @@ config HTE_TEGRA194 config HTE_TEGRA194_TEST tristate "NVIDIA Tegra194 HTE Test" - depends on HTE_TEGRA194 + depends on (HTE_TEGRA194 || COMPILE_TEST) help The NVIDIA Tegra194 GTE test driver demonstrates how to use HTE framework to timestamp GPIO and LIC IRQ lines. From a88f6ef679579256ec9561fb1359332df5eaa94d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 2 Oct 2023 17:34:25 -0700 Subject: [PATCH 154/396] platform/chrome: cros_ec_typec: Use semi-colons instead of commas These should be semi-colons so that one statement is per line. Cc: Prashant Malani Signed-off-by: Stephen Boyd Acked-by: Prashant Malani Link: https://lore.kernel.org/r/20231003003429.1378109-2-swboyd@chromium.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_typec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index d0b4d3fc40ed..82e7d08b52c7 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -271,9 +271,9 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec, struct typec_altmode *amode; /* All PD capable CrOS devices are assumed to support DP altmode. */ - desc.svid = USB_TYPEC_DP_SID, - desc.mode = USB_TYPEC_DP_MODE, - desc.vdo = DP_PORT_VDO, + desc.svid = USB_TYPEC_DP_SID; + desc.mode = USB_TYPEC_DP_MODE; + desc.vdo = DP_PORT_VDO; amode = typec_port_register_altmode(port->port, &desc); if (IS_ERR(amode)) return PTR_ERR(amode); @@ -287,8 +287,8 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec, * here for now. */ memset(&desc, 0, sizeof(desc)); - desc.svid = USB_TYPEC_TBT_SID, - desc.mode = TYPEC_ANY_MODE, + desc.svid = USB_TYPEC_TBT_SID; + desc.mode = TYPEC_ANY_MODE; amode = typec_port_register_altmode(port->port, &desc); if (IS_ERR(amode)) return PTR_ERR(amode); From 2b055bf8ac8492111a62177764e54e0d2614c6b8 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 2 Oct 2023 17:34:26 -0700 Subject: [PATCH 155/396] platform/chrome: cros_ec_typec: Use dev_err_probe() more There's some debug prints here that can be upgraded to dev_err_probe() so that we don't have to fish out the error messages when a true error happens. If they're simply probe defers then the kernel will keep silent but if they're true errors we'll see the errors in the logs. Cc: Prashant Malani Signed-off-by: Stephen Boyd Acked-by: Prashant Malani Link: https://lore.kernel.org/r/20231003003429.1378109-3-swboyd@chromium.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_typec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 82e7d08b52c7..67000e4a8082 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -80,28 +80,28 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port, port->mux = fwnode_typec_mux_get(fwnode); if (IS_ERR(port->mux)) { ret = PTR_ERR(port->mux); - dev_dbg(dev, "Mux handle not found: %d.\n", ret); + dev_err_probe(dev, ret, "Mux handle not found\n"); goto mux_err; } port->retimer = fwnode_typec_retimer_get(fwnode); if (IS_ERR(port->retimer)) { ret = PTR_ERR(port->retimer); - dev_dbg(dev, "Retimer handle not found: %d.\n", ret); + dev_err_probe(dev, ret, "Retimer handle not found\n"); goto retimer_sw_err; } port->ori_sw = fwnode_typec_switch_get(fwnode); if (IS_ERR(port->ori_sw)) { ret = PTR_ERR(port->ori_sw); - dev_dbg(dev, "Orientation switch handle not found: %d\n", ret); + dev_err_probe(dev, ret, "Orientation switch handle not found\n"); goto ori_sw_err; } port->role_sw = fwnode_usb_role_switch_get(fwnode); if (IS_ERR(port->role_sw)) { ret = PTR_ERR(port->role_sw); - dev_dbg(dev, "USB role switch handle not found: %d\n", ret); + dev_err_probe(dev, ret, "USB role switch handle not found\n"); goto role_sw_err; } From 14e7c01cc3494b75c3ff1d099a2f5f76b1fcb01d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 2 Oct 2023 17:34:27 -0700 Subject: [PATCH 156/396] platform/chrome: cros_typec_vdm: Mark port_amode_ops const Mark this struct of functions const so it moves to RO memory. Cc: Prashant Malani Signed-off-by: Stephen Boyd Acked-by: Prashant Malani Link: https://lore.kernel.org/r/20231003003429.1378109-4-swboyd@chromium.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_typec_vdm.c | 2 +- drivers/platform/chrome/cros_typec_vdm.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/chrome/cros_typec_vdm.c b/drivers/platform/chrome/cros_typec_vdm.c index 20515ee0a20e..3f632fd35000 100644 --- a/drivers/platform/chrome/cros_typec_vdm.c +++ b/drivers/platform/chrome/cros_typec_vdm.c @@ -142,7 +142,7 @@ static int cros_typec_port_amode_vdm(struct typec_altmode *amode, const u32 hdr, sizeof(req), NULL, 0); } -struct typec_altmode_ops port_amode_ops = { +const struct typec_altmode_ops port_amode_ops = { .enter = cros_typec_port_amode_enter, .vdm = cros_typec_port_amode_vdm, }; diff --git a/drivers/platform/chrome/cros_typec_vdm.h b/drivers/platform/chrome/cros_typec_vdm.h index 95a6a75d32b6..631bd2ce4b00 100644 --- a/drivers/platform/chrome/cros_typec_vdm.h +++ b/drivers/platform/chrome/cros_typec_vdm.h @@ -5,7 +5,7 @@ #include -extern struct typec_altmode_ops port_amode_ops; +extern const struct typec_altmode_ops port_amode_ops; void cros_typec_handle_vdm_attention(struct cros_typec_data *typec, int port_num); void cros_typec_handle_vdm_response(struct cros_typec_data *typec, int port_num); From 2f3dd39e2b492bec366487a2c9bcbdbd7792f77c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 2 Oct 2023 17:34:28 -0700 Subject: [PATCH 157/396] platform/chrome: cros_ec_proto: Mark outdata as const The 'outdata' is copied to the data buffer in cros_ec_cmd() before being sent over to the EC. Mark the argument as const so that callers can pass const pointers to this function and so that callers know the data won't be modified. Cc: Prashant Malani Signed-off-by: Stephen Boyd Acked-by: Prashant Malani Link: https://lore.kernel.org/r/20231003003429.1378109-5-swboyd@chromium.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_proto.c | 2 +- include/linux/platform_data/cros_ec_proto.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 475a6dd72db6..945b1b15a04c 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -1004,7 +1004,7 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, - void *outdata, + const void *outdata, size_t outsize, void *indata, size_t insize) diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 4f9f756bc17c..8865e350c12a 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -258,7 +258,7 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); -int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, +int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, const void *outdata, size_t outsize, void *indata, size_t insize); /** From da4082841ccf022beae73e63d3f476f59777172b Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 3 Oct 2023 09:32:31 -0700 Subject: [PATCH 158/396] platform/x86: ISST: Use fuse enabled mask instead of allowed levels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allowed level mask is a mask of levels, which are currently allowed to dynamically switch by the OS. Fused mask is a mask of all levels even if OS is not allowed to switch. Even if OS is not allowed to dynamically switch, it is still possible for user to boot to a level by using BIOS option. To decide which level to boot next time, user wants to check parameters (power, performance or thermal) of that level to decide. So, when passing the level mask for display to user space, use fuse enabled mask, which has all levels. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20231003163234.1856669-2-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c index 63faa2ea8327..a672a1c814af 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c @@ -704,7 +704,7 @@ static int isst_if_get_perf_level(void __user *argp) return -EINVAL; perf_level.max_level = power_domain_info->max_level; - perf_level.level_mask = power_domain_info->pp_header.allowed_level_mask; + perf_level.level_mask = power_domain_info->pp_header.level_en_mask; perf_level.feature_rev = power_domain_info->pp_header.feature_rev; _read_pp_info("current_level", perf_level.current_level, SST_PP_STATUS_OFFSET, SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE) From a22d36eb5b150913325640cb793e13e08d1bd715 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 3 Oct 2023 09:32:32 -0700 Subject: [PATCH 159/396] platform/x86: ISST: Allow level 0 to be not present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is possible that SST level 0 or base level is not present in some configurations. So don't set level 0 mask in level_en_mask by default. Signed-off-by: Srinivas Pandruvada Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20231003163234.1856669-3-srinivas.pandruvada@linux.intel.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c index a672a1c814af..ac5c6a812592 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c @@ -364,9 +364,6 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai /* Read PP header */ *((u64 *)&pd_info->pp_header) = readq(pd_info->sst_base + pd_info->sst_header.pp_offset); - /* Force level_en_mask level 0 */ - pd_info->pp_header.level_en_mask |= 0x01; - mask = 0x01; levels = 0; for (i = 0; i < 8; ++i) { From 7525cea3ef9384054a30f25ebb501234befecdcb Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 3 Oct 2023 09:32:33 -0700 Subject: [PATCH 160/396] platform/x86: intel_speed_select_if: Remove hardcoded map size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver is using 256 as the size while calling devm_ioremap(). The maximum offset can be obtained from isst_mmio_range. Add a field "size" to the isst_mmio_range and use it instead of hardcoding. No functional impact is expected. Signed-off-by: Srinivas Pandruvada Reviewed-by: Andy Shevchenko Reviewed-by: Ilpo Järvinen Link: https://lore.kernel.org/r/20231003163234.1856669-4-srinivas.pandruvada@linux.intel.com Signed-off-by: Ilpo Järvinen --- .../x86/intel/speed_select_if/isst_if_mmio.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c b/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c index ff49025ec085..13e068c77d50 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c @@ -18,16 +18,17 @@ struct isst_mmio_range { int beg; int end; + int size; }; static struct isst_mmio_range mmio_range_devid_0[] = { - {0x04, 0x14}, - {0x20, 0xD0}, + {0x04, 0x14, 0x18}, + {0x20, 0xD0, 0xD4}, }; static struct isst_mmio_range mmio_range_devid_1[] = { - {0x04, 0x14}, - {0x20, 0x11C}, + {0x04, 0x14, 0x18}, + {0x20, 0x11C, 0x120}, }; struct isst_if_device { @@ -114,13 +115,16 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pcu_base &= GENMASK(10, 0); base_addr = (u64)mmio_base << 23 | (u64) pcu_base << 12; - punit_dev->punit_mmio = devm_ioremap(&pdev->dev, base_addr, 256); + + punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data; + + punit_dev->punit_mmio = devm_ioremap(&pdev->dev, base_addr, + punit_dev->mmio_range[1].size); if (!punit_dev->punit_mmio) return -ENOMEM; mutex_init(&punit_dev->mutex); pci_set_drvdata(pdev, punit_dev); - punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data; memset(&cb, 0, sizeof(cb)); cb.cmd_size = sizeof(struct isst_if_io_reg); From 23f392ea6d1916f68be8067e2a038ef9a746a94b Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 3 Oct 2023 09:32:34 -0700 Subject: [PATCH 161/396] platform/x86: intel_speed_select_if: Use devm_ioremap_resource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace devm_ioremap() with devm_ioremap_resource() by defining a resource. Signed-off-by: Srinivas Pandruvada Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231003163234.1856669-5-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../platform/x86/intel/speed_select_if/isst_if_mmio.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c b/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c index 13e068c77d50..3f4343147dad 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c @@ -94,6 +94,7 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct isst_if_device *punit_dev; struct isst_if_cmd_cb cb; u32 mmio_base, pcu_base; + struct resource r; u64 base_addr; int ret; @@ -118,10 +119,10 @@ static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent) punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data; - punit_dev->punit_mmio = devm_ioremap(&pdev->dev, base_addr, - punit_dev->mmio_range[1].size); - if (!punit_dev->punit_mmio) - return -ENOMEM; + r = DEFINE_RES_MEM(base_addr, punit_dev->mmio_range[1].size); + punit_dev->punit_mmio = devm_ioremap_resource(&pdev->dev, &r); + if (IS_ERR(punit_dev->punit_mmio)) + return PTR_ERR(punit_dev->punit_mmio); mutex_init(&punit_dev->mutex); pci_set_drvdata(pdev, punit_dev); From 8874e414fe78718d0f2861fe511cecbd1cd73f4d Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 3 Oct 2023 11:49:14 -0700 Subject: [PATCH 162/396] platform/x86/intel/tpmi: Add defines to get version information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add defines to get major and minor version from a TPMI version field value. This will avoid code duplication to convert in every feature driver. Also add define for invalid version field. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20231003184916.1860084-2-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- include/linux/intel_tpmi.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/intel_tpmi.h b/include/linux/intel_tpmi.h index 04d937ad4dc4..ee07393445f9 100644 --- a/include/linux/intel_tpmi.h +++ b/include/linux/intel_tpmi.h @@ -6,6 +6,12 @@ #ifndef _INTEL_TPMI_H_ #define _INTEL_TPMI_H_ +#include + +#define TPMI_VERSION_INVALID 0xff +#define TPMI_MINOR_VERSION(val) FIELD_GET(GENMASK(4, 0), val) +#define TPMI_MAJOR_VERSION(val) FIELD_GET(GENMASK(7, 5), val) + /** * struct intel_tpmi_plat_info - Platform information for a TPMI device instance * @package_id: CPU Package id From 07510a59b316445311775ee53adf10448140607a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 3 Oct 2023 11:49:15 -0700 Subject: [PATCH 163/396] platform/x86: ISST: Ignore minor version change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware definition of every TPMI feature contains a major and minor version. When there is a change in the MMIO offset or change in the definition of a field, hardware will change major version. For addition of new fields without modifying existing MMIO offsets or fields, only the minor version is changed. Driver is developed to support SST functionality for a major and minor version. If the hardware changes major version, since offsets and definitions are changed, driver cannot continue to provide SST interface to users. Driver can still function with a minor version change as it will just miss the new functionality added by the hardware. The current implementation doesn't ignore any version change. If there is mismatch with the minor version, continue with an information log message. If there is mismatch with the major version, log error and exit. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20231003184916.1860084-3-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../x86/intel/speed_select_if/isst_tpmi_core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c index ac5c6a812592..0b6d2c864437 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c @@ -30,7 +30,8 @@ #include "isst_if_common.h" /* Supported SST hardware version by this driver */ -#define ISST_HEADER_VERSION 1 +#define ISST_MAJOR_VERSION 0 +#define ISST_MINOR_VERSION 1 /* * Used to indicate if value read from MMIO needs to get multiplied @@ -352,12 +353,19 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai pd_info->sst_header.cp_offset *= 8; pd_info->sst_header.pp_offset *= 8; - if (pd_info->sst_header.interface_version != ISST_HEADER_VERSION) { - dev_err(&auxdev->dev, "SST: Unsupported version:%x\n", - pd_info->sst_header.interface_version); + if (pd_info->sst_header.interface_version == TPMI_VERSION_INVALID) + return -ENODEV; + + if (TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version) != ISST_MAJOR_VERSION) { + dev_err(&auxdev->dev, "SST: Unsupported major version:%lx\n", + TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version)); return -ENODEV; } + if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) != ISST_MINOR_VERSION) + dev_info(&auxdev->dev, "SST: Ignore: Unsupported minor version:%lx\n", + TPMI_MINOR_VERSION(pd_info->sst_header.interface_version)); + /* Read SST CP Header */ *((u64 *)&pd_info->cp_header) = readq(pd_info->sst_base + pd_info->sst_header.cp_offset); From 4b0d9c8f8f55562ed5346723e66eec64f22887f4 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 3 Oct 2023 11:49:16 -0700 Subject: [PATCH 164/396] platform/x86/intel-uncore-freq: Ignore minor version change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware definition of every TPMI feature contains a major and minor version. When there is a change in the MMIO offset or change in the definition of a field, hardware will change major version. For addition of new fields without modifying existing MMIO offsets or fields, only the minor version is changed. Driver is developed to support uncore frequency control (UFS) for a major and minor version. If the hardware changes major version, since offsets and definitions are changed, driver cannot continue to provide UFS interface to users. Driver can still function with minor version change as it will just miss the new functionality added by the hardware. The current implementation logs information message and skips adding uncore sysfs entry for a resource for any version mismatch. Check major and minor version mismatch for every valid resource and fail on any major version mismatch by logging an error message. A valid resource has a version which is not 0xFF. If there is mismatch with the minor version, continue with a log message. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20231003184916.1860084-4-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- .../uncore-frequency/uncore-frequency-tpmi.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index 7d0a67f8b517..4fb790552c47 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -28,7 +28,8 @@ #include "uncore-frequency-common.h" -#define UNCORE_HEADER_VERSION 1 +#define UNCORE_MAJOR_VERSION 0 +#define UNCORE_MINOR_VERSION 1 #define UNCORE_HEADER_INDEX 0 #define UNCORE_FABRIC_CLUSTER_OFFSET 8 @@ -302,12 +303,21 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ /* Check for version and skip this resource if there is mismatch */ header = readq(pd_info->uncore_base); pd_info->ufs_header_ver = header & UNCORE_VERSION_MASK; - if (pd_info->ufs_header_ver != UNCORE_HEADER_VERSION) { - dev_info(&auxdev->dev, "Uncore: Unsupported version:%d\n", - pd_info->ufs_header_ver); + + if (pd_info->ufs_header_ver == TPMI_VERSION_INVALID) continue; + + if (TPMI_MAJOR_VERSION(pd_info->ufs_header_ver) != UNCORE_MAJOR_VERSION) { + dev_err(&auxdev->dev, "Uncore: Unsupported major version:%lx\n", + TPMI_MAJOR_VERSION(pd_info->ufs_header_ver)); + ret = -ENODEV; + goto remove_clusters; } + if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) != UNCORE_MINOR_VERSION) + dev_info(&auxdev->dev, "Uncore: Ignore: Unsupported minor version:%lx\n", + TPMI_MINOR_VERSION(pd_info->ufs_header_ver)); + /* Get Cluster ID Mask */ cluster_mask = FIELD_GET(UNCORE_LOCAL_FABRIC_CLUSTER_ID_MASK, header); if (!cluster_mask) { From 317e69c49b4ceef8aebb47d771498ccb3571bdf9 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Thu, 21 Sep 2023 12:23:54 +0300 Subject: [PATCH 165/396] clk: imx: Select MXC_CLK for CLK_IMX8QXP If the i.MX8QXP clock provider is built-in but the MXC_CLK is built as module, build fails: aarch64-linux-ld: drivers/clk/imx/clk-imx8-acm.o: in function `imx8_acm_clk_probe': clk-imx8-acm.c:(.text+0x3d0): undefined reference to `imx_check_clk_hws' Fix that by selecting MXC_CLK in case of CLK_IMX8QXP. Fixes: c2cccb6d0b33 ("clk: imx: add imx8qxp clk driver") Closes: https://lore.kernel.org/all/8b77219e-b59e-40f1-96f1-980a0b2debcf@infradead.org/ Reported-by: Randy Dunlap Reviewed-by: Peng Fan Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Abel Vesa --- drivers/clk/imx/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index f6b82e0b9703..db3bca5f4ec9 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -96,6 +96,7 @@ config CLK_IMX8QXP depends on (ARCH_MXC && ARM64) || COMPILE_TEST depends on IMX_SCU && HAVE_ARM_SMCCC select MXC_CLK_SCU + select MXC_CLK help Build the driver for IMX8QXP SCU based clocks. From 156624e2cf815ce98fad5a24f04370f4459ae6f4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 14 Sep 2023 22:31:02 +0200 Subject: [PATCH 166/396] clk: imx: imx8: Fix an error handling path in clk_imx_acm_attach_pm_domains() If a dev_pm_domain_attach_by_id() call fails, previously allocated resources need to be released. Fixes: d3a0946d7ac9 ("clk: imx: imx8: add audio clock mux driver") Reviewed-by: Peng Fan Signed-off-by: Christophe JAILLET Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8-acm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 1e82f72b75c6..87025a6772d0 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -279,8 +279,10 @@ static int clk_imx_acm_attach_pm_domains(struct device *dev, for (i = 0; i < dev_pm->num_domains; i++) { dev_pm->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); - if (IS_ERR(dev_pm->pd_dev[i])) - return PTR_ERR(dev_pm->pd_dev[i]); + if (IS_ERR(dev_pm->pd_dev[i])) { + ret = PTR_ERR(dev_pm->pd_dev[i]); + goto detach_pm; + } dev_pm->pd_dev_link[i] = device_link_add(dev, dev_pm->pd_dev[i], From 9a0108acdb1b6189dcc8f9318edfc6b7e0281df4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 14 Sep 2023 22:31:03 +0200 Subject: [PATCH 167/396] clk: imx: imx8: Fix an error handling path if devm_clk_hw_register_mux_parent_data_table() fails If a devm_clk_hw_register_mux_parent_data_table() call fails, it is likely that the probe should fail with an error code. Set 'ret' before leaving the function. Fixes: d3a0946d7ac9 ("clk: imx: imx8: add audio clock mux driver") Reviewed-by: Peng Fan Signed-off-by: Christophe JAILLET Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8-acm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 87025a6772d0..73b3b5354951 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -373,6 +373,7 @@ static int imx8_acm_clk_probe(struct platform_device *pdev) sels[i].shift, sels[i].width, 0, NULL, NULL); if (IS_ERR(hws[sels[i].clkid])) { + ret = PTR_ERR(hws[sels[i].clkid]); pm_runtime_disable(&pdev->dev); goto err_clk_register; } From e9a164e367f039629fd5466a79b9f495646e1261 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 14 Sep 2023 22:31:04 +0200 Subject: [PATCH 168/396] clk: imx: imx8: Fix an error handling path in imx8_acm_clk_probe() If an error occurs after a successful clk_imx_acm_attach_pm_domains() call, it must be undone. Add an explicit error handling path, re-order the code and add the missing clk_imx_acm_detach_pm_domains() call. Fixes: d3a0946d7ac9 ("clk: imx: imx8: add audio clock mux driver") Reviewed-by: Peng Fan Signed-off-by: Christophe JAILLET Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8-acm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 73b3b5354951..1c95ae905eec 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -374,7 +374,6 @@ static int imx8_acm_clk_probe(struct platform_device *pdev) 0, NULL, NULL); if (IS_ERR(hws[sels[i].clkid])) { ret = PTR_ERR(hws[sels[i].clkid]); - pm_runtime_disable(&pdev->dev); goto err_clk_register; } } @@ -384,12 +383,16 @@ static int imx8_acm_clk_probe(struct platform_device *pdev) ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); if (ret < 0) { dev_err(dev, "failed to register hws for ACM\n"); - pm_runtime_disable(&pdev->dev); + goto err_clk_register; } -err_clk_register: - pm_runtime_put_sync(&pdev->dev); + return 0; + +err_clk_register: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm); return ret; } From ef23d44b7fcbd19773dcedcb50ca2f625107604f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 14 Sep 2023 22:31:05 +0200 Subject: [PATCH 169/396] clk: imx: imx8: Add a message in case of devm_clk_hw_register_mux_parent_data_table() error If devm_clk_hw_register_mux_parent_data_table() fails, we branch to the error handling path and imx_check_clk_hws() is never called. Actually, imx_check_clk_hws() is a no-op because values in 'hws' are either valid, either NULL. Move the call to imx_check_clk_hws() in the error handling path, so that an error is logged. Fixes: d3a0946d7ac9 ("clk: imx: imx8: add audio clock mux driver") Reviewed-by: Peng Fan Signed-off-by: Christophe JAILLET Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8-acm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 1c95ae905eec..c744fb78bb44 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -374,12 +374,11 @@ static int imx8_acm_clk_probe(struct platform_device *pdev) 0, NULL, NULL); if (IS_ERR(hws[sels[i].clkid])) { ret = PTR_ERR(hws[sels[i].clkid]); + imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END); goto err_clk_register; } } - imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END); - ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); if (ret < 0) { dev_err(dev, "failed to register hws for ACM\n"); From 3af29a89de2c6e49737a1201b7d6fd5ad3f635a4 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 14 Sep 2023 22:31:06 +0200 Subject: [PATCH 170/396] clk: imx: imx8: Simplify clk_imx_acm_detach_pm_domains() The return value of clk_imx_acm_detach_pm_domains() is never used. Simplify the code and turn it into a void function. Reviewed-by: Peng Fan Signed-off-by: Christophe JAILLET Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8-acm.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index c744fb78bb44..735b08296cc8 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -310,20 +310,18 @@ detach_pm: * @dev: deivice pointer * @dev_pm: multi power domain for device */ -static int clk_imx_acm_detach_pm_domains(struct device *dev, - struct clk_imx_acm_pm_domains *dev_pm) +static void clk_imx_acm_detach_pm_domains(struct device *dev, + struct clk_imx_acm_pm_domains *dev_pm) { int i; if (dev_pm->num_domains <= 1) - return 0; + return; for (i = 0; i < dev_pm->num_domains; i++) { device_link_del(dev_pm->pd_dev_link[i]); dev_pm_domain_detach(dev_pm->pd_dev[i], false); } - - return 0; } static int imx8_acm_clk_probe(struct platform_device *pdev) From 05eeeff22b216e871be76dcf216a2fdda48880e2 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Wed, 30 Aug 2023 23:44:31 -0500 Subject: [PATCH 171/396] clk: imx8mp: Remove non-existent IMX8MP_CLK_AUDIOMIX_PDM_ROOT The TRM shows there is only one AUDIOMIX PDM Root Clock Select register, and it's called IMX8MP_CLK_AUDIOMIX_PDM_SEL. That selector doesn't appear to have any more children and the MICFIL driver can reference IMX8MP_CLK_AUDIOMIX_PDM_SEL directly without the need for any other. Remove this errant clock, since it doesn't really exist. Signed-off-by: Adam Ford Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230831044431.250338-3-aford173@gmail.com Signed-off-by: Abel Vesa --- include/dt-bindings/clock/imx8mp-clock.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/dt-bindings/clock/imx8mp-clock.h b/include/dt-bindings/clock/imx8mp-clock.h index 11cb0a4fe999..7da4243984b2 100644 --- a/include/dt-bindings/clock/imx8mp-clock.h +++ b/include/dt-bindings/clock/imx8mp-clock.h @@ -376,7 +376,6 @@ #define IMX8MP_CLK_AUDIOMIX_MU2_ROOT 36 #define IMX8MP_CLK_AUDIOMIX_MU3_ROOT 37 #define IMX8MP_CLK_AUDIOMIX_EARC_PHY 38 -#define IMX8MP_CLK_AUDIOMIX_PDM_ROOT 39 #define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1_SEL 40 #define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK2_SEL 41 #define IMX8MP_CLK_AUDIOMIX_SAI2_MCLK1_SEL 42 From 577ad169966e6e75b10e004389a3f79813e84b5d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 1 Oct 2023 20:26:18 +0800 Subject: [PATCH 172/396] clk: imx: imx8mq: correct error handling path Avoid memory leak in error handling path. It does not make much sense for the SoC without clk driver, to make program behavior correct, let's fix it. Fixes: b80522040cd3 ("clk: imx: Add clock driver for i.MX8MQ CCM") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202309240551.e46NllPa-lkp@intel.com/ Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/20231001122618.194498-1-peng.fan@oss.nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8mq.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index 4bd65879fcd3..f70ed231b92d 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -288,8 +288,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) void __iomem *base; int err; - clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, - IMX8MQ_CLK_END), GFP_KERNEL); + clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, IMX8MQ_CLK_END), GFP_KERNEL); if (WARN_ON(!clk_hw_data)) return -ENOMEM; @@ -306,10 +305,12 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) hws[IMX8MQ_CLK_EXT4] = imx_get_clk_hw_by_name(np, "clk_ext4"); np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop"); - base = of_iomap(np, 0); + base = devm_of_iomap(dev, np, 0, NULL); of_node_put(np); - if (WARN_ON(!base)) - return -ENOMEM; + if (WARN_ON(IS_ERR(base))) { + err = PTR_ERR(base); + goto unregister_hws; + } hws[IMX8MQ_ARM_PLL_REF_SEL] = imx_clk_hw_mux("arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); hws[IMX8MQ_GPU_PLL_REF_SEL] = imx_clk_hw_mux("gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)); @@ -395,8 +396,10 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) np = dev->of_node; base = devm_platform_ioremap_resource(pdev, 0); - if (WARN_ON(IS_ERR(base))) - return PTR_ERR(base); + if (WARN_ON(IS_ERR(base))) { + err = PTR_ERR(base); + goto unregister_hws; + } /* CORE */ hws[IMX8MQ_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mq_a53_sels, base + 0x8000); From 8df012a7f513141412b3c35af204ccdb810fcc81 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 25 Sep 2023 12:42:19 -0700 Subject: [PATCH 173/396] platform/x86/intel/tpmi: Add debugfs support for read/write blocked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display read and write blocked status of each TPMI feature in addition to disabled and locked status. This will require reading of read/write blocked state from the hardware. Currently tpmi_read_feature_status(), doesn't provide this state. Define TPMI feature state as defined in the TPMI spec. Modify the function tpmi_read_feature_status() to update full feature state instead of just disabled and locked state. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20230925194219.966602-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/tpmi.c | 81 +++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index 0a95736d97e4..311abcac894a 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -143,6 +143,33 @@ struct tpmi_info_header { u64 lock:1; } __packed; +/** + * struct tpmi_feature_state - Structure to read hardware state of a feature + * @enabled: Enable state of a feature, 1: enabled, 0: disabled + * @reserved_1: Reserved for future use + * @write_blocked: Writes are blocked means all write operations are ignored + * @read_blocked: Reads are blocked means will read 0xFFs + * @pcs_select: Interface used by out of band software, not used in OS + * @reserved_2: Reserved for future use + * @id: TPMI ID of the feature + * @reserved_3: Reserved for future use + * @locked: When set to 1, OS can't change this register. + * + * The structure is used to read hardware state of a TPMI feature. This + * information is used for debug and restricting operations for this feature. + */ +struct tpmi_feature_state { + u32 enabled:1; + u32 reserved_1:3; + u32 write_blocked:1; + u32 read_blocked:1; + u32 pcs_select:1; + u32 reserved_2:1; + u32 id:8; + u32 reserved_3:15; + u32 locked:1; +} __packed; + /* * List of supported TMPI IDs. * Some TMPI IDs are not used by Linux, so the numbers are not consecutive. @@ -202,6 +229,7 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); #define TPMI_CONTROL_STATUS_OFFSET 0x00 #define TPMI_COMMAND_OFFSET 0x08 +#define TMPI_CONTROL_DATA_VAL_OFFSET 0x0c /* * Spec is calling for max 1 seconds to get ownership at the worst @@ -230,7 +258,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); /* TPMI command data registers */ #define TMPI_CONTROL_DATA_CMD GENMASK_ULL(7, 0) -#define TMPI_CONTROL_DATA_VAL GENMASK_ULL(63, 32) #define TPMI_CONTROL_DATA_VAL_FEATURE GENMASK_ULL(48, 40) /* Command to send via control interface */ @@ -240,9 +267,6 @@ EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); #define TPMI_CMD_LEN_MASK GENMASK_ULL(18, 16) -#define TPMI_STATE_DISABLED BIT_ULL(0) -#define TPMI_STATE_LOCKED BIT_ULL(31) - /* Mutex to complete get feature status without interruption */ static DEFINE_MUTEX(tpmi_dev_lock); @@ -256,7 +280,7 @@ static int tpmi_wait_for_owner(struct intel_tpmi_info *tpmi_info, u8 owner) } static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int feature_id, - int *locked, int *disabled) + struct tpmi_feature_state *feature_state) { u64 control, data; int ret; @@ -306,17 +330,8 @@ static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int featu } /* Response is ready */ - data = readq(tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET); - data = FIELD_GET(TMPI_CONTROL_DATA_VAL, data); - - *disabled = 0; - *locked = 0; - - if (!(data & TPMI_STATE_DISABLED)) - *disabled = 1; - - if (data & TPMI_STATE_LOCKED) - *locked = 1; + memcpy_fromio(feature_state, tpmi_info->tpmi_control_mem + TMPI_CONTROL_DATA_VAL_OFFSET, + sizeof(*feature_state)); ret = 0; @@ -335,34 +350,50 @@ int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id, { struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); + struct tpmi_feature_state feature_state; + int ret; - return tpmi_read_feature_status(tpmi_info, feature_id, locked, disabled); + ret = tpmi_read_feature_status(tpmi_info, feature_id, &feature_state); + if (ret) + return ret; + + *locked = feature_state.locked; + *disabled = !feature_state.enabled; + + return 0; } EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI); static int tpmi_pfs_dbg_show(struct seq_file *s, void *unused) { struct intel_tpmi_info *tpmi_info = s->private; + int locked, disabled, read_blocked, write_blocked; + struct tpmi_feature_state feature_state; struct intel_tpmi_pm_feature *pfs; - int locked, disabled, ret, i; + int ret, i; + seq_printf(s, "tpmi PFS start offset 0x:%llx\n", tpmi_info->pfs_start); - seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\n"); + seq_puts(s, "tpmi_id\t\tentries\t\tsize\t\tcap_offset\tattribute\tvsec_offset\tlocked\tdisabled\tread_blocked\twrite_blocked\n"); for (i = 0; i < tpmi_info->feature_count; ++i) { pfs = &tpmi_info->tpmi_features[i]; - ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &locked, - &disabled); + ret = tpmi_read_feature_status(tpmi_info, pfs->pfs_header.tpmi_id, &feature_state); if (ret) { locked = 'U'; disabled = 'U'; + read_blocked = 'U'; + write_blocked = 'U'; } else { - disabled = disabled ? 'Y' : 'N'; - locked = locked ? 'Y' : 'N'; + disabled = feature_state.enabled ? 'N' : 'Y'; + locked = feature_state.locked ? 'Y' : 'N'; + read_blocked = feature_state.read_blocked ? 'Y' : 'N'; + write_blocked = feature_state.write_blocked ? 'Y' : 'N'; } - seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\n", + seq_printf(s, "0x%02x\t\t0x%02x\t\t0x%04x\t\t0x%04x\t\t0x%02x\t\t0x%08x\t%c\t%c\t\t%c\t\t%c\n", pfs->pfs_header.tpmi_id, pfs->pfs_header.num_entries, pfs->pfs_header.entry_size, pfs->pfs_header.cap_offset, - pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled); + pfs->pfs_header.attribute, pfs->vsec_offset, locked, disabled, + read_blocked, write_blocked); } return 0; From 0a22b3a6f446223aff5bcdcc06003ef6e412bfd8 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 15 Aug 2023 10:09:23 -0300 Subject: [PATCH 174/396] clk: imx: imx6sx: Allow a different LCDIF1 clock parent It is not a good idea to hardcode the LCDIF1 parent inside the clock driver because some users may want to use a different clock parent for LCDIF1. One of the reasons could be related to EMI tests. Remove the harcoded LCDIF1 parent when the LCDIF1 parent is described via devicetree. Old dtb's that do not describe the LCDIF1 parent via devicetree will use the same PLL5 clock as parent to keep the original behavior. Signed-off-by: Fabio Estevam Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230815130923.775117-1-festevam@gmail.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx6sx.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index 3f1502933e59..69f8f6f9ca49 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -121,6 +121,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; + bool lcdif1_assigned_clk; clk_hw_data = kzalloc(struct_size(clk_hw_data, hws, IMX6SX_CLK_CLK_END), GFP_KERNEL); @@ -498,9 +499,16 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) clk_set_parent(hws[IMX6SX_CLK_EIM_SLOW_SEL]->clk, hws[IMX6SX_CLK_PLL2_PFD2]->clk); clk_set_rate(hws[IMX6SX_CLK_EIM_SLOW]->clk, 132000000); - /* set parent clock for LCDIF1 pixel clock */ - clk_set_parent(hws[IMX6SX_CLK_LCDIF1_PRE_SEL]->clk, hws[IMX6SX_CLK_PLL5_VIDEO_DIV]->clk); - clk_set_parent(hws[IMX6SX_CLK_LCDIF1_SEL]->clk, hws[IMX6SX_CLK_LCDIF1_PODF]->clk); + np = of_find_node_by_path("/soc/bus@2200000/spba-bus@2240000/lcdif@2220000"); + lcdif1_assigned_clk = of_find_property(np, "assigned-clock-parents", NULL); + + /* Set parent clock for LCDIF1 pixel clock if not done via devicetree */ + if (!lcdif1_assigned_clk) { + clk_set_parent(hws[IMX6SX_CLK_LCDIF1_PRE_SEL]->clk, + hws[IMX6SX_CLK_PLL5_VIDEO_DIV]->clk); + clk_set_parent(hws[IMX6SX_CLK_LCDIF1_SEL]->clk, + hws[IMX6SX_CLK_LCDIF1_PODF]->clk); + } /* Set the parent clks of PCIe lvds1 and pcie_axi to be pcie ref, axi */ if (clk_set_parent(hws[IMX6SX_CLK_LVDS1_SEL]->clk, hws[IMX6SX_CLK_PCIE_REF_125M]->clk)) From ab2c30f6bbe34dbf13ff2cc0cf7bc237de2df013 Mon Sep 17 00:00:00 2001 From: Viorel Suman Date: Tue, 12 Sep 2023 17:18:59 +0800 Subject: [PATCH 175/396] clk: imx: imx8dxl-rsrc: keep sorted in the ascending order Entries in imx8dxl_clk_scu_rsrc_table must be kept in the ascending order, and IMX_SC_R_M4_0_UART < IMX_SC_R_M4_0_I2C. Fixes: 036a4b4b4dfa ("clk: imx: Add imx8dxl clk driver") Signed-off-by: Viorel Suman Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230912-imx8-clk-v1-v1-1-69a34bcfcae1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8dxl-rsrc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8dxl-rsrc.c b/drivers/clk/imx/clk-imx8dxl-rsrc.c index 69b7aa34fff5..a36e821ba807 100644 --- a/drivers/clk/imx/clk-imx8dxl-rsrc.c +++ b/drivers/clk/imx/clk-imx8dxl-rsrc.c @@ -50,8 +50,8 @@ static u32 imx8dxl_clk_scu_rsrc_table[] = { IMX_SC_R_MLB_0, IMX_SC_R_USB_1, IMX_SC_R_NAND, - IMX_SC_R_M4_0_I2C, IMX_SC_R_M4_0_UART, + IMX_SC_R_M4_0_I2C, IMX_SC_R_ELCDIF_PLL, IMX_SC_R_AUDIO_PLL_0, IMX_SC_R_AUDIO_PLL_1, From 15cee75dacb82ade710d61bfd536011933ef9bf2 Mon Sep 17 00:00:00 2001 From: Robert Chiras Date: Tue, 12 Sep 2023 17:19:00 +0800 Subject: [PATCH 176/396] clk: imx: imx8qxp: Fix elcdif_pll clock Move the elcdif_pll clock initialization before the lcd_clk, since the elcdif_clk needs to be initialized ahead of lcd_clk, being its parent. This change fixes issues with the LCD clocks during suspend/resume. Fixes: babfaa9556d7 ("clk: imx: scu: add more scu clocks") Suggested-by: Ranjani Vaidyanathan Acked-by: Laurentiu Palcu Signed-off-by: Robert Chiras Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230912-imx8-clk-v1-v1-2-69a34bcfcae1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8qxp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index cadcbb318f5c..4020aa4b79bf 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -147,10 +147,10 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER); imx_clk_scu("adc1_clk", IMX_SC_R_ADC_1, IMX_SC_PM_CLK_PER); imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL); imx_clk_scu2("lcd_clk", lcd_sels, ARRAY_SIZE(lcd_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER); imx_clk_scu2("lcd_pxl_clk", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_MISC0); imx_clk_scu("lcd_pxl_bypass_div_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_BYPASS); - imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL); /* Audio SS */ imx_clk_scu("audio_pll0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_PLL); From 8568b3c499268456b76cdc2e9e1b9d86d8b08837 Mon Sep 17 00:00:00 2001 From: Shenwei Wang Date: Tue, 12 Sep 2023 17:19:01 +0800 Subject: [PATCH 177/396] clk: imx: imx8qxp: correct the enet clocks for i.MX8DXL The SC_PM_CLK_MISC0 clock is not available for the resources of ENET0/1 on i.MX8DXL. Using the clock device compatible string to identify the platform and only initialize the enetX_rgmii_rx_clk clock for non i.MX8DXL platform. Signed-off-by: Shenwei Wang Reviewed-by: Ranjani Vaidyanathan Reviewed-by: Jacky Bai Acked-by: Jason Liu Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230912-imx8-clk-v1-v1-3-69a34bcfcae1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8qxp.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index 4020aa4b79bf..41f0a45aa162 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -90,6 +90,11 @@ static const char * const pi_pll0_sels[] = { "clk_dummy", }; +static inline bool clk_on_imx8dxl(struct device_node *node) +{ + return of_device_is_compatible(node, "fsl,imx8dxl-clk"); +} + static int imx8qxp_clk_probe(struct platform_device *pdev) { struct device_node *ccm_node = pdev->dev.of_node; @@ -169,13 +174,15 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) imx_clk_mux_gpr_scu("enet0_rgmii_txc_sel", enet0_rgmii_txc_sels, ARRAY_SIZE(enet0_rgmii_txc_sels), IMX_SC_R_ENET_0, IMX_SC_C_TXCLK); imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS); imx_clk_gate_gpr_scu("enet0_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_0, IMX_SC_C_DISABLE_50, true); - imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0); + if (!clk_on_imx8dxl(ccm_node)) { + imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0); + imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0); + } imx_clk_scu("enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER); imx_clk_divider_gpr_scu("enet1_ref_div", "enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_C_CLKDIV); imx_clk_mux_gpr_scu("enet1_rgmii_txc_sel", enet1_rgmii_txc_sels, ARRAY_SIZE(enet1_rgmii_txc_sels), IMX_SC_R_ENET_1, IMX_SC_C_TXCLK); imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS); imx_clk_gate_gpr_scu("enet1_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_1, IMX_SC_C_DISABLE_50, true); - imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0); imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS); imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER); imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER); From 4fcb51fb0e3084ee81edaf8aea98ac01e456a871 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 12 Sep 2023 17:19:02 +0800 Subject: [PATCH 178/396] clk: imx: imx8qm-rsrc: drop VPU_UART/VPUCORE IMX_SC_R_VPU_UART and IMX_SC_R_VPUCORE was used in i.MX8QM A0 which not for mass production. i.MX8QM B0 not have the two resources, so drop it. Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230912-imx8-clk-v1-v1-4-69a34bcfcae1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8qm-rsrc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clk/imx/clk-imx8qm-rsrc.c b/drivers/clk/imx/clk-imx8qm-rsrc.c index 87e0b6ac027e..8412fa349569 100644 --- a/drivers/clk/imx/clk-imx8qm-rsrc.c +++ b/drivers/clk/imx/clk-imx8qm-rsrc.c @@ -79,8 +79,6 @@ static const u32 imx8qm_clk_scu_rsrc_table[] = { IMX_SC_R_M4_0_I2C, IMX_SC_R_M4_1_I2C, IMX_SC_R_AUDIO_PLL_0, - IMX_SC_R_VPU_UART, - IMX_SC_R_VPUCORE, IMX_SC_R_MIPI_0, IMX_SC_R_MIPI_0_PWM_0, IMX_SC_R_MIPI_0_I2C_0, From a699148b8704aa11600321b9f6b6b21f09418c42 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 12 Sep 2023 17:19:03 +0800 Subject: [PATCH 179/396] clk: imx8: remove MLB support MLB was de-featured, so drop MLB clk for i.MX8QM/QXP/DXL Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230912-imx8-clk-v1-v1-5-69a34bcfcae1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8-acm.c | 6 +++--- drivers/clk/imx/clk-imx8dxl-rsrc.c | 1 - drivers/clk/imx/clk-imx8qm-rsrc.c | 1 - drivers/clk/imx/clk-imx8qxp-lpcg.h | 1 - drivers/clk/imx/clk-imx8qxp-rsrc.c | 1 - 5 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 735b08296cc8..f68877eef873 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -77,7 +77,7 @@ struct imx8_acm_priv { static const struct clk_parent_data imx8qm_aud_clk_sels[] = { { .fw_name = "aud_rec_clk0_lpcg_clk" }, { .fw_name = "aud_rec_clk1_lpcg_clk" }, - { .fw_name = "mlb_clk" }, + { .fw_name = "dummy" }, { .fw_name = "hdmi_rx_mclk" }, { .fw_name = "ext_aud_mclk0" }, { .fw_name = "ext_aud_mclk1" }, @@ -103,7 +103,7 @@ static const struct clk_parent_data imx8qm_aud_clk_sels[] = { static const struct clk_parent_data imx8qm_mclk_out_sels[] = { { .fw_name = "aud_rec_clk0_lpcg_clk" }, { .fw_name = "aud_rec_clk1_lpcg_clk" }, - { .fw_name = "mlb_clk" }, + { .fw_name = "dummy" }, { .fw_name = "hdmi_rx_mclk" }, { .fw_name = "spdif0_rx" }, { .fw_name = "spdif1_rx" }, @@ -122,7 +122,7 @@ static const struct clk_parent_data imx8qm_asrc_mux_clk_sels[] = { { .fw_name = "sai4_rx_bclk" }, { .fw_name = "sai5_tx_bclk" }, { .index = -1 }, - { .fw_name = "mlb_clk" }, + { .fw_name = "dummy" }, }; diff --git a/drivers/clk/imx/clk-imx8dxl-rsrc.c b/drivers/clk/imx/clk-imx8dxl-rsrc.c index a36e821ba807..0f940335d83c 100644 --- a/drivers/clk/imx/clk-imx8dxl-rsrc.c +++ b/drivers/clk/imx/clk-imx8dxl-rsrc.c @@ -47,7 +47,6 @@ static u32 imx8dxl_clk_scu_rsrc_table[] = { IMX_SC_R_SDHC_2, IMX_SC_R_ENET_0, IMX_SC_R_ENET_1, - IMX_SC_R_MLB_0, IMX_SC_R_USB_1, IMX_SC_R_NAND, IMX_SC_R_M4_0_UART, diff --git a/drivers/clk/imx/clk-imx8qm-rsrc.c b/drivers/clk/imx/clk-imx8qm-rsrc.c index 8412fa349569..634bc3058657 100644 --- a/drivers/clk/imx/clk-imx8qm-rsrc.c +++ b/drivers/clk/imx/clk-imx8qm-rsrc.c @@ -65,7 +65,6 @@ static const u32 imx8qm_clk_scu_rsrc_table[] = { IMX_SC_R_SDHC_2, IMX_SC_R_ENET_0, IMX_SC_R_ENET_1, - IMX_SC_R_MLB_0, IMX_SC_R_USB_2, IMX_SC_R_NAND, IMX_SC_R_LVDS_0, diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.h b/drivers/clk/imx/clk-imx8qxp-lpcg.h index 2a37ce57c500..ebca8fa9268f 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.h +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.h @@ -42,7 +42,6 @@ #define CONN_ENET_0_LPCG 0x30000 #define CONN_ENET_1_LPCG 0x40000 #define CONN_DTCP_LPCG 0x50000 -#define CONN_MLB_LPCG 0x60000 #define CONN_USB_2_LPCG 0x70000 #define CONN_USB_3_LPCG 0x80000 #define CONN_NAND_LPCG 0x90000 diff --git a/drivers/clk/imx/clk-imx8qxp-rsrc.c b/drivers/clk/imx/clk-imx8qxp-rsrc.c index df09f2a7996d..29868e686921 100644 --- a/drivers/clk/imx/clk-imx8qxp-rsrc.c +++ b/drivers/clk/imx/clk-imx8qxp-rsrc.c @@ -54,7 +54,6 @@ static const u32 imx8qxp_clk_scu_rsrc_table[] = { IMX_SC_R_SDHC_2, IMX_SC_R_ENET_0, IMX_SC_R_ENET_1, - IMX_SC_R_MLB_0, IMX_SC_R_USB_2, IMX_SC_R_NAND, IMX_SC_R_LVDS_0, From eaefd1cf36a6507ff7dd2d30f68201de259eec63 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 12 Sep 2023 17:19:04 +0800 Subject: [PATCH 180/396] clk: imx: scu: ignore clks not owned by Cortex-A partition Not register clks that not owned to current partition. CPU resources are specical resources, it is assigned in ATF, not non-secure OS, but we still need to allow cpu freq, so return true for non-secure OS for cpu resources. Otherwise there will be error log if the resources are owned by current partition: [ 19.387291] cm40_i2c_div: failed to attached the power domain -2 [ 19.389305] cm40_lpuart_div: failed to attached the power domain -2 Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230912-imx8-clk-v1-v1-6-69a34bcfcae1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-scu.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index cd83c52e9952..be89180dd19c 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -10,10 +10,12 @@ #include #include #include +#include #include #include #include #include +#include #include "clk-scu.h" @@ -670,6 +672,18 @@ static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id) return of_genpd_add_device(&genpdspec, dev); } +static bool imx_clk_is_resource_owned(u32 rsrc) +{ + /* + * A-core resources are special. SCFW reports they are not "owned" by + * current partition but linux can still adjust them for cpufreq. + */ + if (rsrc == IMX_SC_R_A53 || rsrc == IMX_SC_R_A72 || rsrc == IMX_SC_R_A35) + return true; + + return imx_sc_rm_is_resource_owned(ccm_ipc_handle, rsrc); +} + struct clk_hw *imx_clk_scu_alloc_dev(const char *name, const char * const *parents, int num_parents, u32 rsrc_id, u8 clk_type) @@ -687,6 +701,9 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name, if (!imx_scu_clk_is_valid(rsrc_id)) return ERR_PTR(-EINVAL); + if (!imx_clk_is_resource_owned(rsrc_id)) + return NULL; + pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE); if (!pdev) { pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n", @@ -869,6 +886,9 @@ struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_na return ERR_PTR(-EINVAL); } + if (!imx_clk_is_resource_owned(rsrc_id)) + return NULL; + clk = kzalloc(sizeof(*clk), GFP_KERNEL); if (!clk) { kfree(clk_node); From 2838820800dcaa60f32bef715c7e2e87e049aebc Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 12 Sep 2023 17:19:05 +0800 Subject: [PATCH 181/396] clk: imx: imx8qm/qxp: add more resources to whitelist Add CAN_1/2 support for i.MX8QM Add M4_0, PI_0_PWM_0 and PI_0_I2C_0 for i.MX8QXP Signed-off-by: Peng Fan Reviewed-by: Abel Vesa Link: https://lore.kernel.org/r/20230912-imx8-clk-v1-v1-7-69a34bcfcae1@nxp.com Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx8qm-rsrc.c | 2 ++ drivers/clk/imx/clk-imx8qxp-rsrc.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/clk/imx/clk-imx8qm-rsrc.c b/drivers/clk/imx/clk-imx8qm-rsrc.c index 634bc3058657..dadfdd9a4541 100644 --- a/drivers/clk/imx/clk-imx8qm-rsrc.c +++ b/drivers/clk/imx/clk-imx8qm-rsrc.c @@ -43,6 +43,8 @@ static const u32 imx8qm_clk_scu_rsrc_table[] = { IMX_SC_R_FTM_0, IMX_SC_R_FTM_1, IMX_SC_R_CAN_0, + IMX_SC_R_CAN_1, + IMX_SC_R_CAN_2, IMX_SC_R_GPU_0_PID0, IMX_SC_R_GPU_1_PID0, IMX_SC_R_PWM_0, diff --git a/drivers/clk/imx/clk-imx8qxp-rsrc.c b/drivers/clk/imx/clk-imx8qxp-rsrc.c index 29868e686921..585c425524a4 100644 --- a/drivers/clk/imx/clk-imx8qxp-rsrc.c +++ b/drivers/clk/imx/clk-imx8qxp-rsrc.c @@ -58,10 +58,13 @@ static const u32 imx8qxp_clk_scu_rsrc_table[] = { IMX_SC_R_NAND, IMX_SC_R_LVDS_0, IMX_SC_R_LVDS_1, + IMX_SC_R_M4_0_UART, IMX_SC_R_M4_0_I2C, IMX_SC_R_ELCDIF_PLL, IMX_SC_R_AUDIO_PLL_0, IMX_SC_R_PI_0, + IMX_SC_R_PI_0_PWM_0, + IMX_SC_R_PI_0_I2C_0, IMX_SC_R_PI_0_PLL, IMX_SC_R_MIPI_0, IMX_SC_R_MIPI_0_PWM_0, From 8242336dc8a8009b93fb7c4506d79a8c894b3583 Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Sun, 1 Oct 2023 15:17:42 +0200 Subject: [PATCH 182/396] power: supply: rt5033_charger: Add cable detection and USB OTG supply Implement cable detection by extcon and handle the driver according to the connector type. There are basically three types of action: "set_charging", "set_otg" and "set_disconnect". A forth helper function to "unset_otg" was added because this is used in both "set_charging" and "set_disconnect". In the first case it covers the rather rare event that someone changes from OTG to charging without disconnect. In the second case, when disconnecting, the values are set back to the ones from initialization to return into a defined state. Additionally, there is "set_mivr". When connecting to e.g. a laptop/PC, the minimum input voltage regulation (MIVR) shall prevent a voltage drop if the cable or the supply is weak. The MIVR value is set to 4600MV, same as in the Android driver [1]. When disconnecting, MIVR is set back to DISABLED. In the function rt5033_get_charger_state(): When in OTG mode, the chip reports status "charging". Change this to "discharging" because there is no charging going on in OTG mode [2]. Yang Yingliang detected missing mutex_unlock() in some error path and suggested a fix [3]. The suggestion was squashed into this patch. [1] https://github.com/msm8916-mainline/linux-downstream/blob/GT-I9195I/drivers/battery/rt5033_charger.c#L499 [2] https://github.com/msm8916-mainline/linux-downstream/blob/GT-I9195I/drivers/battery/rt5033_charger.c#L686-L687 [3] https://lore.kernel.org/linux-pm/20230822030207.644738-1-yangyingliang@huawei.com Tested-by: Raymond Hackley Co-developed-by: Yang Yingliang Signed-off-by: Jakob Hauser Link: https://lore.kernel.org/r/cc4e37e510abbb0cdfa7faa8408da48c2cb448a4.1696165240.git.jahau@rocketmail.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/rt5033_charger.c | 287 +++++++++++++++++++++++++- 1 file changed, 285 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c index c0c516f22c66..091ca4a21f29 100644 --- a/drivers/power/supply/rt5033_charger.c +++ b/drivers/power/supply/rt5033_charger.c @@ -6,8 +6,12 @@ * Author: Beomho Seo */ +#include +#include #include #include +#include +#include #include #include #include @@ -26,6 +30,14 @@ struct rt5033_charger { struct regmap *regmap; struct power_supply *psy; struct rt5033_charger_data *chg; + struct extcon_dev *edev; + struct notifier_block extcon_nb; + struct work_struct extcon_work; + struct mutex lock; + bool online; + bool otg; + bool mivr_enabled; + u8 cv_regval; }; static int rt5033_get_charger_state(struct rt5033_charger *charger) @@ -56,6 +68,10 @@ static int rt5033_get_charger_state(struct rt5033_charger *charger) state = POWER_SUPPLY_STATUS_UNKNOWN; } + /* For OTG mode, RT5033 would still report "charging" */ + if (charger->otg) + state = POWER_SUPPLY_STATUS_DISCHARGING; + return state; } @@ -147,6 +163,9 @@ static inline int rt5033_init_const_charge(struct rt5033_charger *charger) return -EINVAL; } + /* Store that value for later usage */ + charger->cv_regval = reg_data; + /* Set end of charge current */ if (chg->eoc_uamp < RT5033_CHARGER_EOC_MIN || chg->eoc_uamp > RT5033_CHARGER_EOC_MAX) { @@ -330,6 +349,162 @@ static int rt5033_charger_reg_init(struct rt5033_charger *charger) return 0; } +static int rt5033_charger_set_otg(struct rt5033_charger *charger) +{ + int ret; + + mutex_lock(&charger->lock); + + /* Set OTG boost v_out to 5 volts */ + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2, + RT5033_CHGCTRL2_CV_MASK, + 0x37 << RT5033_CHGCTRL2_CV_SHIFT); + if (ret) { + dev_err(charger->dev, "Failed set OTG boost v_out\n"); + ret = -EINVAL; + goto out_unlock; + } + + /* Set operation mode to OTG */ + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, + RT5033_CHGCTRL1_MODE_MASK, RT5033_BOOST_MODE); + if (ret) { + dev_err(charger->dev, "Failed to update OTG mode.\n"); + ret = -EINVAL; + goto out_unlock; + } + + /* In case someone switched from charging to OTG directly */ + if (charger->online) + charger->online = false; + + charger->otg = true; + +out_unlock: + mutex_unlock(&charger->lock); + + return ret; +} + +static int rt5033_charger_unset_otg(struct rt5033_charger *charger) +{ + int ret; + u8 data; + + /* Restore constant voltage for charging */ + data = charger->cv_regval; + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL2, + RT5033_CHGCTRL2_CV_MASK, + data << RT5033_CHGCTRL2_CV_SHIFT); + if (ret) { + dev_err(charger->dev, "Failed to restore constant voltage\n"); + return -EINVAL; + } + + /* Set operation mode to charging */ + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL1, + RT5033_CHGCTRL1_MODE_MASK, RT5033_CHARGER_MODE); + if (ret) { + dev_err(charger->dev, "Failed to update charger mode.\n"); + return -EINVAL; + } + + charger->otg = false; + + return 0; +} + +static int rt5033_charger_set_charging(struct rt5033_charger *charger) +{ + int ret; + + mutex_lock(&charger->lock); + + /* In case someone switched from OTG to charging directly */ + if (charger->otg) { + ret = rt5033_charger_unset_otg(charger); + if (ret) { + mutex_unlock(&charger->lock); + return -EINVAL; + } + } + + charger->online = true; + + mutex_unlock(&charger->lock); + + return 0; +} + +static int rt5033_charger_set_mivr(struct rt5033_charger *charger) +{ + int ret; + + mutex_lock(&charger->lock); + + /* + * When connected via USB connector type SDP (Standard Downstream Port), + * the minimum input voltage regulation (MIVR) should be enabled. It + * prevents an input voltage drop due to insufficient current provided + * by the adapter or USB input. As a downside, it may reduces the + * charging current and thus slows the charging. + */ + ret = regmap_update_bits(charger->regmap, RT5033_REG_CHG_CTRL4, + RT5033_CHGCTRL4_MIVR_MASK, RT5033_CHARGER_MIVR_4600MV); + if (ret) { + dev_err(charger->dev, "Failed to set MIVR level.\n"); + mutex_unlock(&charger->lock); + return -EINVAL; + } + + charger->mivr_enabled = true; + + mutex_unlock(&charger->lock); + + /* Beyond this, do the same steps like setting charging */ + rt5033_charger_set_charging(charger); + + return 0; +} + +static int rt5033_charger_set_disconnect(struct rt5033_charger *charger) +{ + int ret = 0; + + mutex_lock(&charger->lock); + + /* Disable MIVR if enabled */ + if (charger->mivr_enabled) { + ret = regmap_update_bits(charger->regmap, + RT5033_REG_CHG_CTRL4, + RT5033_CHGCTRL4_MIVR_MASK, + RT5033_CHARGER_MIVR_DISABLE); + if (ret) { + dev_err(charger->dev, "Failed to disable MIVR.\n"); + ret = -EINVAL; + goto out_unlock; + } + + charger->mivr_enabled = false; + } + + if (charger->otg) { + ret = rt5033_charger_unset_otg(charger); + if (ret) { + ret = -EINVAL; + goto out_unlock; + } + } + + if (charger->online) + charger->online = false; + +out_unlock: + mutex_unlock(&charger->lock); + + return ret; +} + static enum power_supply_property rt5033_charger_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_CHARGE_TYPE, @@ -366,8 +541,7 @@ static int rt5033_charger_get_property(struct power_supply *psy, val->strval = RT5033_MANUFACTURER; break; case POWER_SUPPLY_PROP_ONLINE: - val->intval = (rt5033_get_charger_state(charger) == - POWER_SUPPLY_STATUS_CHARGING); + val->intval = charger->online; break; default: return -EINVAL; @@ -402,6 +576,86 @@ static struct rt5033_charger_data *rt5033_charger_dt_init( return chg; } +static void rt5033_charger_extcon_work(struct work_struct *work) +{ + struct rt5033_charger *charger = + container_of(work, struct rt5033_charger, extcon_work); + struct extcon_dev *edev = charger->edev; + int connector, state; + int ret; + + for (connector = EXTCON_USB_HOST; connector <= EXTCON_CHG_USB_PD; + connector++) { + state = extcon_get_state(edev, connector); + if (state == 1) + break; + } + + /* + * Adding a delay between extcon notification and extcon action. This + * makes extcon action execution more reliable. Without the delay the + * execution sometimes fails, possibly because the chip is busy or not + * ready. + */ + msleep(100); + + switch (connector) { + case EXTCON_CHG_USB_SDP: + ret = rt5033_charger_set_mivr(charger); + if (ret) { + dev_err(charger->dev, "failed to set USB mode\n"); + break; + } + dev_info(charger->dev, "USB mode. connector type: %d\n", + connector); + break; + case EXTCON_CHG_USB_DCP: + case EXTCON_CHG_USB_CDP: + case EXTCON_CHG_USB_ACA: + case EXTCON_CHG_USB_FAST: + case EXTCON_CHG_USB_SLOW: + case EXTCON_CHG_WPT: + case EXTCON_CHG_USB_PD: + ret = rt5033_charger_set_charging(charger); + if (ret) { + dev_err(charger->dev, "failed to set charging\n"); + break; + } + dev_info(charger->dev, "charging. connector type: %d\n", + connector); + break; + case EXTCON_USB_HOST: + ret = rt5033_charger_set_otg(charger); + if (ret) { + dev_err(charger->dev, "failed to set OTG\n"); + break; + } + dev_info(charger->dev, "OTG enabled\n"); + break; + default: + ret = rt5033_charger_set_disconnect(charger); + if (ret) { + dev_err(charger->dev, "failed to set disconnect\n"); + break; + } + dev_info(charger->dev, "disconnected\n"); + break; + } + + power_supply_changed(charger->psy); +} + +static int rt5033_charger_extcon_notifier(struct notifier_block *nb, + unsigned long event, void *param) +{ + struct rt5033_charger *charger = + container_of(nb, struct rt5033_charger, extcon_nb); + + schedule_work(&charger->extcon_work); + + return NOTIFY_OK; +} + static const struct power_supply_desc rt5033_charger_desc = { .name = "rt5033-charger", .type = POWER_SUPPLY_TYPE_USB, @@ -414,6 +668,7 @@ static int rt5033_charger_probe(struct platform_device *pdev) { struct rt5033_charger *charger; struct power_supply_config psy_cfg = {}; + struct device_node *np_conn, *np_edev; int ret; charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); @@ -423,6 +678,7 @@ static int rt5033_charger_probe(struct platform_device *pdev) platform_set_drvdata(pdev, charger); charger->dev = &pdev->dev; charger->regmap = dev_get_regmap(pdev->dev.parent, NULL); + mutex_init(&charger->lock); psy_cfg.of_node = pdev->dev.of_node; psy_cfg.drv_data = charger; @@ -442,6 +698,33 @@ static int rt5033_charger_probe(struct platform_device *pdev) if (ret) return ret; + /* + * Extcon support is not vital for the charger to work. If no extcon + * is available, just emit a warning and leave the probe function. + */ + np_conn = of_parse_phandle(pdev->dev.of_node, "richtek,usb-connector", 0); + np_edev = of_get_parent(np_conn); + charger->edev = extcon_find_edev_by_node(np_edev); + if (IS_ERR(charger->edev)) { + dev_warn(&pdev->dev, "no extcon device found in device-tree\n"); + goto out; + } + + ret = devm_work_autocancel(&pdev->dev, &charger->extcon_work, + rt5033_charger_extcon_work); + if (ret) { + dev_err(&pdev->dev, "failed to initialize extcon work\n"); + return ret; + } + + charger->extcon_nb.notifier_call = rt5033_charger_extcon_notifier; + ret = devm_extcon_register_notifier_all(&pdev->dev, charger->edev, + &charger->extcon_nb); + if (ret) { + dev_err(&pdev->dev, "failed to register extcon notifier\n"); + return ret; + } +out: return 0; } From 1c6877f1768a34c04e3a82f9f950f78488a1753b Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Sun, 1 Oct 2023 15:17:43 +0200 Subject: [PATCH 183/396] power: supply: rt5033_charger: Simplify initialization of rt5033_charger_data Currently the struct "rt5033_charger_data" is initialized rather complicated. The cause lies inside of the struct "rt5033_charger", where struct "rt5033_charger_data" is implemented as a pointer *chg. Therefore, inside of struct "rt5033_charger" change the struct "rt5033_charger_data" to non-pointer "chg". It is then initialized right away and can be accessed more easily. Signed-off-by: Jakob Hauser Link: https://lore.kernel.org/r/0aff8c2a18cf4b88ec3333f6679a8419dd76ca29.1696165240.git.jahau@rocketmail.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/rt5033_charger.c | 29 +++++++++++---------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c index 091ca4a21f29..b34ef0ea6f8a 100644 --- a/drivers/power/supply/rt5033_charger.c +++ b/drivers/power/supply/rt5033_charger.c @@ -29,7 +29,7 @@ struct rt5033_charger { struct device *dev; struct regmap *regmap; struct power_supply *psy; - struct rt5033_charger_data *chg; + struct rt5033_charger_data chg; struct extcon_dev *edev; struct notifier_block extcon_nb; struct work_struct extcon_work; @@ -131,7 +131,7 @@ static int rt5033_get_charger_const_voltage(struct rt5033_charger *charger) static inline int rt5033_init_const_charge(struct rt5033_charger *charger) { - struct rt5033_charger_data *chg = charger->chg; + struct rt5033_charger_data *chg = &charger->chg; int ret; unsigned int val; u8 reg_data; @@ -205,7 +205,7 @@ static inline int rt5033_init_const_charge(struct rt5033_charger *charger) static inline int rt5033_init_fast_charge(struct rt5033_charger *charger) { - struct rt5033_charger_data *chg = charger->chg; + struct rt5033_charger_data *chg = &charger->chg; int ret; unsigned int val; u8 reg_data; @@ -250,7 +250,7 @@ static inline int rt5033_init_fast_charge(struct rt5033_charger *charger) static inline int rt5033_init_pre_charge(struct rt5033_charger *charger) { - struct rt5033_charger_data *chg = charger->chg; + struct rt5033_charger_data *chg = &charger->chg; int ret; unsigned int val; u8 reg_data; @@ -550,21 +550,16 @@ static int rt5033_charger_get_property(struct power_supply *psy, return 0; } -static struct rt5033_charger_data *rt5033_charger_dt_init( - struct rt5033_charger *charger) +static int rt5033_charger_dt_init(struct rt5033_charger *charger) { - struct rt5033_charger_data *chg; + struct rt5033_charger_data *chg = &charger->chg; struct power_supply_battery_info *info; int ret; - chg = devm_kzalloc(charger->dev, sizeof(*chg), GFP_KERNEL); - if (!chg) - return ERR_PTR(-ENOMEM); - ret = power_supply_get_battery_info(charger->psy, &info); if (ret) - return ERR_PTR(dev_err_probe(charger->dev, -EINVAL, - "missing battery info\n")); + return dev_err_probe(charger->dev, -EINVAL, + "missing battery info\n"); /* Assign data. Validity will be checked in the init functions. */ chg->pre_uamp = info->precharge_current_ua; @@ -573,7 +568,7 @@ static struct rt5033_charger_data *rt5033_charger_dt_init( chg->pre_uvolt = info->precharge_voltage_max_uv; chg->const_uvolt = info->constant_charge_voltage_max_uv; - return chg; + return 0; } static void rt5033_charger_extcon_work(struct work_struct *work) @@ -690,9 +685,9 @@ static int rt5033_charger_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(charger->psy), "Failed to register power supply\n"); - charger->chg = rt5033_charger_dt_init(charger); - if (IS_ERR_OR_NULL(charger->chg)) - return PTR_ERR(charger->chg); + ret = rt5033_charger_dt_init(charger); + if (ret) + return ret; ret = rt5033_charger_reg_init(charger); if (ret) From 3f26d8b6d1cbd41c5fa663c9ea48a2b832cfb58f Mon Sep 17 00:00:00 2001 From: Jakob Hauser Date: Sun, 1 Oct 2023 15:17:44 +0200 Subject: [PATCH 184/396] power: supply: rt5033_charger: Replace "&pdev->dev" by "charger->dev" in probe At the beginning of the probe function, "charger->dev" is set equal to "&pdev->dev". Therefore it's more clear to subsequently use "charger->dev" instead of "&pdev->dev". Signed-off-by: Jakob Hauser Link: https://lore.kernel.org/r/39b4f00e010446e453905c8dc3ca1e47e9f2c5f8.1696165240.git.jahau@rocketmail.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/rt5033_charger.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c index b34ef0ea6f8a..d19c7e80a92a 100644 --- a/drivers/power/supply/rt5033_charger.c +++ b/drivers/power/supply/rt5033_charger.c @@ -678,11 +678,11 @@ static int rt5033_charger_probe(struct platform_device *pdev) psy_cfg.of_node = pdev->dev.of_node; psy_cfg.drv_data = charger; - charger->psy = devm_power_supply_register(&pdev->dev, + charger->psy = devm_power_supply_register(charger->dev, &rt5033_charger_desc, &psy_cfg); if (IS_ERR(charger->psy)) - return dev_err_probe(&pdev->dev, PTR_ERR(charger->psy), + return dev_err_probe(charger->dev, PTR_ERR(charger->psy), "Failed to register power supply\n"); ret = rt5033_charger_dt_init(charger); @@ -701,22 +701,22 @@ static int rt5033_charger_probe(struct platform_device *pdev) np_edev = of_get_parent(np_conn); charger->edev = extcon_find_edev_by_node(np_edev); if (IS_ERR(charger->edev)) { - dev_warn(&pdev->dev, "no extcon device found in device-tree\n"); + dev_warn(charger->dev, "no extcon device found in device-tree\n"); goto out; } - ret = devm_work_autocancel(&pdev->dev, &charger->extcon_work, + ret = devm_work_autocancel(charger->dev, &charger->extcon_work, rt5033_charger_extcon_work); if (ret) { - dev_err(&pdev->dev, "failed to initialize extcon work\n"); + dev_err(charger->dev, "failed to initialize extcon work\n"); return ret; } charger->extcon_nb.notifier_call = rt5033_charger_extcon_notifier; - ret = devm_extcon_register_notifier_all(&pdev->dev, charger->edev, + ret = devm_extcon_register_notifier_all(charger->dev, charger->edev, &charger->extcon_nb); if (ret) { - dev_err(&pdev->dev, "failed to register extcon notifier\n"); + dev_err(charger->dev, "failed to register extcon notifier\n"); return ret; } out: From e372aee8c24957cbcb55d93b14ba386096497bca Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:59 +0300 Subject: [PATCH 185/396] dt-bindings: clock: renesas,rzg2l-cpg: Document RZ/G3S SoC Add documentation for the RZ/G3S CPG. The RZ/G3S CPG module is almost identical to the one available in RZ/G2{L,UL}, the exception being some core clocks as follows: - The SD clock is composed of a mux and a divider, and the divider has some limitations (div = 1 cannot be set if mux rate is 800MHz), - There are 3 SD clocks, - The OCTA and TSU clocks are specific to RZ/G3S, - PLL1/4/6 are specific to RZ/G3S with its own computation formula. Even with this RZ/G3S could use the same bindings as RZ/G2L. Along with documentation bindings for the RZ/G3S (R9A08G045) Clock Pulse Generator (CPG) core clocks, module clocks and resets were added. Signed-off-by: Claudiu Beznea Acked-by: Rob Herring Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-13-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- .../bindings/clock/renesas,rzg2l-cpg.yaml | 1 + include/dt-bindings/clock/r9a08g045-cpg.h | 242 ++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 include/dt-bindings/clock/r9a08g045-cpg.h diff --git a/Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml b/Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml index fe2fba18ae84..80a8c7114c31 100644 --- a/Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml +++ b/Documentation/devicetree/bindings/clock/renesas,rzg2l-cpg.yaml @@ -27,6 +27,7 @@ properties: - renesas,r9a07g043-cpg # RZ/G2UL{Type-1,Type-2} and RZ/Five - renesas,r9a07g044-cpg # RZ/G2{L,LC} - renesas,r9a07g054-cpg # RZ/V2L + - renesas,r9a08g045-cpg # RZ/G3S - renesas,r9a09g011-cpg # RZ/V2M reg: diff --git a/include/dt-bindings/clock/r9a08g045-cpg.h b/include/dt-bindings/clock/r9a08g045-cpg.h new file mode 100644 index 000000000000..410725b778a8 --- /dev/null +++ b/include/dt-bindings/clock/r9a08g045-cpg.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + * + * Copyright (C) 2023 Renesas Electronics Corp. + */ +#ifndef __DT_BINDINGS_CLOCK_R9A08G045_CPG_H__ +#define __DT_BINDINGS_CLOCK_R9A08G045_CPG_H__ + +#include + +/* R9A08G045 CPG Core Clocks */ +#define R9A08G045_CLK_I 0 +#define R9A08G045_CLK_I2 1 +#define R9A08G045_CLK_I3 2 +#define R9A08G045_CLK_S0 3 +#define R9A08G045_CLK_SPI0 4 +#define R9A08G045_CLK_SPI1 5 +#define R9A08G045_CLK_SD0 6 +#define R9A08G045_CLK_SD1 7 +#define R9A08G045_CLK_SD2 8 +#define R9A08G045_CLK_M0 9 +#define R9A08G045_CLK_HP 10 +#define R9A08G045_CLK_TSU 11 +#define R9A08G045_CLK_ZT 12 +#define R9A08G045_CLK_P0 13 +#define R9A08G045_CLK_P1 14 +#define R9A08G045_CLK_P2 15 +#define R9A08G045_CLK_P3 16 +#define R9A08G045_CLK_P4 17 +#define R9A08G045_CLK_P5 18 +#define R9A08G045_CLK_AT 19 +#define R9A08G045_CLK_OC0 20 +#define R9A08G045_CLK_OC1 21 +#define R9A08G045_OSCCLK 22 +#define R9A08G045_OSCCLK2 23 +#define R9A08G045_SWD 24 + +/* R9A08G045 Module Clocks */ +#define R9A08G045_OCTA_ACLK 0 +#define R9A08G045_OCTA_MCLK 1 +#define R9A08G045_CA55_SCLK 2 +#define R9A08G045_CA55_PCLK 3 +#define R9A08G045_CA55_ATCLK 4 +#define R9A08G045_CA55_GICCLK 5 +#define R9A08G045_CA55_PERICLK 6 +#define R9A08G045_CA55_ACLK 7 +#define R9A08G045_CA55_TSCLK 8 +#define R9A08G045_SRAM_ACPU_ACLK0 9 +#define R9A08G045_SRAM_ACPU_ACLK1 10 +#define R9A08G045_SRAM_ACPU_ACLK2 11 +#define R9A08G045_GIC600_GICCLK 12 +#define R9A08G045_IA55_CLK 13 +#define R9A08G045_IA55_PCLK 14 +#define R9A08G045_MHU_PCLK 15 +#define R9A08G045_SYC_CNT_CLK 16 +#define R9A08G045_DMAC_ACLK 17 +#define R9A08G045_DMAC_PCLK 18 +#define R9A08G045_OSTM0_PCLK 19 +#define R9A08G045_OSTM1_PCLK 20 +#define R9A08G045_OSTM2_PCLK 21 +#define R9A08G045_OSTM3_PCLK 22 +#define R9A08G045_OSTM4_PCLK 23 +#define R9A08G045_OSTM5_PCLK 24 +#define R9A08G045_OSTM6_PCLK 25 +#define R9A08G045_OSTM7_PCLK 26 +#define R9A08G045_MTU_X_MCK_MTU3 27 +#define R9A08G045_POE3_CLKM_POE 28 +#define R9A08G045_GPT_PCLK 29 +#define R9A08G045_POEG_A_CLKP 30 +#define R9A08G045_POEG_B_CLKP 31 +#define R9A08G045_POEG_C_CLKP 32 +#define R9A08G045_POEG_D_CLKP 33 +#define R9A08G045_WDT0_PCLK 34 +#define R9A08G045_WDT0_CLK 35 +#define R9A08G045_WDT1_PCLK 36 +#define R9A08G045_WDT1_CLK 37 +#define R9A08G045_WDT2_PCLK 38 +#define R9A08G045_WDT2_CLK 39 +#define R9A08G045_SPI_HCLK 40 +#define R9A08G045_SPI_ACLK 41 +#define R9A08G045_SPI_CLK 42 +#define R9A08G045_SPI_CLKX2 43 +#define R9A08G045_SDHI0_IMCLK 44 +#define R9A08G045_SDHI0_IMCLK2 45 +#define R9A08G045_SDHI0_CLK_HS 46 +#define R9A08G045_SDHI0_ACLK 47 +#define R9A08G045_SDHI1_IMCLK 48 +#define R9A08G045_SDHI1_IMCLK2 49 +#define R9A08G045_SDHI1_CLK_HS 50 +#define R9A08G045_SDHI1_ACLK 51 +#define R9A08G045_SDHI2_IMCLK 52 +#define R9A08G045_SDHI2_IMCLK2 53 +#define R9A08G045_SDHI2_CLK_HS 54 +#define R9A08G045_SDHI2_ACLK 55 +#define R9A08G045_SSI0_PCLK2 56 +#define R9A08G045_SSI0_PCLK_SFR 57 +#define R9A08G045_SSI1_PCLK2 58 +#define R9A08G045_SSI1_PCLK_SFR 59 +#define R9A08G045_SSI2_PCLK2 60 +#define R9A08G045_SSI2_PCLK_SFR 61 +#define R9A08G045_SSI3_PCLK2 62 +#define R9A08G045_SSI3_PCLK_SFR 63 +#define R9A08G045_SRC_CLKP 64 +#define R9A08G045_USB_U2H0_HCLK 65 +#define R9A08G045_USB_U2H1_HCLK 66 +#define R9A08G045_USB_U2P_EXR_CPUCLK 67 +#define R9A08G045_USB_PCLK 68 +#define R9A08G045_ETH0_CLK_AXI 69 +#define R9A08G045_ETH0_CLK_CHI 70 +#define R9A08G045_ETH0_REFCLK 71 +#define R9A08G045_ETH1_CLK_AXI 72 +#define R9A08G045_ETH1_CLK_CHI 73 +#define R9A08G045_ETH1_REFCLK 74 +#define R9A08G045_I2C0_PCLK 75 +#define R9A08G045_I2C1_PCLK 76 +#define R9A08G045_I2C2_PCLK 77 +#define R9A08G045_I2C3_PCLK 78 +#define R9A08G045_SCIF0_CLK_PCK 79 +#define R9A08G045_SCIF1_CLK_PCK 80 +#define R9A08G045_SCIF2_CLK_PCK 81 +#define R9A08G045_SCIF3_CLK_PCK 82 +#define R9A08G045_SCIF4_CLK_PCK 83 +#define R9A08G045_SCIF5_CLK_PCK 84 +#define R9A08G045_SCI0_CLKP 85 +#define R9A08G045_SCI1_CLKP 86 +#define R9A08G045_IRDA_CLKP 87 +#define R9A08G045_RSPI0_CLKB 88 +#define R9A08G045_RSPI1_CLKB 89 +#define R9A08G045_RSPI2_CLKB 90 +#define R9A08G045_RSPI3_CLKB 91 +#define R9A08G045_RSPI4_CLKB 92 +#define R9A08G045_CANFD_PCLK 93 +#define R9A08G045_CANFD_CLK_RAM 94 +#define R9A08G045_GPIO_HCLK 95 +#define R9A08G045_ADC_ADCLK 96 +#define R9A08G045_ADC_PCLK 97 +#define R9A08G045_TSU_PCLK 98 +#define R9A08G045_PDM_PCLK 99 +#define R9A08G045_PDM_CCLK 100 +#define R9A08G045_PCI_ACLK 101 +#define R9A08G045_PCI_CLKL1PM 102 +#define R9A08G045_SPDIF_PCLK 103 +#define R9A08G045_I3C_PCLK 104 +#define R9A08G045_I3C_TCLK 105 +#define R9A08G045_VBAT_BCLK 106 + +/* R9A08G045 Resets */ +#define R9A08G045_CA55_RST_1_0 0 +#define R9A08G045_CA55_RST_3_0 1 +#define R9A08G045_CA55_RST_4 2 +#define R9A08G045_CA55_RST_5 3 +#define R9A08G045_CA55_RST_6 4 +#define R9A08G045_CA55_RST_7 5 +#define R9A08G045_CA55_RST_8 6 +#define R9A08G045_CA55_RST_9 7 +#define R9A08G045_CA55_RST_10 8 +#define R9A08G045_CA55_RST_11 9 +#define R9A08G045_CA55_RST_12 10 +#define R9A08G045_SRAM_ACPU_ARESETN0 11 +#define R9A08G045_SRAM_ACPU_ARESETN1 12 +#define R9A08G045_SRAM_ACPU_ARESETN2 13 +#define R9A08G045_GIC600_GICRESET_N 14 +#define R9A08G045_GIC600_DBG_GICRESET_N 15 +#define R9A08G045_IA55_RESETN 16 +#define R9A08G045_MHU_RESETN 17 +#define R9A08G045_DMAC_ARESETN 18 +#define R9A08G045_DMAC_RST_ASYNC 19 +#define R9A08G045_SYC_RESETN 20 +#define R9A08G045_OSTM0_PRESETZ 21 +#define R9A08G045_OSTM1_PRESETZ 22 +#define R9A08G045_OSTM2_PRESETZ 23 +#define R9A08G045_OSTM3_PRESETZ 24 +#define R9A08G045_OSTM4_PRESETZ 25 +#define R9A08G045_OSTM5_PRESETZ 26 +#define R9A08G045_OSTM6_PRESETZ 27 +#define R9A08G045_OSTM7_PRESETZ 28 +#define R9A08G045_MTU_X_PRESET_MTU3 29 +#define R9A08G045_POE3_RST_M_REG 30 +#define R9A08G045_GPT_RST_C 31 +#define R9A08G045_POEG_A_RST 32 +#define R9A08G045_POEG_B_RST 33 +#define R9A08G045_POEG_C_RST 34 +#define R9A08G045_POEG_D_RST 35 +#define R9A08G045_WDT0_PRESETN 36 +#define R9A08G045_WDT1_PRESETN 37 +#define R9A08G045_WDT2_PRESETN 38 +#define R9A08G045_SPI_HRESETN 39 +#define R9A08G045_SPI_ARESETN 40 +#define R9A08G045_SDHI0_IXRST 41 +#define R9A08G045_SDHI1_IXRST 42 +#define R9A08G045_SDHI2_IXRST 43 +#define R9A08G045_SSI0_RST_M2_REG 44 +#define R9A08G045_SSI1_RST_M2_REG 45 +#define R9A08G045_SSI2_RST_M2_REG 46 +#define R9A08G045_SSI3_RST_M2_REG 47 +#define R9A08G045_SRC_RST 48 +#define R9A08G045_USB_U2H0_HRESETN 49 +#define R9A08G045_USB_U2H1_HRESETN 50 +#define R9A08G045_USB_U2P_EXL_SYSRST 51 +#define R9A08G045_USB_PRESETN 52 +#define R9A08G045_ETH0_RST_HW_N 53 +#define R9A08G045_ETH1_RST_HW_N 54 +#define R9A08G045_I2C0_MRST 55 +#define R9A08G045_I2C1_MRST 56 +#define R9A08G045_I2C2_MRST 57 +#define R9A08G045_I2C3_MRST 58 +#define R9A08G045_SCIF0_RST_SYSTEM_N 59 +#define R9A08G045_SCIF1_RST_SYSTEM_N 60 +#define R9A08G045_SCIF2_RST_SYSTEM_N 61 +#define R9A08G045_SCIF3_RST_SYSTEM_N 62 +#define R9A08G045_SCIF4_RST_SYSTEM_N 63 +#define R9A08G045_SCIF5_RST_SYSTEM_N 64 +#define R9A08G045_SCI0_RST 65 +#define R9A08G045_SCI1_RST 66 +#define R9A08G045_IRDA_RST 67 +#define R9A08G045_RSPI0_RST 68 +#define R9A08G045_RSPI1_RST 69 +#define R9A08G045_RSPI2_RST 70 +#define R9A08G045_RSPI3_RST 71 +#define R9A08G045_RSPI4_RST 72 +#define R9A08G045_CANFD_RSTP_N 73 +#define R9A08G045_CANFD_RSTC_N 74 +#define R9A08G045_GPIO_RSTN 75 +#define R9A08G045_GPIO_PORT_RESETN 76 +#define R9A08G045_GPIO_SPARE_RESETN 77 +#define R9A08G045_ADC_PRESETN 78 +#define R9A08G045_ADC_ADRST_N 79 +#define R9A08G045_TSU_PRESETN 80 +#define R9A08G045_OCTA_ARESETN 81 +#define R9A08G045_PDM0_PRESETNT 82 +#define R9A08G045_PCI_ARESETN 83 +#define R9A08G045_PCI_RST_B 84 +#define R9A08G045_PCI_RST_GP_B 85 +#define R9A08G045_PCI_RST_PS_B 86 +#define R9A08G045_PCI_RST_RSM_B 87 +#define R9A08G045_PCI_RST_CFG_B 88 +#define R9A08G045_PCI_RST_LOAD_B 89 +#define R9A08G045_SPDIF_RST 90 +#define R9A08G045_I3C_TRESETN 91 +#define R9A08G045_I3C_PRESETN 92 +#define R9A08G045_VBAT_BRESETN 93 + +#endif /* __DT_BINDINGS_CLOCK_R9A08G045_CPG_H__ */ From a7bad167bdc3cf4c47c6a9ec4fc9b4ae18b4614d Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 3 Oct 2023 08:04:53 +0000 Subject: [PATCH 186/396] platform/chrome: cros_ec: fix compilation warning When including cros_ec.h solely, the compiler emits the following warning: > 'struct cros_ec_device' declared inside parameter list will not be visible outside of this definition or declaration Fix it by forward declaration. Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231003080453.4011301-1-tzungbi@kernel.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/chrome/cros_ec.h b/drivers/platform/chrome/cros_ec.h index bbca0096868a..2b2574236030 100644 --- a/drivers/platform/chrome/cros_ec.h +++ b/drivers/platform/chrome/cros_ec.h @@ -10,6 +10,8 @@ #include +struct cros_ec_device; + int cros_ec_register(struct cros_ec_device *ec_dev); void cros_ec_unregister(struct cros_ec_device *ec_dev); From e410b4ade83d06a046f6e32b5085997502ba0559 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 3 Oct 2023 08:05:04 +0000 Subject: [PATCH 187/396] platform/chrome: kunit: initialize lock for fake ec_dev cros_ec_cmd_xfer() uses ec_dev->lock. Initialize it. Otherwise, dmesg shows the following: > DEBUG_LOCKS_WARN_ON(lock->magic != lock) > ... > Call Trace: > ? __mutex_lock > ? __warn > ? __mutex_lock > ... > ? cros_ec_cmd_xfer Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231003080504.4011337-1-tzungbi@kernel.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec_proto_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 5b9748e0463b..63e38671e95a 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -2668,6 +2668,7 @@ static int cros_ec_proto_test_init(struct kunit *test) ec_dev->dev->release = cros_ec_proto_test_release; ec_dev->cmd_xfer = cros_kunit_ec_xfer_mock; ec_dev->pkt_xfer = cros_kunit_ec_xfer_mock; + mutex_init(&ec_dev->lock); priv->msg = (struct cros_ec_command *)priv->_msg; From 466f70fb1b10fd139582646285e587fb38a9ff2c Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Tue, 3 Oct 2023 08:05:15 +0000 Subject: [PATCH 188/396] platform/chrome: kunit: make EC protocol tests independent Remove CONFIG_CROS_KUNIT and common code concept for ChromeOS Kunit but make it bundle to ChromeOS EC protocol tests. Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231003080515.4011374-1-tzungbi@kernel.org Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/Kconfig | 6 +++--- drivers/platform/chrome/Makefile | 5 ++--- drivers/platform/chrome/cros_ec_proto_test.c | 2 +- .../chrome/{cros_kunit_util.c => cros_ec_proto_test_util.c} | 4 +--- .../chrome/{cros_kunit_util.h => cros_ec_proto_test_util.h} | 0 5 files changed, 7 insertions(+), 10 deletions(-) rename drivers/platform/chrome/{cros_kunit_util.c => cros_ec_proto_test_util.c} (98%) rename drivers/platform/chrome/{cros_kunit_util.h => cros_ec_proto_test_util.h} (100%) diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 7d82a0946e1c..7a83346bfa53 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -299,12 +299,12 @@ config CROS_TYPEC_SWITCH source "drivers/platform/chrome/wilco_ec/Kconfig" # Kunit test cases -config CROS_KUNIT - tristate "Kunit tests for ChromeOS" if !KUNIT_ALL_TESTS +config CROS_KUNIT_EC_PROTO_TEST + tristate "Kunit tests for ChromeOS EC protocol" if !KUNIT_ALL_TESTS depends on KUNIT && CROS_EC default KUNIT_ALL_TESTS select CROS_EC_PROTO help - ChromeOS Kunit tests. + Kunit tests for ChromeOS EC protocol. endif # CHROMEOS_PLATFORMS diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 9e26e45c4a37..2dcc6ccc2302 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -36,6 +36,5 @@ obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o obj-$(CONFIG_WILCO_EC) += wilco_ec/ # Kunit test cases -obj-$(CONFIG_CROS_KUNIT) += cros_kunit.o -cros_kunit-objs := cros_kunit_util.o -cros_kunit-objs += cros_ec_proto_test.o +obj-$(CONFIG_CROS_KUNIT_EC_PROTO_TEST) += cros_kunit_proto_test.o +cros_kunit_proto_test-objs := cros_ec_proto_test_util.o cros_ec_proto_test.o diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 63e38671e95a..b6169d6f2467 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -11,7 +11,7 @@ #include #include "cros_ec.h" -#include "cros_kunit_util.h" +#include "cros_ec_proto_test_util.h" #define BUFSIZE 512 diff --git a/drivers/platform/chrome/cros_kunit_util.c b/drivers/platform/chrome/cros_ec_proto_test_util.c similarity index 98% rename from drivers/platform/chrome/cros_kunit_util.c rename to drivers/platform/chrome/cros_ec_proto_test_util.c index f0fda96b11bd..65d328bcd6eb 100644 --- a/drivers/platform/chrome/cros_kunit_util.c +++ b/drivers/platform/chrome/cros_ec_proto_test_util.c @@ -11,7 +11,7 @@ #include #include "cros_ec.h" -#include "cros_kunit_util.h" +#include "cros_ec_proto_test_util.h" int cros_kunit_ec_xfer_mock_default_result; int cros_kunit_ec_xfer_mock_default_ret; @@ -126,5 +126,3 @@ void cros_kunit_mock_reset(void) cros_kunit_readmem_mock_data = NULL; cros_kunit_readmem_mock_ret = 0; } - -MODULE_LICENSE("GPL"); diff --git a/drivers/platform/chrome/cros_kunit_util.h b/drivers/platform/chrome/cros_ec_proto_test_util.h similarity index 100% rename from drivers/platform/chrome/cros_kunit_util.h rename to drivers/platform/chrome/cros_ec_proto_test_util.h From d5252d9697a3e7007c741e9c103073868955a304 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Thu, 28 Sep 2023 10:03:17 +0200 Subject: [PATCH 189/396] clk: renesas: rcar-gen3: Extend SDnH divider table The clock dividers might be used with clock stop bit enabled or not. Current tables only support recommended values from the datasheet. This might result in warnings like below because no valid clock divider is found. Resulting in a 0 divider. There are Renesas ARM Trusted Firmware version out there which e.g. configure 0x201 (shifted logical right by 2: 0x80) and with this match the added { STPnHCK | 0, 1 }: https://github.com/renesas-rcar/arm-trusted-firmware/blob/rcar_gen3_v2.3/drivers/renesas/rcar/emmc/emmc_init.c#L108 ------------[ cut here ]------------ sd1h: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set WARNING: CPU: 1 PID: 1 at drivers/clk/clk-divider.c:141 divider_recalc_rate+0x48/0x70 Modules linked in: CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.1.52 #1 Hardware name: Custom board based on r8a7796 (DT) pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : divider_recalc_rate+0x48/0x70 ... ------------[ cut here ]------------ Fixes: bb6d3fa98a41 ("clk: renesas: rcar-gen3: Switch to new SD clock handling") Signed-off-by: Dirk Behme [wsa: extended the table to 5 entries, added comments, reword commit message a little] Signed-off-by: Wolfram Sang Tested-by: Dirk Behme Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230928080317.28224-1-wsa+renesas@sang-engineering.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rcar-cpg-lib.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c index e2e0447de190..5a15f8788b92 100644 --- a/drivers/clk/renesas/rcar-cpg-lib.c +++ b/drivers/clk/renesas/rcar-cpg-lib.c @@ -70,8 +70,21 @@ void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, #define STPnHCK BIT(9 - SDnSRCFC_SHIFT) static const struct clk_div_table cpg_sdh_div_table[] = { + /* + * These values are recommended by the datasheet. Because they come + * first, Linux will only use these. + */ { 0, 1 }, { 1, 2 }, { STPnHCK | 2, 4 }, { STPnHCK | 3, 8 }, - { STPnHCK | 4, 16 }, { 0, 0 }, + { STPnHCK | 4, 16 }, + /* + * These values are not recommended because STPnHCK is wrong. But they + * have been seen because of broken firmware. So, we support reading + * them but Linux will sanitize them when initializing through + * recalc_rate. + */ + { STPnHCK | 0, 1 }, { STPnHCK | 1, 2 }, { 2, 4 }, { 3, 8 }, { 4, 16 }, + /* Sentinel */ + { 0, 0 } }; struct clk * __init cpg_sdh_clk_register(const char *name, From 549f4ae2601f968e2474c6031fb4799468882f64 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:49 +0300 Subject: [PATCH 190/396] clk: renesas: rzg2l: Wait for status bit of SD mux before continuing The hardware user manual for RZ/G2L (r01uh0914ej0130-rzg2l-rzg2lc.pdf, chapter 7.4.7 Procedure for Switching Clocks by the Dynamic Switching Frequency Selectors) specifies that we need to check CPG_PL2SDHI_DSEL for SD clock switching status. Fixes: eaff33646f4cb ("clk: renesas: rzg2l: Add SDHI clk mux support") Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-3-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 9baae7bb7094..5343d04fd70d 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -188,7 +188,8 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) u32 off = GET_REG_OFFSET(hwdata->conf); u32 shift = GET_SHIFT(hwdata->conf); const u32 clk_src_266 = 2; - u32 bitmask; + u32 msk, val, bitmask; + int ret; /* * As per the HW manual, we should not directly switch from 533 MHz to @@ -202,14 +203,10 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) * the index to value mapping is done by adding 1 to the index. */ bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16; + msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; if (index != clk_src_266) { - u32 msk, val; - int ret; - writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off); - msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; - ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val, !(val & msk), 100, CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); @@ -221,7 +218,13 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) writel(bitmask | ((index + 1) << shift), priv->base + off); - return 0; + ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val, + !(val & msk), 100, + CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); + if (ret) + dev_err(priv->dev, "failed to switch clk source\n"); + + return ret; } static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) From d2692ed490e680a41401cef879adebcfafb4298f Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:50 +0300 Subject: [PATCH 191/396] clk: renesas: rzg2l: Lock around writes to mux register The SD MUX output (SD0) is further divided by 4 in G2{L,UL}. The divided clock is SD0_DIV4. SD0_DIV4 is registered with CLK_SET_RATE_PARENT which means a rate request for it is propagated to the MUX and could reach rzg2l_cpg_sd_clk_mux_set_parent() concurrently with the users of SD0. Add proper locking to avoid concurrent accesses on SD MUX set rate registers. Fixes: eaff33646f4cb ("clk: renesas: rzg2l: Add SDHI clk mux support") Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-4-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 23 +++++++++++++---------- drivers/clk/renesas/rzg2l-cpg.h | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 5343d04fd70d..0679f2c7649e 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -189,6 +189,7 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) u32 shift = GET_SHIFT(hwdata->conf); const u32 clk_src_266 = 2; u32 msk, val, bitmask; + unsigned long flags; int ret; /* @@ -204,23 +205,25 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) */ bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16; msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; + spin_lock_irqsave(&priv->rmw_lock, flags); if (index != clk_src_266) { writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off); - ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val, - !(val & msk), 100, - CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); - if (ret) { - dev_err(priv->dev, "failed to switch clk source\n"); - return ret; - } + ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, + !(val & msk), 10, + CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); + if (ret) + goto unlock; } writel(bitmask | ((index + 1) << shift), priv->base + off); - ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val, - !(val & msk), 100, - CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); + ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, + !(val & msk), 10, + CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); +unlock: + spin_unlock_irqrestore(&priv->rmw_lock, flags); + if (ret) dev_err(priv->dev, "failed to switch clk source\n"); diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 0b28870a6f9d..097fd8f61680 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -43,7 +43,7 @@ #define CPG_CLKSTATUS_SELSDHI0_STS BIT(28) #define CPG_CLKSTATUS_SELSDHI1_STS BIT(29) -#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 20000 +#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 200 /* n = 0/1/2 for PLL1/4/6 */ #define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n)) From bf51d3b2d048c312764a55d91d67a85ee5535e31 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:51 +0300 Subject: [PATCH 192/396] clk: renesas: rzg2l: Trust value returned by hardware The onitial value of the CPG_PL2SDHI_DSEL bits 0..1 or 4..6 is 01b. The hardware user's manual (r01uh0914ej0130-rzg2l-rzg2lc.pdf) specifies that setting 0 is prohibited. Hence rzg2l_cpg_sd_clk_mux_get_parent() should just read CPG_PL2SDHI_DSEL, trust the value, and return the proper clock parent index based on the value read. Fixes: eaff33646f4cb ("clk: renesas: rzg2l: Add SDHI clk mux support") Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-5-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 0679f2c7649e..6f50f0329ecf 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -238,14 +238,8 @@ static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) val >>= GET_SHIFT(hwdata->conf); val &= GENMASK(GET_WIDTH(hwdata->conf) - 1, 0); - if (val) { - val--; - } else { - /* Prohibited clk source, change it to 533 MHz(reset value) */ - rzg2l_cpg_sd_clk_mux_set_parent(hw, 0); - } - return val; + return val ? val - 1 : 0; } static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { From a2b23159499efd36b2d63b3c4534075d12ddc97a Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:52 +0300 Subject: [PATCH 193/396] clk: renesas: rzg2l: Fix computation formula According to the hardware manual for RZ/G2L (r01uh0914ej0130-rzg2l-rzg2lc.pdf), the computation formula for PLL rate is as follows: Fout = ((m + k/65536) * Fin) / (p * 2^s) and k has values in the range [-32768, 32767]. Dividing k by 65536 with integer arithmetic gives zero all the time, causing slight differences b/w what has been set vs. what is displayed. Thus, get rid of this and decompose the formula before dividing k by 65536. Fixes: ef3c613ccd68a ("clk: renesas: Add CPG core wrapper for RZ/G2L SoC") Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-6-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 6f50f0329ecf..a4723dd3a070 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -42,7 +42,7 @@ #define GET_SHIFT(val) ((val >> 12) & 0xff) #define GET_WIDTH(val) ((val >> 8) & 0xf) -#define KDIV(val) FIELD_GET(GENMASK(31, 16), val) +#define KDIV(val) ((s16)FIELD_GET(GENMASK(31, 16), val)) #define MDIV(val) FIELD_GET(GENMASK(15, 6), val) #define PDIV(val) FIELD_GET(GENMASK(5, 0), val) #define SDIV(val) FIELD_GET(GENMASK(2, 0), val) @@ -695,18 +695,18 @@ static unsigned long rzg2l_cpg_pll_clk_recalc_rate(struct clk_hw *hw, struct pll_clk *pll_clk = to_pll(hw); struct rzg2l_cpg_priv *priv = pll_clk->priv; unsigned int val1, val2; - unsigned int mult = 1; - unsigned int div = 1; + u64 rate; if (pll_clk->type != CLK_TYPE_SAM_PLL) return parent_rate; val1 = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf)); val2 = readl(priv->base + GET_REG_SAMPLL_CLK2(pll_clk->conf)); - mult = MDIV(val1) + KDIV(val1) / 65536; - div = PDIV(val1) << SDIV(val2); - return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, div); + rate = mul_u64_u32_shr(parent_rate, (MDIV(val1) << 16) + KDIV(val1), + 16 + SDIV(val2)); + + return DIV_ROUND_CLOSEST_ULL(rate, PDIV(val1)); } static const struct clk_ops rzg2l_cpg_pll_ops = { From 5f710e3bc5987373737470f98798bbd49134a2e0 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:53 +0300 Subject: [PATCH 194/396] clk: renesas: rzg2l: Remove critical area The spinlock in rzg2l_mod_clock_endisable() is intended to protect RMW-accesses to the hardware register. There is no need to protect instructions that set temporary variables which will be written afterwards to a hardware register. With this only one write to one clock register is executed thus locking/unlocking rmw_lock is removed. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-7-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index a4723dd3a070..3e4773b13076 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -895,7 +895,6 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable) struct rzg2l_cpg_priv *priv = clock->priv; unsigned int reg = clock->off; struct device *dev = priv->dev; - unsigned long flags; u32 bitmask = BIT(clock->bit); u32 value; int error; @@ -907,14 +906,12 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable) dev_dbg(dev, "CLK_ON %u/%pC %s\n", CLK_ON_R(reg), hw->clk, enable ? "ON" : "OFF"); - spin_lock_irqsave(&priv->rmw_lock, flags); value = bitmask << 16; if (enable) value |= bitmask; - writel(value, priv->base + CLK_ON_R(reg)); - spin_unlock_irqrestore(&priv->rmw_lock, flags); + writel(value, priv->base + CLK_ON_R(reg)); if (!enable) return 0; From 01eabef547e63d80086acd3f247d36c5f9f92456 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:54 +0300 Subject: [PATCH 195/396] clk: renesas: rzg2l: Add support for RZ/G3S PLL Add support for reading the frequency of PLL1/4/6 as available on RZ/G3S. The computation formula for the PLL frequency is as follows: Fout = (nir + nfr / 4096) * Fin / (mr * pr) Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-8-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 49 ++++++++++++++++++++++++++++++--- drivers/clk/renesas/rzg2l-cpg.h | 3 ++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 3e4773b13076..f8ab433a4253 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -47,6 +47,11 @@ #define PDIV(val) FIELD_GET(GENMASK(5, 0), val) #define SDIV(val) FIELD_GET(GENMASK(2, 0), val) +#define RZG3S_DIV_P GENMASK(28, 26) +#define RZG3S_DIV_M GENMASK(25, 22) +#define RZG3S_DIV_NI GENMASK(21, 13) +#define RZG3S_DIV_NF GENMASK(12, 1) + #define CLK_ON_R(reg) (reg) #define CLK_MON_R(reg) (0x180 + (reg)) #define CLK_RST_R(reg) (reg) @@ -713,11 +718,43 @@ static const struct clk_ops rzg2l_cpg_pll_ops = { .recalc_rate = rzg2l_cpg_pll_clk_recalc_rate, }; +static unsigned long rzg3s_cpg_pll_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct pll_clk *pll_clk = to_pll(hw); + struct rzg2l_cpg_priv *priv = pll_clk->priv; + u32 nir, nfr, mr, pr, val; + u64 rate; + + if (pll_clk->type != CLK_TYPE_G3S_PLL) + return parent_rate; + + val = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf)); + + pr = 1 << FIELD_GET(RZG3S_DIV_P, val); + /* Hardware interprets values higher than 8 as p = 16. */ + if (pr > 8) + pr = 16; + + mr = FIELD_GET(RZG3S_DIV_M, val) + 1; + nir = FIELD_GET(RZG3S_DIV_NI, val) + 1; + nfr = FIELD_GET(RZG3S_DIV_NF, val); + + rate = mul_u64_u32_shr(parent_rate, 4096 * nir + nfr, 12); + + return DIV_ROUND_CLOSEST_ULL(rate, (mr * pr)); +} + +static const struct clk_ops rzg3s_cpg_pll_ops = { + .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate, +}; + static struct clk * __init rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core, struct clk **clks, void __iomem *base, - struct rzg2l_cpg_priv *priv) + struct rzg2l_cpg_priv *priv, + const struct clk_ops *ops) { struct device *dev = priv->dev; const struct clk *parent; @@ -735,7 +772,7 @@ rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core, parent_name = __clk_get_name(parent); init.name = core->name; - init.ops = &rzg2l_cpg_pll_ops; + init.ops = ops; init.flags = 0; init.parent_names = &parent_name; init.num_parents = 1; @@ -830,8 +867,12 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, core->mult, div); break; case CLK_TYPE_SAM_PLL: - clk = rzg2l_cpg_pll_clk_register(core, priv->clks, - priv->base, priv); + clk = rzg2l_cpg_pll_clk_register(core, priv->clks, priv->base, priv, + &rzg2l_cpg_pll_ops); + break; + case CLK_TYPE_G3S_PLL: + clk = rzg2l_cpg_pll_clk_register(core, priv->clks, priv->base, priv, + &rzg3s_cpg_pll_ops); break; case CLK_TYPE_SIPLL5: clk = rzg2l_cpg_sipll5_register(core, priv->clks, priv); diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 097fd8f61680..20da0c620b90 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -102,6 +102,7 @@ enum clk_types { CLK_TYPE_IN, /* External Clock Input */ CLK_TYPE_FF, /* Fixed Factor Clock */ CLK_TYPE_SAM_PLL, + CLK_TYPE_G3S_PLL, /* Clock with divider */ CLK_TYPE_DIV, @@ -129,6 +130,8 @@ enum clk_types { DEF_TYPE(_name, _id, _type, .parent = _parent) #define DEF_SAMPLL(_name, _id, _parent, _conf) \ DEF_TYPE(_name, _id, CLK_TYPE_SAM_PLL, .parent = _parent, .conf = _conf) +#define DEF_G3S_PLL(_name, _id, _parent, _conf) \ + DEF_TYPE(_name, _id, CLK_TYPE_G3S_PLL, .parent = _parent, .conf = _conf) #define DEF_INPUT(_name, _id) \ DEF_TYPE(_name, _id, CLK_TYPE_IN) #define DEF_FIXED(_name, _id, _parent, _mult, _div) \ From 97c1c4ccda76d2919775d748cf223637cf0e82ae Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:55 +0300 Subject: [PATCH 196/396] clk: renesas: rzg2l: Add struct clk_hw_data Add clk_hw_data struct that keeps the core part of the clock data. sd_hw_data embeds a member of type struct clk_hw_data along with other members (in the next commits). This commit prepares the field for refactoring the SD MUX clock driver. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-9-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 52 +++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index f8ab433a4253..6ca81d22c669 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -63,13 +63,29 @@ #define MAX_VCLK_FREQ (148500000) -struct sd_hw_data { +/** + * struct clk_hw_data - clock hardware data + * @hw: clock hw + * @conf: clock configuration (register offset, shift, width) + * @priv: CPG private data structure + */ +struct clk_hw_data { struct clk_hw hw; u32 conf; struct rzg2l_cpg_priv *priv; }; -#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw) +#define to_clk_hw_data(_hw) container_of(_hw, struct clk_hw_data, hw) + +/** + * struct sd_hw_data - SD clock hardware data + * @hw_data: clock hw data + */ +struct sd_hw_data { + struct clk_hw_data hw_data; +}; + +#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw_data) struct rzg2l_pll5_param { u32 pl5_fracin; @@ -188,10 +204,10 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) { - struct sd_hw_data *hwdata = to_sd_hw_data(hw); - struct rzg2l_cpg_priv *priv = hwdata->priv; - u32 off = GET_REG_OFFSET(hwdata->conf); - u32 shift = GET_SHIFT(hwdata->conf); + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct rzg2l_cpg_priv *priv = clk_hw_data->priv; + u32 off = GET_REG_OFFSET(clk_hw_data->conf); + u32 shift = GET_SHIFT(clk_hw_data->conf); const u32 clk_src_266 = 2; u32 msk, val, bitmask; unsigned long flags; @@ -208,7 +224,7 @@ static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and * the index to value mapping is done by adding 1 to the index. */ - bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16; + bitmask = (GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0) << shift) << 16; msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; spin_lock_irqsave(&priv->rmw_lock, flags); if (index != clk_src_266) { @@ -237,12 +253,12 @@ unlock: static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) { - struct sd_hw_data *hwdata = to_sd_hw_data(hw); - struct rzg2l_cpg_priv *priv = hwdata->priv; - u32 val = readl(priv->base + GET_REG_OFFSET(hwdata->conf)); + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct rzg2l_cpg_priv *priv = clk_hw_data->priv; + u32 val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); - val >>= GET_SHIFT(hwdata->conf); - val &= GENMASK(GET_WIDTH(hwdata->conf) - 1, 0); + val >>= GET_SHIFT(clk_hw_data->conf); + val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0); return val ? val - 1 : 0; } @@ -258,17 +274,17 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, void __iomem *base, struct rzg2l_cpg_priv *priv) { - struct sd_hw_data *clk_hw_data; + struct sd_hw_data *sd_hw_data; struct clk_init_data init; struct clk_hw *clk_hw; int ret; - clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); - if (!clk_hw_data) + sd_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_hw_data), GFP_KERNEL); + if (!sd_hw_data) return ERR_PTR(-ENOMEM); - clk_hw_data->priv = priv; - clk_hw_data->conf = core->conf; + sd_hw_data->hw_data.priv = priv; + sd_hw_data->hw_data.conf = core->conf; init.name = core->name; init.ops = &rzg2l_cpg_sd_clk_mux_ops; @@ -276,7 +292,7 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, init.num_parents = core->num_parents; init.parent_names = core->parent_names; - clk_hw = &clk_hw_data->hw; + clk_hw = &sd_hw_data->hw_data.hw; clk_hw->init = &init; ret = devm_clk_hw_register(priv->dev, clk_hw); From 3e8008fcf6b7f7c65ad2718c18fb79f37007f1a5 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 29 Sep 2023 08:38:56 +0300 Subject: [PATCH 197/396] clk: renesas: rzg2l: Remove CPG_SDHI_DSEL from generic header Remove CPG_SDHI_DSEL and its bits from the generic header as RZ/G3S has different offset registers and bits for this, thus avoid mixing them. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230929053915.1530607-10-claudiu.beznea@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a07g043-cpg.c | 7 +++++++ drivers/clk/renesas/r9a07g044-cpg.c | 7 +++++++ drivers/clk/renesas/rzg2l-cpg.h | 4 ---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c index 1a7a6d60aca4..e0ae25644e1a 100644 --- a/drivers/clk/renesas/r9a07g043-cpg.c +++ b/drivers/clk/renesas/r9a07g043-cpg.c @@ -14,6 +14,13 @@ #include "rzg2l-cpg.h" +/* Specific registers. */ +#define CPG_PL2SDHI_DSEL (0x218) + +/* Clock select configuration. */ +#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) +#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) + enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R9A07G043_CLK_P0_DIV2, diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c index c597414a94d8..d4dcf5d896d4 100644 --- a/drivers/clk/renesas/r9a07g044-cpg.c +++ b/drivers/clk/renesas/r9a07g044-cpg.c @@ -15,6 +15,13 @@ #include "rzg2l-cpg.h" +/* Specific registers. */ +#define CPG_PL2SDHI_DSEL (0x218) + +/* Clock select configuration. */ +#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) +#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) + enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A, diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 20da0c620b90..f5382333d327 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -19,7 +19,6 @@ #define CPG_PL2_DDIV (0x204) #define CPG_PL3A_DDIV (0x208) #define CPG_PL6_DDIV (0x210) -#define CPG_PL2SDHI_DSEL (0x218) #define CPG_CLKSTATUS (0x280) #define CPG_PL3_SSEL (0x408) #define CPG_PL6_SSEL (0x414) @@ -69,9 +68,6 @@ #define SEL_PLL6_2 SEL_PLL_PACK(CPG_PL6_ETH_SSEL, 0, 1) #define SEL_GPU2 SEL_PLL_PACK(CPG_PL6_SSEL, 12, 1) -#define SEL_SDHI0 DDIV_PACK(CPG_PL2SDHI_DSEL, 0, 2) -#define SEL_SDHI1 DDIV_PACK(CPG_PL2SDHI_DSEL, 4, 2) - #define EXTAL_FREQ_IN_MEGA_HZ (24) /** From 06eaa531f2dd1a4d5137a1b49e7c762cc3689b14 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 Sep 2023 11:44:43 +0200 Subject: [PATCH 198/396] hte: tegra194: improve the GPIO-related comment Using any of the GPIO interfaces using the global numberspace is deprecated. Make it clear in the comment. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij Reviewed-by: Dipen Patel Signed-off-by: Dipen Patel --- drivers/hte/hte-tegra194.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/hte/hte-tegra194.c b/drivers/hte/hte-tegra194.c index 6fe6897047ac..9fd3c00ff695 100644 --- a/drivers/hte/hte-tegra194.c +++ b/drivers/hte/hte-tegra194.c @@ -407,12 +407,15 @@ static int tegra_hte_line_xlate(struct hte_chip *gc, return -EINVAL; /* + * GPIO consumers can access GPIOs in two ways: * - * There are two paths GPIO consumers can take as follows: - * 1) The consumer (gpiolib-cdev for example) which uses GPIO global - * number which gets assigned run time. - * 2) The consumer passing GPIO from the DT which is assigned - * statically for example by using TEGRA194_AON_GPIO gpio DT binding. + * 1) Using the global GPIO numberspace. + * + * This is the old, now DEPRECATED method and should not be used in + * new code. TODO: Check if tegra is even concerned by this. + * + * 2) Using GPIO descriptors that can be assigned to consumer devices + * using device-tree, ACPI or lookup tables. * * The code below addresses both the consumer use cases and maps into * HTE/GTE namespace. From cdb1013808bed0c0c392b44ed4eed6c7743028c3 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Sun, 10 Sep 2023 19:50:33 +0530 Subject: [PATCH 199/396] platform/x86/amd/pmc: Add PMFW command id to support S2D force flush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent PMFW have the capability that can force flush the FIFO contents to DRAM on sending a command id via the mailbox. Add this support to the driver. Co-developed-by: Sanket Goswami Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20230910142034.2967110-1-Shyam-sundar.S-k@amd.com [ij: Corrected whitespace in dev_dbg_once()] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmc/pmc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index c1e788b67a74..922932a71233 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -55,6 +55,9 @@ #define S2D_TELEMETRY_BYTES_MAX 0x100000 #define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000 +/* STB Spill to DRAM Message Definition */ +#define STB_FORCE_FLUSH_DATA 0xCF + /* Base address of SMU for mapping physical address to virtual address */ #define AMD_PMC_MAPPING_SIZE 0x01000 #define AMD_PMC_BASE_ADDR_OFFSET 0x10000 @@ -236,7 +239,7 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = { static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) { struct amd_pmc_dev *dev = filp->f_inode->i_private; - u32 *buf, fsize, num_samples, stb_rdptr_offset = 0; + u32 *buf, fsize, num_samples, val, stb_rdptr_offset = 0; int ret; /* Write dummy postcode while reading the STB buffer */ @@ -251,6 +254,10 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) /* Spill to DRAM num_samples uses separate SMU message port */ dev->msg_port = 1; + ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1); + if (ret) + dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret); + /* Get the num_samples to calculate the last push location */ ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->s2d_msg_id, true); /* Clear msg_port for other SMU operation */ From 97a5e801b3045c1e800f76bc0fb544972538089d Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:29 -0700 Subject: [PATCH 200/396] platform/x86/intel/ifs: Store IFS generation number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IFS generation number is reported via MSR_INTEGRITY_CAPS. As IFS support gets added to newer CPUs, some differences are expected during IFS image loading and test flows. Define MSR bitmasks to extract and store the generation in driver data, so that driver can modify its MSR interaction appropriately. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Reviewed-by: Ilpo Järvinen Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-2-jithu.joseph@intel.com Signed-off-by: Ilpo Järvinen --- arch/x86/include/asm/msr-index.h | 1 + drivers/platform/x86/intel/ifs/core.c | 3 +++ drivers/platform/x86/intel/ifs/ifs.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 1d111350197f..838e5a013a07 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -222,6 +222,7 @@ #define MSR_INTEGRITY_CAPS_ARRAY_BIST BIT(MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT) #define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4 #define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT) +#define MSR_INTEGRITY_CAPS_SAF_GEN_MASK GENMASK_ULL(10, 9) #define MSR_LBR_NHM_FROM 0x00000680 #define MSR_LBR_NHM_TO 0x000006c0 diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c index 306f886b52d2..4ff2aa4b484b 100644 --- a/drivers/platform/x86/intel/ifs/core.c +++ b/drivers/platform/x86/intel/ifs/core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2022 Intel Corporation. */ +#include #include #include #include @@ -94,6 +95,8 @@ static int __init ifs_init(void) for (i = 0; i < IFS_NUMTESTS; i++) { if (!(msrval & BIT(ifs_devices[i].test_caps->integrity_cap_bit))) continue; + ifs_devices[i].rw_data.generation = FIELD_GET(MSR_INTEGRITY_CAPS_SAF_GEN_MASK, + msrval); ret = misc_register(&ifs_devices[i].misc); if (ret) goto err_exit; diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index 93191855890f..d666aeed20fc 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -229,6 +229,7 @@ struct ifs_test_caps { * @status: it holds simple status pass/fail/untested * @scan_details: opaque scan status code from h/w * @cur_batch: number indicating the currently loaded test file + * @generation: IFS test generation enumerated by hardware */ struct ifs_data { int loaded_version; @@ -238,6 +239,7 @@ struct ifs_data { int status; u64 scan_details; u32 cur_batch; + u32 generation; }; struct ifs_work { From a138ac2656d1329c3994a227769b7ba3926818a7 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:30 -0700 Subject: [PATCH 201/396] platform/x86/intel/ifs: Refactor image loading code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IFS image loading flow is slightly different for newer IFS generations. In preparation for adding support for newer IFS generations, refactor portions of existing image loading code for reuse. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Reviewed-by: Ilpo Järvinen Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-3-jithu.joseph@intel.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/ifs/load.c | 31 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index cefd0d886cfd..851c97cc6a6b 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -80,6 +80,23 @@ static struct metadata_header *find_meta_data(void *ucode, unsigned int meta_typ return NULL; } +static void hashcopy_err_message(struct device *dev, u32 err_code) +{ + if (err_code >= ARRAY_SIZE(scan_hash_status)) + dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code); + else + dev_err(dev, "Hash copy error : %s\n", scan_hash_status[err_code]); +} + +static void auth_err_message(struct device *dev, u32 err_code) +{ + if (err_code >= ARRAY_SIZE(scan_authentication_status)) + dev_err(dev, "invalid error code 0x%x for authentication\n", err_code); + else + dev_err(dev, "Chunk authentication error : %s\n", + scan_authentication_status[err_code]); +} + /* * To copy scan hashes and authenticate test chunks, the initiating cpu must point * to the EDX:EAX to the test image in linear address. @@ -109,11 +126,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work) if (!hashes_status.valid) { ifsd->loading_error = true; - if (err_code >= ARRAY_SIZE(scan_hash_status)) { - dev_err(dev, "invalid error code 0x%x for hash copy\n", err_code); - goto done; - } - dev_err(dev, "Hash copy error : %s", scan_hash_status[err_code]); + hashcopy_err_message(dev, err_code); goto done; } @@ -133,13 +146,7 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work) if (err_code) { ifsd->loading_error = true; - if (err_code >= ARRAY_SIZE(scan_authentication_status)) { - dev_err(dev, - "invalid error code 0x%x for authentication\n", err_code); - goto done; - } - dev_err(dev, "Chunk authentication error %s\n", - scan_authentication_status[err_code]); + auth_err_message(dev, err_code); goto done; } } From 07f47c01b3bc2a42c4d4da35831edab10aa60449 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:31 -0700 Subject: [PATCH 202/396] platform/x86/intel/ifs: Gen2 scan image loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scan image loading flow for newer IFS generations are slightly different from that of current generation. In newer schemes, loading need not be done once for each socket as was done in gen0. Also the width of NUM_CHUNKS bitfield in SCAN_HASHES_STATUS MSR has increased from 8 -> 16 bits. Similarly there are width differences for CHUNK_AUTHENTICATION_STATUS too. Further the parameter to AUTHENTICATE_AND_COPY_CHUNK is passed differently in newer generations. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Reviewed-by: Ilpo Järvinen Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-4-jithu.joseph@intel.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/ifs/ifs.h | 27 +++++++ drivers/platform/x86/intel/ifs/load.c | 112 +++++++++++++++++++++++++- 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index d666aeed20fc..4824316b3acd 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -137,6 +137,8 @@ #define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5 #define MSR_ACTIVATE_SCAN 0x000002c6 #define MSR_SCAN_STATUS 0x000002c7 +#define MSR_SAF_CTRL 0x000004f0 + #define SCAN_NOT_TESTED 0 #define SCAN_TEST_PASS 1 #define SCAN_TEST_FAIL 2 @@ -158,6 +160,19 @@ union ifs_scan_hashes_status { }; }; +union ifs_scan_hashes_status_gen2 { + u64 data; + struct { + u16 chunk_size; + u16 num_chunks; + u32 error_code :8; + u32 chunks_in_stride :9; + u32 rsvd :2; + u32 max_core_limit :12; + u32 valid :1; + }; +}; + /* MSR_CHUNKS_AUTH_STATUS bit fields */ union ifs_chunks_auth_status { u64 data; @@ -170,6 +185,16 @@ union ifs_chunks_auth_status { }; }; +union ifs_chunks_auth_status_gen2 { + u64 data; + struct { + u16 valid_chunks; + u16 total_chunks; + u32 error_code :8; + u32 rsvd2 :24; + }; +}; + /* MSR_ACTIVATE_SCAN bit fields */ union ifs_scan { u64 data; @@ -230,6 +255,7 @@ struct ifs_test_caps { * @scan_details: opaque scan status code from h/w * @cur_batch: number indicating the currently loaded test file * @generation: IFS test generation enumerated by hardware + * @chunk_size: size of a test chunk */ struct ifs_data { int loaded_version; @@ -240,6 +266,7 @@ struct ifs_data { u64 scan_details; u32 cur_batch; u32 generation; + u32 chunk_size; }; struct ifs_work { diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index 851c97cc6a6b..6b827247945b 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -2,6 +2,7 @@ /* Copyright(c) 2022 Intel Corporation. */ #include +#include #include #include @@ -26,6 +27,11 @@ union meta_data { #define IFS_HEADER_SIZE (sizeof(struct microcode_header_intel)) #define META_TYPE_IFS 1 +#define INVALIDATE_STRIDE 0x1UL +#define IFS_GEN_STRIDE_AWARE 2 +#define AUTH_INTERRUPTED_ERROR 5 +#define IFS_AUTH_RETRY_CT 10 + static struct microcode_header_intel *ifs_header_ptr; /* pointer to the ifs image header */ static u64 ifs_hash_ptr; /* Address of ifs metadata (hash) */ static u64 ifs_test_image_ptr; /* 256B aligned address of test pattern */ @@ -44,7 +50,10 @@ static const char * const scan_hash_status[] = { static const char * const scan_authentication_status[] = { [0] = "No error reported", [1] = "Attempt to authenticate a chunk which is already marked as authentic", - [2] = "Chunk authentication error. The hash of chunk did not match expected value" + [2] = "Chunk authentication error. The hash of chunk did not match expected value", + [3] = "Reserved", + [4] = "Chunk outside the current stride", + [5] = "Authentication flow interrupted", }; #define MC_HEADER_META_TYPE_END (0) @@ -154,6 +163,102 @@ done: complete(&ifs_done); } +static int get_num_chunks(int gen, union ifs_scan_hashes_status_gen2 status) +{ + return gen >= IFS_GEN_STRIDE_AWARE ? status.chunks_in_stride : status.num_chunks; +} + +static bool need_copy_scan_hashes(struct ifs_data *ifsd) +{ + return !ifsd->loaded || + ifsd->generation < IFS_GEN_STRIDE_AWARE || + ifsd->loaded_version != ifs_header_ptr->rev; +} + +static int copy_hashes_authenticate_chunks_gen2(struct device *dev) +{ + union ifs_scan_hashes_status_gen2 hashes_status; + union ifs_chunks_auth_status_gen2 chunk_status; + u32 err_code, valid_chunks, total_chunks; + int i, num_chunks, chunk_size; + union meta_data *ifs_meta; + int starting_chunk_nr; + struct ifs_data *ifsd; + u64 linear_addr, base; + u64 chunk_table[2]; + int retry_count; + + ifsd = ifs_get_data(dev); + + if (need_copy_scan_hashes(ifsd)) { + wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr); + rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data); + + /* enumerate the scan image information */ + chunk_size = hashes_status.chunk_size * SZ_1K; + err_code = hashes_status.error_code; + + num_chunks = get_num_chunks(ifsd->generation, hashes_status); + + if (!hashes_status.valid) { + hashcopy_err_message(dev, err_code); + return -EIO; + } + ifsd->loaded_version = ifs_header_ptr->rev; + ifsd->chunk_size = chunk_size; + } else { + num_chunks = ifsd->valid_chunks; + chunk_size = ifsd->chunk_size; + } + + if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) { + wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE); + rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); + if (chunk_status.valid_chunks != 0) { + dev_err(dev, "Couldn't invalidate installed stride - %d\n", + chunk_status.valid_chunks); + return -EIO; + } + } + + base = ifs_test_image_ptr; + ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS); + starting_chunk_nr = ifs_meta->starting_chunk; + + /* scan data authentication and copy chunks to secured memory */ + for (i = 0; i < num_chunks; i++) { + retry_count = IFS_AUTH_RETRY_CT; + linear_addr = base + i * chunk_size; + + chunk_table[0] = starting_chunk_nr + i; + chunk_table[1] = linear_addr; + do { + wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table); + rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data); + err_code = chunk_status.error_code; + } while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count); + + if (err_code) { + ifsd->loading_error = true; + auth_err_message(dev, err_code); + return -EIO; + } + } + + valid_chunks = chunk_status.valid_chunks; + total_chunks = chunk_status.total_chunks; + + if (valid_chunks != total_chunks) { + ifsd->loading_error = true; + dev_err(dev, "Couldn't authenticate all the chunks. Authenticated %d total %d.\n", + valid_chunks, total_chunks); + return -EIO; + } + ifsd->valid_chunks = valid_chunks; + + return 0; +} + static int validate_ifs_metadata(struct device *dev) { struct ifs_data *ifsd = ifs_get_data(dev); @@ -206,7 +311,9 @@ static int scan_chunks_sanity_check(struct device *dev) return ret; ifsd->loading_error = false; - ifsd->loaded_version = ifs_header_ptr->rev; + + if (ifsd->generation > 0) + return copy_hashes_authenticate_chunks_gen2(dev); /* copy the scan hash and authenticate per package */ cpus_read_lock(); @@ -226,6 +333,7 @@ static int scan_chunks_sanity_check(struct device *dev) ifs_pkg_auth[curr_pkg] = 1; } ret = 0; + ifsd->loaded_version = ifs_header_ptr->rev; out: cpus_read_unlock(); From 72b96ee29ed6f7670bbb180ba694816e33d361d1 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:32 -0700 Subject: [PATCH 203/396] platform/x86/intel/ifs: Gen2 Scan test support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Width of chunk related bitfields is ACTIVATE_SCAN and SCAN_STATUS MSRs are different in newer IFS generation compared to gen0. Make changes to scan test flow such that MSRs are populated appropriately based on the generation supported by hardware. Account for the 8/16 bit MSR bitfield width differences between gen0 and newer generations for the scan test trace event too. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Reviewed-by: Ilpo Järvinen Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-5-jithu.joseph@intel.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/ifs/ifs.h | 28 ++++++++++++++++++----- drivers/platform/x86/intel/ifs/runtest.c | 29 ++++++++++++++++++------ include/trace/events/intel_ifs.h | 16 ++++++------- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index 4824316b3acd..f0dd849b3400 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -199,9 +199,17 @@ union ifs_chunks_auth_status_gen2 { union ifs_scan { u64 data; struct { - u32 start :8; - u32 stop :8; - u32 rsvd :16; + union { + struct { + u8 start; + u8 stop; + u16 rsvd; + } gen0; + struct { + u16 start; + u16 stop; + } gen2; + }; u32 delay :31; u32 sigmce :1; }; @@ -211,9 +219,17 @@ union ifs_scan { union ifs_status { u64 data; struct { - u32 chunk_num :8; - u32 chunk_stop_index :8; - u32 rsvd1 :16; + union { + struct { + u8 chunk_num; + u8 chunk_stop_index; + u16 rsvd1; + } gen0; + struct { + u16 chunk_num; + u16 chunk_stop_index; + } gen2; + }; u32 error_code :8; u32 rsvd2 :22; u32 control_error :1; diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c index 1061eb7ec399..925c30c79011 100644 --- a/drivers/platform/x86/intel/ifs/runtest.c +++ b/drivers/platform/x86/intel/ifs/runtest.c @@ -171,21 +171,31 @@ static void ifs_test_core(int cpu, struct device *dev) union ifs_status status; unsigned long timeout; struct ifs_data *ifsd; + int to_start, to_stop; + int status_chunk; u64 msrvals[2]; int retries; ifsd = ifs_get_data(dev); - activate.rsvd = 0; + activate.gen0.rsvd = 0; activate.delay = IFS_THREAD_WAIT; activate.sigmce = 0; - activate.start = 0; - activate.stop = ifsd->valid_chunks - 1; + to_start = 0; + to_stop = ifsd->valid_chunks - 1; + + if (ifsd->generation) { + activate.gen2.start = to_start; + activate.gen2.stop = to_stop; + } else { + activate.gen0.start = to_start; + activate.gen0.stop = to_stop; + } timeout = jiffies + HZ / 2; retries = MAX_IFS_RETRIES; - while (activate.start <= activate.stop) { + while (to_start <= to_stop) { if (time_after(jiffies, timeout)) { status.error_code = IFS_SW_TIMEOUT; break; @@ -196,13 +206,14 @@ static void ifs_test_core(int cpu, struct device *dev) status.data = msrvals[1]; - trace_ifs_status(cpu, activate, status); + trace_ifs_status(cpu, to_start, to_stop, status.data); /* Some cases can be retried, give up for others */ if (!can_restart(status)) break; - if (status.chunk_num == activate.start) { + status_chunk = ifsd->generation ? status.gen2.chunk_num : status.gen0.chunk_num; + if (status_chunk == to_start) { /* Check for forward progress */ if (--retries == 0) { if (status.error_code == IFS_NO_ERROR) @@ -211,7 +222,11 @@ static void ifs_test_core(int cpu, struct device *dev) } } else { retries = MAX_IFS_RETRIES; - activate.start = status.chunk_num; + if (ifsd->generation) + activate.gen2.start = status_chunk; + else + activate.gen0.start = status_chunk; + to_start = status_chunk; } } diff --git a/include/trace/events/intel_ifs.h b/include/trace/events/intel_ifs.h index d7353024016c..af0af3f1d9b7 100644 --- a/include/trace/events/intel_ifs.h +++ b/include/trace/events/intel_ifs.h @@ -10,25 +10,25 @@ TRACE_EVENT(ifs_status, - TP_PROTO(int cpu, union ifs_scan activate, union ifs_status status), + TP_PROTO(int cpu, int start, int stop, u64 status), - TP_ARGS(cpu, activate, status), + TP_ARGS(cpu, start, stop, status), TP_STRUCT__entry( __field( u64, status ) __field( int, cpu ) - __field( u8, start ) - __field( u8, stop ) + __field( u16, start ) + __field( u16, stop ) ), TP_fast_assign( __entry->cpu = cpu; - __entry->start = activate.start; - __entry->stop = activate.stop; - __entry->status = status.data; + __entry->start = start; + __entry->stop = stop; + __entry->status = status; ), - TP_printk("cpu: %d, start: %.2x, stop: %.2x, status: %llx", + TP_printk("cpu: %d, start: %.4x, stop: %.4x, status: %.16llx", __entry->cpu, __entry->start, __entry->stop, From 25a76dbb36dd58ad4df7f6a4dc43061a10b0d817 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:33 -0700 Subject: [PATCH 204/396] platform/x86/intel/ifs: Validate image size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Perform additional validation prior to loading IFS image. Error out if the size of the file being loaded doesn't match the size specified in the header. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Reviewed-by: Ilpo Järvinen Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-6-jithu.joseph@intel.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/ifs/load.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index 6b827247945b..582f1801aaaa 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -375,6 +375,7 @@ int ifs_load_firmware(struct device *dev) { const struct ifs_test_caps *test = ifs_get_test_caps(dev); struct ifs_data *ifsd = ifs_get_data(dev); + unsigned int expected_size; const struct firmware *fw; char scan_path[64]; int ret = -EINVAL; @@ -389,6 +390,13 @@ int ifs_load_firmware(struct device *dev) goto done; } + expected_size = ((struct microcode_header_intel *)fw->data)->totalsize; + if (fw->size != expected_size) { + dev_err(dev, "File size mismatch (expected %u, actual %zu). Corrupted IFS image.\n", + expected_size, fw->size); + return -EINVAL; + } + ret = image_sanity_check(dev, (struct microcode_header_intel *)fw->data); if (ret) goto release; From 60d2e1b37d530d6b1f8b7773cebaf8bbc1536b28 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:34 -0700 Subject: [PATCH 205/396] platform/x86/intel/ifs: Metadata validation for start_chunk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an additional check to validate IFS image metadata field prior to loading the test image. If start_chunk is not a multiple of chunks_per_stride error out. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-7-jithu.joseph@intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/ifs/load.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c index 582f1801aaaa..959b1878cae6 100644 --- a/drivers/platform/x86/intel/ifs/load.c +++ b/drivers/platform/x86/intel/ifs/load.c @@ -291,6 +291,13 @@ static int validate_ifs_metadata(struct device *dev) return ret; } + if (ifs_meta->chunks_per_stride && + (ifs_meta->starting_chunk % ifs_meta->chunks_per_stride != 0)) { + dev_warn(dev, "Starting chunk num %u not a multiple of chunks_per_stride %u\n", + ifs_meta->starting_chunk, ifs_meta->chunks_per_stride); + return ret; + } + return 0; } From e6483a0b59026ded36a6f5eba1425a6b0965984a Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:35 -0700 Subject: [PATCH 206/396] platform/x86/intel/ifs: Add new CPU support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Granite Rapids(GNR) and Sierra Forest(SRF) cpuids to x86 match table so that IFS driver can be loaded for those. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Reviewed-by: Ilpo Järvinen Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-8-jithu.joseph@intel.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/ifs/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c index 4ff2aa4b484b..0c8927916373 100644 --- a/drivers/platform/x86/intel/ifs/core.c +++ b/drivers/platform/x86/intel/ifs/core.c @@ -18,6 +18,9 @@ static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { X86_MATCH(SAPPHIRERAPIDS_X), X86_MATCH(EMERALDRAPIDS_X), + X86_MATCH(GRANITERAPIDS_X), + X86_MATCH(GRANITERAPIDS_D), + X86_MATCH(ATOM_CRESTMONT_X), {} }; MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); From b9aa9e4c8b4e52b6f2f5986b27e97f4b6163f0bf Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:36 -0700 Subject: [PATCH 207/396] platform/x86/intel/ifs: Add new error code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make driver aware of a newly added error code so that it can provide a more appropriate error message. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Reviewed-by: Ilpo Järvinen Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-9-jithu.joseph@intel.com Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/ifs/runtest.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c index 925c30c79011..4fe544d79946 100644 --- a/drivers/platform/x86/intel/ifs/runtest.c +++ b/drivers/platform/x86/intel/ifs/runtest.c @@ -40,6 +40,8 @@ enum ifs_status_err_code { IFS_UNASSIGNED_ERROR_CODE = 7, IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT = 8, IFS_INTERRUPTED_DURING_EXECUTION = 9, + IFS_UNASSIGNED_ERROR_CODE_0xA = 0xA, + IFS_CORRUPTED_CHUNK = 0xB, }; static const char * const scan_test_status[] = { @@ -55,6 +57,8 @@ static const char * const scan_test_status[] = { [IFS_EXCEED_NUMBER_OF_THREADS_CONCURRENT] = "Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently", [IFS_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SCAN start", + [IFS_UNASSIGNED_ERROR_CODE_0xA] = "Unassigned error code 0xA", + [IFS_CORRUPTED_CHUNK] = "Scan operation aborted due to corrupted image. Try reloading", }; static void message_not_tested(struct device *dev, int cpu, union ifs_status status) @@ -123,6 +127,8 @@ static bool can_restart(union ifs_status status) case IFS_MISMATCH_ARGUMENTS_BETWEEN_THREADS: case IFS_CORE_NOT_CAPABLE_CURRENTLY: case IFS_UNASSIGNED_ERROR_CODE: + case IFS_UNASSIGNED_ERROR_CODE_0xA: + case IFS_CORRUPTED_CHUNK: break; } return false; From 06d65b2bc532fc9af1c55aa7a18cfd237ce46588 Mon Sep 17 00:00:00 2001 From: Jithu Joseph Date: Thu, 5 Oct 2023 12:51:37 -0700 Subject: [PATCH 208/396] platform/x86/intel/ifs: ARRAY BIST for Sierra Forest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Array BIST MSR addresses, bit definition and semantics are different for Sierra Forest. Branch into a separate Array BIST flow on Sierra Forest when user invokes Array Test. Signed-off-by: Jithu Joseph Reviewed-by: Tony Luck Tested-by: Pengfei Xu Link: https://lore.kernel.org/r/20231005195137.3117166-10-jithu.joseph@intel.com [ij: ARRAY_GEN_* -> ARRAY_GEN* for consistency] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/ifs/core.c | 15 +++++----- drivers/platform/x86/intel/ifs/ifs.h | 7 +++++ drivers/platform/x86/intel/ifs/runtest.c | 37 +++++++++++++++++++++++- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c index 0c8927916373..7b11198d85a1 100644 --- a/drivers/platform/x86/intel/ifs/core.c +++ b/drivers/platform/x86/intel/ifs/core.c @@ -11,16 +11,16 @@ #include "ifs.h" -#define X86_MATCH(model) \ +#define X86_MATCH(model, array_gen) \ X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, \ - INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, NULL) + INTEL_FAM6_##model, X86_FEATURE_CORE_CAPABILITIES, array_gen) static const struct x86_cpu_id ifs_cpu_ids[] __initconst = { - X86_MATCH(SAPPHIRERAPIDS_X), - X86_MATCH(EMERALDRAPIDS_X), - X86_MATCH(GRANITERAPIDS_X), - X86_MATCH(GRANITERAPIDS_D), - X86_MATCH(ATOM_CRESTMONT_X), + X86_MATCH(SAPPHIRERAPIDS_X, ARRAY_GEN0), + X86_MATCH(EMERALDRAPIDS_X, ARRAY_GEN0), + X86_MATCH(GRANITERAPIDS_X, ARRAY_GEN0), + X86_MATCH(GRANITERAPIDS_D, ARRAY_GEN0), + X86_MATCH(ATOM_CRESTMONT_X, ARRAY_GEN1), {} }; MODULE_DEVICE_TABLE(x86cpu, ifs_cpu_ids); @@ -100,6 +100,7 @@ static int __init ifs_init(void) continue; ifs_devices[i].rw_data.generation = FIELD_GET(MSR_INTEGRITY_CAPS_SAF_GEN_MASK, msrval); + ifs_devices[i].rw_data.array_gen = (u32)m->driver_data; ret = misc_register(&ifs_devices[i].misc); if (ret) goto err_exit; diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h index f0dd849b3400..56b9f3e3cf76 100644 --- a/drivers/platform/x86/intel/ifs/ifs.h +++ b/drivers/platform/x86/intel/ifs/ifs.h @@ -137,6 +137,8 @@ #define MSR_CHUNKS_AUTHENTICATION_STATUS 0x000002c5 #define MSR_ACTIVATE_SCAN 0x000002c6 #define MSR_SCAN_STATUS 0x000002c7 +#define MSR_ARRAY_TRIGGER 0x000002d6 +#define MSR_ARRAY_STATUS 0x000002d7 #define MSR_SAF_CTRL 0x000004f0 #define SCAN_NOT_TESTED 0 @@ -146,6 +148,9 @@ #define IFS_TYPE_SAF 0 #define IFS_TYPE_ARRAY_BIST 1 +#define ARRAY_GEN0 0 +#define ARRAY_GEN1 1 + /* MSR_SCAN_HASHES_STATUS bit fields */ union ifs_scan_hashes_status { u64 data; @@ -272,6 +277,7 @@ struct ifs_test_caps { * @cur_batch: number indicating the currently loaded test file * @generation: IFS test generation enumerated by hardware * @chunk_size: size of a test chunk + * @array_gen: test generation of array test */ struct ifs_data { int loaded_version; @@ -283,6 +289,7 @@ struct ifs_data { u32 cur_batch; u32 generation; u32 chunk_size; + u32 array_gen; }; struct ifs_work { diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c index 4fe544d79946..9c1a027bc591 100644 --- a/drivers/platform/x86/intel/ifs/runtest.c +++ b/drivers/platform/x86/intel/ifs/runtest.c @@ -329,6 +329,38 @@ static void ifs_array_test_core(int cpu, struct device *dev) ifsd->status = SCAN_TEST_PASS; } +#define ARRAY_GEN1_TEST_ALL_ARRAYS 0x0ULL +#define ARRAY_GEN1_STATUS_FAIL 0x1ULL + +static int do_array_test_gen1(void *status) +{ + int cpu = smp_processor_id(); + int first; + + first = cpumask_first(cpu_smt_mask(cpu)); + + if (cpu == first) { + wrmsrl(MSR_ARRAY_TRIGGER, ARRAY_GEN1_TEST_ALL_ARRAYS); + rdmsrl(MSR_ARRAY_STATUS, *((u64 *)status)); + } + + return 0; +} + +static void ifs_array_test_gen1(int cpu, struct device *dev) +{ + struct ifs_data *ifsd = ifs_get_data(dev); + u64 status = 0; + + stop_core_cpuslocked(cpu, do_array_test_gen1, &status); + ifsd->scan_details = status; + + if (status & ARRAY_GEN1_STATUS_FAIL) + ifsd->status = SCAN_TEST_FAIL; + else + ifsd->status = SCAN_TEST_PASS; +} + /* * Initiate per core test. It wakes up work queue threads on the target cpu and * its sibling cpu. Once all sibling threads wake up, the scan test gets executed and @@ -356,7 +388,10 @@ int do_core_test(int cpu, struct device *dev) ifs_test_core(cpu, dev); break; case IFS_TYPE_ARRAY_BIST: - ifs_array_test_core(cpu, dev); + if (ifsd->array_gen == ARRAY_GEN0) + ifs_array_test_core(cpu, dev); + else + ifs_array_test_gen1(cpu, dev); break; default: return -EINVAL; From b26bcdd5f03e0b9fdd5dd8567b620538c5058c54 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 5 Oct 2023 07:56:16 +0000 Subject: [PATCH 209/396] platform: mellanox: Rename some init()/exit() functions for consistent naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently some names of init()/exit() pairing function are not consistent. Rename pair mlxplat_pre_init()/mlxplat_post_exit() to respectively mlxplat_logicdev_init()/mlxplat_logicdev_exit(). Rename pair mlxplat_post_init()/mlxplat_pre_exit() to respectively mlxplat_platdevs_init()/mlxplat_platdevs_exit(). Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20231005075616.42777-4-vadimp@nvidia.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/mlx-platform.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index a2ffe4157df1..b9c709d7dbe0 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -6291,7 +6291,7 @@ static void mlxplat_pci_fpga_devices_exit(void) } static int -mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size) +mlxplat_logicdev_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size) { int err; @@ -6302,7 +6302,7 @@ mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_reso return err; } -static void mlxplat_post_exit(void) +static void mlxplat_logicdev_exit(void) { if (lpc_bridge) mlxplat_pci_fpga_devices_exit(); @@ -6310,7 +6310,7 @@ static void mlxplat_post_exit(void) mlxplat_lpc_cpld_device_exit(); } -static int mlxplat_post_init(struct mlxplat_priv *priv) +static int mlxplat_platdevs_init(struct mlxplat_priv *priv) { int i = 0, err; @@ -6407,7 +6407,7 @@ fail_platform_hotplug_register: return err; } -static void mlxplat_pre_exit(struct mlxplat_priv *priv) +static void mlxplat_platdevs_exit(struct mlxplat_priv *priv) { int i; @@ -6429,7 +6429,7 @@ mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent, { struct mlxplat_priv *priv = handle; - return mlxplat_post_init(priv); + return mlxplat_platdevs_init(priv); } static int mlxplat_i2c_mux_topology_init(struct mlxplat_priv *priv) @@ -6522,7 +6522,7 @@ fail_mlxplat_mlxcpld_verify_bus_topology: static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv) { - mlxplat_pre_exit(priv); + mlxplat_platdevs_exit(priv); mlxplat_i2c_mux_topology_exit(priv); if (priv->pdev_i2c) platform_device_unregister(priv->pdev_i2c); @@ -6544,7 +6544,7 @@ static int mlxplat_probe(struct platform_device *pdev) mlxplat_dev = pdev; } - err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size); + err = mlxplat_logicdev_init(&hotplug_resources, &hotplug_resources_size); if (err) return err; @@ -6603,7 +6603,7 @@ fail_regcache_sync: fail_mlxplat_i2c_main_init: fail_regmap_write: fail_alloc: - mlxplat_post_exit(); + mlxplat_logicdev_exit(); return err; } @@ -6617,7 +6617,7 @@ static int mlxplat_remove(struct platform_device *pdev) if (mlxplat_reboot_nb) unregister_reboot_notifier(mlxplat_reboot_nb); mlxplat_i2c_main_exit(priv); - mlxplat_post_exit(); + mlxplat_logicdev_exit(); return 0; } From 8634c1114b94049b48805b412b28160cb25a3198 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 5 Oct 2023 07:56:15 +0000 Subject: [PATCH 210/396] platform: mellanox: Fix misspelling error in routine name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change mlxplat_i2c_main_complition_notify() to mlxplat_i2c_main_completion_notify(). Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20231005075616.42777-3-vadimp@nvidia.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/mlx-platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index b9c709d7dbe0..1bad4c64f36c 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -368,7 +368,7 @@ struct mlxplat_priv { }; static struct platform_device *mlxplat_dev; -static int mlxplat_i2c_main_complition_notify(void *handle, int id); +static int mlxplat_i2c_main_completion_notify(void *handle, int id); static void __iomem *i2c_bridge_addr, *jtag_bridge_addr; /* Regions for LPC I2C controller and LPC base register space */ @@ -384,7 +384,7 @@ static const struct resource mlxplat_lpc_resources[] = { /* Platform systems default i2c data */ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_default_data = { - .completion_notify = mlxplat_i2c_main_complition_notify, + .completion_notify = mlxplat_i2c_main_completion_notify, }; /* Platform i2c next generation systems data */ @@ -409,7 +409,7 @@ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C, - .completion_notify = mlxplat_i2c_main_complition_notify, + .completion_notify = mlxplat_i2c_main_completion_notify, }; /* Platform default channels */ @@ -6471,7 +6471,7 @@ static void mlxplat_i2c_mux_topology_exit(struct mlxplat_priv *priv) } } -static int mlxplat_i2c_main_complition_notify(void *handle, int id) +static int mlxplat_i2c_main_completion_notify(void *handle, int id) { struct mlxplat_priv *priv = handle; From ff54dc31fbee363f3bbae85b99b1390dc02ce062 Mon Sep 17 00:00:00 2001 From: Nikita Kravets Date: Fri, 6 Oct 2023 20:53:55 +0300 Subject: [PATCH 211/396] platform/x86: msi-ec: rename fn_super_swap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch renames fn_super_swap to fn_win_swap for consistency with the downstream version of the driver. Renaming the field to fn_super_swap in the downstream driver would require modifying several branches that are yet to be merged into the main branch, so I decided to do it here instead. Cc: Aakash Singh Cc: Jose Angel Pastrana Signed-off-by: Nikita Kravets Link: https://lore.kernel.org/r/20231006175352.1753017-7-teackot@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/msi-ec.c | 16 ++++++++-------- drivers/platform/x86/msi-ec.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c index f26a3121092f..48311d5a41ce 100644 --- a/drivers/platform/x86/msi-ec.c +++ b/drivers/platform/x86/msi-ec.c @@ -58,7 +58,7 @@ static struct msi_ec_conf CONF0 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xbf, .bit = 4, }, @@ -138,7 +138,7 @@ static struct msi_ec_conf CONF1 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xbf, .bit = 4, }, @@ -215,7 +215,7 @@ static struct msi_ec_conf CONF2 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xe8, .bit = 4, }, @@ -294,7 +294,7 @@ static struct msi_ec_conf CONF3 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xe8, .bit = 4, }, @@ -372,7 +372,7 @@ static struct msi_ec_conf CONF4 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = MSI_EC_ADDR_UNKNOWN, // supported, but unknown .bit = 4, }, @@ -451,7 +451,7 @@ static struct msi_ec_conf CONF5 __initdata = { .block_address = 0x2f, .bit = 1, }, - .fn_super_swap = { // todo: reverse + .fn_win_swap = { // todo: reverse .address = 0xbf, .bit = 4, }, @@ -529,7 +529,7 @@ static struct msi_ec_conf CONF6 __initdata = { .block_address = MSI_EC_ADDR_UNSUPP, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xbf, // todo: reverse .bit = 4, }, @@ -609,7 +609,7 @@ static struct msi_ec_conf CONF7 __initdata = { .block_address = MSI_EC_ADDR_UNSUPP, .bit = 1, }, - .fn_super_swap = { + .fn_win_swap = { .address = 0xbf, // needs testing .bit = 4, }, diff --git a/drivers/platform/x86/msi-ec.h b/drivers/platform/x86/msi-ec.h index be3533dc9cc6..086351217505 100644 --- a/drivers/platform/x86/msi-ec.h +++ b/drivers/platform/x86/msi-ec.h @@ -40,7 +40,7 @@ struct msi_ec_webcam_conf { int bit; }; -struct msi_ec_fn_super_swap_conf { +struct msi_ec_fn_win_swap_conf { int address; int bit; }; @@ -108,7 +108,7 @@ struct msi_ec_conf { struct msi_ec_charge_control_conf charge_control; struct msi_ec_webcam_conf webcam; - struct msi_ec_fn_super_swap_conf fn_super_swap; + struct msi_ec_fn_win_swap_conf fn_win_swap; struct msi_ec_cooler_boost_conf cooler_boost; struct msi_ec_shift_mode_conf shift_mode; struct msi_ec_super_battery_conf super_battery; From 8abba08944663add37111dd6bc4f2916fd6d9085 Mon Sep 17 00:00:00 2001 From: Nikita Kravets Date: Fri, 6 Oct 2023 20:53:57 +0300 Subject: [PATCH 212/396] platform/x86: msi-ec: Add more EC configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds configurations for new EC firmware from the downstream version of the driver. Cc: Aakash Singh Cc: Jose Angel Pastrana Signed-off-by: Nikita Kravets Link: https://lore.kernel.org/r/20231006175352.1753017-9-teackot@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/msi-ec.c | 467 ++++++++++++++++++++++++++++++++++ 1 file changed, 467 insertions(+) diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c index 48311d5a41ce..2be92ba45926 100644 --- a/drivers/platform/x86/msi-ec.c +++ b/drivers/platform/x86/msi-ec.c @@ -668,6 +668,467 @@ static struct msi_ec_conf CONF7 __initdata = { }, }; +static const char * const ALLOWED_FW_8[] __initconst = { + "14F1EMS1.115", + NULL +}; + +static struct msi_ec_conf CONF8 __initdata = { + .allowed_fw = ALLOWED_FW_8, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = MSI_EC_ADDR_UNSUPP, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xe8, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = 0xeb, + .mask = 0x0f, + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_BASIC_NAME, 0x4d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, + .rt_fan_speed_base_min = 0x19, + .rt_fan_speed_base_max = 0x37, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = MSI_EC_ADDR_UNKNOWN, + .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN, + }, + .leds = { + .micmute_led_address = MSI_EC_ADDR_UNSUPP, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ? + .bl_modes = { 0x00, 0x08 }, // ? + .max_mode = 1, // ? + .bl_state_address = MSI_EC_ADDR_UNSUPP, // not functional + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_9[] __initconst = { + "14JKEMS1.104", + NULL +}; + +static struct msi_ec_conf CONF9 __initdata = { + .allowed_fw = ALLOWED_FW_9, + .charge_control = { + .address = 0xef, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = 0x2f, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xbf, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xf2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift + .mask = 0x0f, + }, + .fan_mode = { + .address = 0xf4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x8d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, + .rt_fan_speed_base_min = 0x00, + .rt_fan_speed_base_max = 0x96, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = MSI_EC_ADDR_UNSUPP, + .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, + }, + .leds = { + .micmute_led_address = 0x2b, + .mute_led_address = 0x2c, + .bit = 2, + }, + .kbd_bl = { + .bl_mode_address = MSI_EC_ADDR_UNSUPP, // not presented in MSI app + .bl_modes = { 0x00, 0x08 }, + .max_mode = 1, + .bl_state_address = 0xf3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_10[] __initconst = { + "1582EMS1.107", // GF66 11UC + NULL +}; + +static struct msi_ec_conf CONF10 __initdata = { + .allowed_fw = ALLOWED_FW_10, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = 0x2f, + .bit = 1, + }, + .fn_win_swap = { + .address = MSI_EC_ADDR_UNSUPP, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + { SM_TURBO_NAME, 0xc4 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = 0xe5, + .mask = 0x0f, + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x8d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, // ? + .rt_fan_speed_base_min = 0x19, + .rt_fan_speed_base_max = 0x37, + .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, // ? + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = 0x80, + .rt_fan_speed_address = 0x89, + }, + .leds = { + .micmute_led_address = 0x2c, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = 0x2c, + .bl_modes = { 0x00, 0x08 }, + .max_mode = 1, + .bl_state_address = 0xd3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_11[] __initconst = { + "16S6EMS1.111", // Prestige 15 a11scx + "1552EMS1.115", // Modern 15 a11m + NULL +}; + +static struct msi_ec_conf CONF11 __initdata = { + .allowed_fw = ALLOWED_FW_11, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = MSI_EC_ADDR_UNKNOWN, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xe8, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = 0xeb, + .mask = 0x0f, + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x4d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + }, + .gpu = { + .rt_temp_address = MSI_EC_ADDR_UNSUPP, + .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, + }, + .leds = { + .micmute_led_address = 0x2c, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = MSI_EC_ADDR_UNKNOWN, + .bl_modes = {}, // ? + .max_mode = 1, // ? + .bl_state_address = 0xd3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_12[] __initconst = { + "16R6EMS1.104", // GF63 Thin 11UC + NULL +}; + +static struct msi_ec_conf CONF12 __initdata = { + .allowed_fw = ALLOWED_FW_12, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = 0x2f, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xe8, + .bit = 4, + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, + { SM_COMFORT_NAME, 0xc1 }, + { SM_SPORT_NAME, 0xc0 }, + { SM_TURBO_NAME, 0xc4 }, + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = MSI_EC_ADDR_UNSUPP, // 0xeb + .mask = 0x0f, // 00, 0f + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x8d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, + .rt_fan_speed_base_min = 0x19, + .rt_fan_speed_base_max = 0x37, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = MSI_EC_ADDR_UNSUPP, + .rt_fan_speed_address = 0x89, + }, + .leds = { + .micmute_led_address = MSI_EC_ADDR_UNSUPP, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = MSI_EC_ADDR_UNKNOWN, + .bl_modes = { 0x00, 0x08 }, + .max_mode = 1, + .bl_state_address = 0xd3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + +static const char * const ALLOWED_FW_13[] __initconst = { + "1594EMS1.109", // MSI Prestige 16 Studio A13VE + NULL +}; + +static struct msi_ec_conf CONF13 __initdata = { + .allowed_fw = ALLOWED_FW_13, + .charge_control = { + .address = 0xd7, + .offset_start = 0x8a, + .offset_end = 0x80, + .range_min = 0x8a, + .range_max = 0xe4, + }, + .webcam = { + .address = 0x2e, + .block_address = 0x2f, + .bit = 1, + }, + .fn_win_swap = { + .address = 0xe8, + .bit = 4, // 0x00-0x10 + }, + .cooler_boost = { + .address = 0x98, + .bit = 7, + }, + .shift_mode = { + .address = 0xd2, + .modes = { + { SM_ECO_NAME, 0xc2 }, // super battery + { SM_COMFORT_NAME, 0xc1 }, // balanced + { SM_TURBO_NAME, 0xc4 }, // extreme + MSI_EC_MODE_NULL + }, + }, + .super_battery = { + .address = MSI_EC_ADDR_UNSUPP, + .mask = 0x0f, // 00, 0f + }, + .fan_mode = { + .address = 0xd4, + .modes = { + { FM_AUTO_NAME, 0x0d }, + { FM_SILENT_NAME, 0x1d }, + { FM_ADVANCED_NAME, 0x8d }, + MSI_EC_MODE_NULL + }, + }, + .cpu = { + .rt_temp_address = 0x68, + .rt_fan_speed_address = 0x71, // 0x0-0x96 + .rt_fan_speed_base_min = 0x00, + .rt_fan_speed_base_max = 0x96, + .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, + .bs_fan_speed_base_min = 0x00, + .bs_fan_speed_base_max = 0x0f, + }, + .gpu = { + .rt_temp_address = 0x80, + .rt_fan_speed_address = 0x89, + }, + .leds = { + .micmute_led_address = 0x2c, + .mute_led_address = 0x2d, + .bit = 1, + }, + .kbd_bl = { + .bl_mode_address = 0x2c, // KB auto turn off + .bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec + .max_mode = 1, + .bl_state_address = 0xd3, + .state_base_value = 0x80, + .max_state = 3, + }, +}; + static struct msi_ec_conf *CONFIGS[] __initdata = { &CONF0, &CONF1, @@ -677,6 +1138,12 @@ static struct msi_ec_conf *CONFIGS[] __initdata = { &CONF5, &CONF6, &CONF7, + &CONF8, + &CONF9, + &CONF10, + &CONF11, + &CONF12, + &CONF13, NULL }; From 096b256c9a786b42199fcb63ef5d9f65c312a3f6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 12 Sep 2023 10:55:30 -0700 Subject: [PATCH 213/396] clk: Drive clk_leaf_mux_set_rate_parent test from clk_ops Running this kunit test with lockdep enabled leads to warning splats about calling clk provider APIs without the clk_prepare lock held. I proposed adding a wrapper around these APIs to grab the prepare lock so we can call them from anywhere, and Maxime implemented that approach[1], but it didn't look great. That's because we had to make more kunit testing APIs just to call code from a place that isn't a clk provider when the prepare lock isn't held. Instead of doing that, let's implement a determine_rate clk_op for a new leaf clk that is the child of the existing leaf clk. We can call __clk_determine_rate() on the existing leaf clk from there, and stash away the clk_rate_request struct to check once the clk_op returns. Drive that clk_op by calling clk_round_rate() to keep things similar to how it was before (i.e. nothing actually changes rate, just the new rate is determined). This silences the warning by driving the test from a clk_op where we know the prepare lock is held. While looking at this in more detail, it was determined that the code we intended to test in commit 262ca38f4b6e ("clk: Stop forwarding clk_rate_requests to the parent") wasn't actually tested. The call to __clk_determine_rate() wasn't actually getting to the newly introduced code under the CLK_SET_RATE_PARENT if condition in clk_core_round_rate_nolock() because the parent clk (the mux) could round rates. We introduce a new leaf and make sure the parent of that clk has no clk_ops so that we can be certain that the CLK_SET_RATE_PARENT condition in clk_core_round_rate_nolock() is evaluated. Reported-by: Guenter Roeck Closes: https://lore.kernel.org/linux-clk/2b594e50-2bbf-4a2d-88e6-49fc39f3957a@roeck-us.net/ Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202301310919.b9d56ee3-yujie.liu@intel.com Cc: Maxime Ripard Link: https://lore.kernel.org/r/20230721-clk-fix-kunit-lockdep-v1-0-32cdba4c8fc1@kernel.org [1] Fixes: 262ca38f4b6e ("clk: Stop forwarding clk_rate_requests to the parent") Link: https://lore.kernel.org/r/20230912175534.2427862-2-sboyd@kernel.org Acked-by: Maxime Ripard Signed-off-by: Stephen Boyd --- drivers/clk/clk_test.c | 65 +++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index a154ec9d0111..43e85fc0b025 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -10,6 +10,8 @@ #include +static const struct clk_ops empty_clk_ops = { }; + #define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000) #define DUMMY_CLOCK_RATE_1 (142 * 1000 * 1000) #define DUMMY_CLOCK_RATE_2 (242 * 1000 * 1000) @@ -2155,6 +2157,30 @@ static struct kunit_suite clk_range_minimize_test_suite = { struct clk_leaf_mux_ctx { struct clk_multiple_parent_ctx mux_ctx; struct clk_hw hw; + struct clk_hw parent; + struct clk_rate_request *req; +}; + +static int clk_leaf_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + struct clk_leaf_mux_ctx *ctx = container_of(hw, struct clk_leaf_mux_ctx, hw); + int ret; + struct clk_rate_request *parent_req = ctx->req; + + clk_hw_forward_rate_request(hw, req, req->best_parent_hw, parent_req, req->rate); + ret = __clk_determine_rate(req->best_parent_hw, parent_req); + if (ret) + return ret; + + req->rate = parent_req->rate; + + return 0; +} + +static const struct clk_ops clk_leaf_mux_set_rate_parent_ops = { + .determine_rate = clk_leaf_mux_determine_rate, + .set_parent = clk_dummy_single_set_parent, + .get_parent = clk_dummy_single_get_parent, }; static int @@ -2193,8 +2219,14 @@ clk_leaf_mux_set_rate_parent_test_init(struct kunit *test) if (ret) return ret; - ctx->hw.init = CLK_HW_INIT_HW("test-clock", &ctx->mux_ctx.hw, - &clk_dummy_single_parent_ops, + ctx->parent.init = CLK_HW_INIT_HW("test-parent", &ctx->mux_ctx.hw, + &empty_clk_ops, CLK_SET_RATE_PARENT); + ret = clk_hw_register(NULL, &ctx->parent); + if (ret) + return ret; + + ctx->hw.init = CLK_HW_INIT_HW("test-clock", &ctx->parent, + &clk_leaf_mux_set_rate_parent_ops, CLK_SET_RATE_PARENT); ret = clk_hw_register(NULL, &ctx->hw); if (ret) @@ -2208,32 +2240,31 @@ static void clk_leaf_mux_set_rate_parent_test_exit(struct kunit *test) struct clk_leaf_mux_ctx *ctx = test->priv; clk_hw_unregister(&ctx->hw); + clk_hw_unregister(&ctx->parent); clk_hw_unregister(&ctx->mux_ctx.hw); clk_hw_unregister(&ctx->mux_ctx.parents_ctx[0].hw); clk_hw_unregister(&ctx->mux_ctx.parents_ctx[1].hw); } /* - * Test that, for a clock that will forward any rate request to its - * parent, the rate request structure returned by __clk_determine_rate - * is sane and will be what we expect. + * Test that, for a clock that will forward any rate request to its parent, the + * rate request structure returned by __clk_determine_rate() is sane and + * doesn't have the clk_rate_request's best_parent_hw pointer point to the + * clk_hw passed into __clk_determine_rate(). See commit 262ca38f4b6e ("clk: + * Stop forwarding clk_rate_requests to the parent") for more background. */ -static void clk_leaf_mux_set_rate_parent_determine_rate(struct kunit *test) +static void clk_leaf_mux_set_rate_parent__clk_determine_rate_proper_parent(struct kunit *test) { struct clk_leaf_mux_ctx *ctx = test->priv; struct clk_hw *hw = &ctx->hw; struct clk *clk = clk_hw_get_clk(hw, NULL); struct clk_rate_request req; unsigned long rate; - int ret; + ctx->req = &req; rate = clk_get_rate(clk); KUNIT_ASSERT_EQ(test, rate, DUMMY_CLOCK_RATE_1); - - clk_hw_init_rate_request(hw, &req, DUMMY_CLOCK_RATE_2); - - ret = __clk_determine_rate(hw, &req); - KUNIT_ASSERT_EQ(test, ret, 0); + KUNIT_ASSERT_EQ(test, DUMMY_CLOCK_RATE_2, clk_round_rate(clk, DUMMY_CLOCK_RATE_2)); KUNIT_EXPECT_EQ(test, req.rate, DUMMY_CLOCK_RATE_2); KUNIT_EXPECT_EQ(test, req.best_parent_rate, DUMMY_CLOCK_RATE_2); @@ -2243,15 +2274,15 @@ static void clk_leaf_mux_set_rate_parent_determine_rate(struct kunit *test) } static struct kunit_case clk_leaf_mux_set_rate_parent_test_cases[] = { - KUNIT_CASE(clk_leaf_mux_set_rate_parent_determine_rate), + KUNIT_CASE(clk_leaf_mux_set_rate_parent__clk_determine_rate_proper_parent), {} }; /* - * Test suite for a clock whose parent is a mux with multiple parents. - * The leaf clock has CLK_SET_RATE_PARENT, and will forward rate - * requests to the mux, which will then select which parent is the best - * fit for a given rate. + * Test suite for a clock whose parent is a pass-through clk whose parent is a + * mux with multiple parents. The leaf and pass-through clocks have the + * CLK_SET_RATE_PARENT flag, and will forward rate requests to the mux, which + * will then select which parent is the best fit for a given rate. * * These tests exercise the behaviour of muxes, and the proper selection * of parents. From 831187c6946f29ba8309d386d5ca466eec8b9f79 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 12 Sep 2023 10:55:31 -0700 Subject: [PATCH 214/396] clk: Parameterize clk_leaf_mux_set_rate_parent Transform the existing clk_leaf_mux_set_rate_parent test into a parameterized test that calls the various determine rate APIs that exist for clk providers. This ensures that whatever determine rate API is used by a clk provider will return the correct parent in the best_parent_hw pointer of the clk_rate_request because clk_rate_requests are forwarded properly. Cc: Guenter Roeck Cc: Maxime Ripard Link: https://lore.kernel.org/r/20230912175534.2427862-3-sboyd@kernel.org Acked-by: Maxime Ripard Signed-off-by: Stephen Boyd --- drivers/clk/clk_test.c | 81 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index 43e85fc0b025..39e2b5ff4f51 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -2159,6 +2159,7 @@ struct clk_leaf_mux_ctx { struct clk_hw hw; struct clk_hw parent; struct clk_rate_request *req; + int (*determine_rate_func)(struct clk_hw *hw, struct clk_rate_request *req); }; static int clk_leaf_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) @@ -2168,7 +2169,7 @@ static int clk_leaf_mux_determine_rate(struct clk_hw *hw, struct clk_rate_reques struct clk_rate_request *parent_req = ctx->req; clk_hw_forward_rate_request(hw, req, req->best_parent_hw, parent_req, req->rate); - ret = __clk_determine_rate(req->best_parent_hw, parent_req); + ret = ctx->determine_rate_func(req->best_parent_hw, parent_req); if (ret) return ret; @@ -2246,20 +2247,83 @@ static void clk_leaf_mux_set_rate_parent_test_exit(struct kunit *test) clk_hw_unregister(&ctx->mux_ctx.parents_ctx[1].hw); } +struct clk_leaf_mux_set_rate_parent_determine_rate_test_case { + const char *desc; + int (*determine_rate_func)(struct clk_hw *hw, struct clk_rate_request *req); +}; + +static void +clk_leaf_mux_set_rate_parent_determine_rate_test_case_to_desc( + const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case *t, char *desc) +{ + strcpy(desc, t->desc); +} + +static const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case +clk_leaf_mux_set_rate_parent_determine_rate_test_cases[] = { + { + /* + * Test that __clk_determine_rate() on the parent that can't + * change rate doesn't return a clk_rate_request structure with + * the best_parent_hw pointer pointing to the parent. + */ + .desc = "clk_leaf_mux_set_rate_parent__clk_determine_rate_proper_parent", + .determine_rate_func = __clk_determine_rate, + }, + { + /* + * Test that __clk_mux_determine_rate() on the parent that + * can't change rate doesn't return a clk_rate_request + * structure with the best_parent_hw pointer pointing to + * the parent. + */ + .desc = "clk_leaf_mux_set_rate_parent__clk_mux_determine_rate_proper_parent", + .determine_rate_func = __clk_mux_determine_rate, + }, + { + /* + * Test that __clk_mux_determine_rate_closest() on the parent + * that can't change rate doesn't return a clk_rate_request + * structure with the best_parent_hw pointer pointing to + * the parent. + */ + .desc = "clk_leaf_mux_set_rate_parent__clk_mux_determine_rate_closest_proper_parent", + .determine_rate_func = __clk_mux_determine_rate_closest, + }, + { + /* + * Test that clk_hw_determine_rate_no_reparent() on the parent + * that can't change rate doesn't return a clk_rate_request + * structure with the best_parent_hw pointer pointing to + * the parent. + */ + .desc = "clk_leaf_mux_set_rate_parent_clk_hw_determine_rate_no_reparent_proper_parent", + .determine_rate_func = clk_hw_determine_rate_no_reparent, + }, +}; + +KUNIT_ARRAY_PARAM(clk_leaf_mux_set_rate_parent_determine_rate_test, + clk_leaf_mux_set_rate_parent_determine_rate_test_cases, + clk_leaf_mux_set_rate_parent_determine_rate_test_case_to_desc) + /* - * Test that, for a clock that will forward any rate request to its parent, the - * rate request structure returned by __clk_determine_rate() is sane and - * doesn't have the clk_rate_request's best_parent_hw pointer point to the - * clk_hw passed into __clk_determine_rate(). See commit 262ca38f4b6e ("clk: - * Stop forwarding clk_rate_requests to the parent") for more background. + * Test that when a clk that can't change rate itself calls a function like + * __clk_determine_rate() on its parent it doesn't get back a clk_rate_request + * structure that has the best_parent_hw pointer point to the clk_hw passed + * into the determine rate function. See commit 262ca38f4b6e ("clk: Stop + * forwarding clk_rate_requests to the parent") for more background. */ -static void clk_leaf_mux_set_rate_parent__clk_determine_rate_proper_parent(struct kunit *test) +static void clk_leaf_mux_set_rate_parent_determine_rate_test(struct kunit *test) { struct clk_leaf_mux_ctx *ctx = test->priv; struct clk_hw *hw = &ctx->hw; struct clk *clk = clk_hw_get_clk(hw, NULL); struct clk_rate_request req; unsigned long rate; + const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case *test_param; + + test_param = test->param_value; + ctx->determine_rate_func = test_param->determine_rate_func; ctx->req = &req; rate = clk_get_rate(clk); @@ -2274,7 +2338,8 @@ static void clk_leaf_mux_set_rate_parent__clk_determine_rate_proper_parent(struc } static struct kunit_case clk_leaf_mux_set_rate_parent_test_cases[] = { - KUNIT_CASE(clk_leaf_mux_set_rate_parent__clk_determine_rate_proper_parent), + KUNIT_CASE_PARAM(clk_leaf_mux_set_rate_parent_determine_rate_test, + clk_leaf_mux_set_rate_parent_determine_rate_test_gen_params), {} }; From 6fc469ab7fe50e03abef0550482613d736bd1e9b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 14:03:43 +0200 Subject: [PATCH 215/396] clk: cdce925: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-rbtree-cdce925-v1-1-a36b459002f7@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-cdce925.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index cdee4958f26d..5ffaf1255ff7 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -647,7 +647,7 @@ static int cdce925_probe(struct i2c_client *client) .name = "configuration0", .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; dev_dbg(&client->dev, "%s\n", __func__); From 29171344a1cdbf2b897cbbef78649fd0e90f6d67 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 14:21:59 +0200 Subject: [PATCH 216/396] clk: si514: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-si-v1-1-e26cfcaf27bd@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-si514.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index e8c18afac184..6ee148e5469d 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -321,7 +321,7 @@ static bool si514_regmap_is_writeable(struct device *dev, unsigned int reg) static const struct regmap_config si514_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = SI514_REG_CONTROL, .writeable_reg = si514_regmap_is_writeable, .volatile_reg = si514_regmap_is_volatile, From e2ec8f6631739b9319239f5be6354758ad04fb09 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 14:22:00 +0200 Subject: [PATCH 217/396] clk: si5341: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-si-v1-2-e26cfcaf27bd@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-si5341.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c index 9599857842c7..845b451511d2 100644 --- a/drivers/clk/clk-si5341.c +++ b/drivers/clk/clk-si5341.c @@ -1260,7 +1260,7 @@ static int si5341_wait_device_ready(struct i2c_client *client) static const struct regmap_config si5341_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .ranges = si5341_regmap_ranges, .num_ranges = ARRAY_SIZE(si5341_regmap_ranges), .max_register = SI5341_REGISTER_MAX, From 41d2288629b9a627c4b55f05c6c6998b1e62726d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 14:22:01 +0200 Subject: [PATCH 218/396] clk: si5351: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-si-v1-3-e26cfcaf27bd@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-si5351.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 00fb9b09e030..cbf7cde01157 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -206,7 +206,7 @@ static bool si5351_regmap_is_writeable(struct device *dev, unsigned int reg) static const struct regmap_config si5351_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 187, .writeable_reg = si5351_regmap_is_writeable, .volatile_reg = si5351_regmap_is_volatile, From 8df090919db2d566233757879adf4ee09de7e818 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 14:22:02 +0200 Subject: [PATCH 219/396] clk: si544: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-si-v1-4-e26cfcaf27bd@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-si544.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c index 22925968aa35..c4288cf83f9f 100644 --- a/drivers/clk/clk-si544.c +++ b/drivers/clk/clk-si544.c @@ -446,7 +446,7 @@ static bool si544_regmap_is_volatile(struct device *dev, unsigned int reg) static const struct regmap_config si544_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = SI544_REG_PAGE_SELECT, .volatile_reg = si544_regmap_is_volatile, }; From ebb7a1919f44303abe7623ce2ead4fb948d48fd2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 14:22:03 +0200 Subject: [PATCH 220/396] clk: si570: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-si-v1-5-e26cfcaf27bd@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-si570.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index de0212fb5f87..262f582c9213 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -392,7 +392,7 @@ static bool si570_regmap_is_writeable(struct device *dev, unsigned int reg) static const struct regmap_config si570_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 137, .writeable_reg = si570_regmap_is_writeable, .volatile_reg = si570_regmap_is_volatile, From df43983922c2307ff0b796913e0ca614f8f51705 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 16:26:05 +0200 Subject: [PATCH 221/396] clk: versaclock3: Remove redundant _is_writeable() The versaclock3 driver provides an _is_writeable() function which returns true for all registers. This is the default assumption for regmaps so we can remove the function for a very minor improvement in performance and code size. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-versaclk-v1-1-24dd5b3d8689@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-versaclock3.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c index 7ab2447bd203..a5ab48ff242c 100644 --- a/drivers/clk/clk-versaclock3.c +++ b/drivers/clk/clk-versaclock3.c @@ -586,17 +586,11 @@ static const struct clk_ops vc3_clk_mux_ops = { .get_parent = vc3_clk_mux_get_parent, }; -static bool vc3_regmap_is_writeable(struct device *dev, unsigned int reg) -{ - return true; -} - static const struct regmap_config vc3_regmap_config = { .reg_bits = 8, .val_bits = 8, .cache_type = REGCACHE_RBTREE, .max_register = 0x24, - .writeable_reg = vc3_regmap_is_writeable, }; static struct vc3_hw_data clk_div[5]; From 4b58a0144b1b041818f89851eea87606a3cd80a1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 16:26:06 +0200 Subject: [PATCH 222/396] clk: versaclock3: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-versaclk-v1-2-24dd5b3d8689@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-versaclock3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c index a5ab48ff242c..b4a89c083c11 100644 --- a/drivers/clk/clk-versaclock3.c +++ b/drivers/clk/clk-versaclock3.c @@ -589,7 +589,7 @@ static const struct clk_ops vc3_clk_mux_ops = { static const struct regmap_config vc3_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 0x24, }; From 2902ba682ae1b59687b5ae8794202a4649e62954 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 16:26:07 +0200 Subject: [PATCH 223/396] clk: versaclock5: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-versaclk-v1-3-24dd5b3d8689@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-versaclock5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index 17cbb30d20ad..6d31cd54d7cf 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -217,7 +217,7 @@ static bool vc5_regmap_is_writeable(struct device *dev, unsigned int reg) static const struct regmap_config vc5_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 0x76, .writeable_reg = vc5_regmap_is_writeable, }; From 9e952929dfe22aa1566d930f363213e1ccfe004d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 16:26:08 +0200 Subject: [PATCH 224/396] clk: versaclock7: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230929-clk-maple-versaclk-v1-4-24dd5b3d8689@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/clk-versaclock7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-versaclock7.c b/drivers/clk/clk-versaclock7.c index 9ab35c1af0ff..f323263e32c3 100644 --- a/drivers/clk/clk-versaclock7.c +++ b/drivers/clk/clk-versaclock7.c @@ -1275,7 +1275,7 @@ static const struct regmap_config vc7_regmap_config = { .ranges = vc7_range_cfg, .num_ranges = ARRAY_SIZE(vc7_range_cfg), .volatile_reg = vc7_volatile_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .can_multi_write = true, .reg_format_endian = REGMAP_ENDIAN_LITTLE, .val_format_endian = REGMAP_ENDIAN_LITTLE, From 16b86e5c03c5b3ef35bf5126b35384faa97428f0 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 6 Oct 2023 13:39:57 +0300 Subject: [PATCH 225/396] clk: renesas: rzg2l: Refactor SD mux driver Refactor SD MUX driver to be able to reuse the same code on RZ/G3S. RZ/G2{L,UL} has a limitation with regards to switching the clock source for SD MUX (MUX clock source has to be switched to 266MHz before switching b/w 533MHz and 400MHz). Rework the handling of this limitation to use a clock notifier that is registered according to platform based initialization data, so the SD MUX code can be reused on RZ/G3S. As RZ/G2{L,UL} and RZ/G3S use different bits in different registers to check if the clock switching has been done, this configuration (register offset, register bits and bitfield width) is now passed through struct cpg_core_clk::sconf (status configuration) from platform specific initialization code. Along with struct cpg_core_clk::sconf the mux table indices are also passed from platform specific initialization code. Also, mux flags are now passed to DEF_SD_MUX() as they will be used later by RZ/G3S. CPG_WEN_BIT macro has been introduced to select properly the WEN bit of various registers. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231006103959.197485-3-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a07g043-cpg.c | 12 ++- drivers/clk/renesas/r9a07g044-cpg.c | 12 ++- drivers/clk/renesas/rzg2l-cpg.c | 148 ++++++++++++++++++++-------- drivers/clk/renesas/rzg2l-cpg.h | 16 ++- 4 files changed, 138 insertions(+), 50 deletions(-) diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c index e0ae25644e1a..b70bb378ab46 100644 --- a/drivers/clk/renesas/r9a07g043-cpg.c +++ b/drivers/clk/renesas/r9a07g043-cpg.c @@ -21,6 +21,10 @@ #define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) #define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) +/* Clock status configuration. */ +#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1) +#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1) + enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R9A07G043_CLK_P0_DIV2, @@ -85,6 +89,8 @@ static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" }; static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; +static const u32 mtable_sdhi[] = { 1, 2, 3 }; + static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { /* External Clock Inputs */ DEF_INPUT("extal", CLK_EXTAL), @@ -130,8 +136,10 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { DEF_MUX("HP", R9A07G043_CLK_HP, SEL_PLL6_2, sel_pll6_2), DEF_FIXED("SPI0", R9A07G043_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), - DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, sel_shdi), - DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, sel_shdi), + DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), }; diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c index d4dcf5d896d4..1047278c9079 100644 --- a/drivers/clk/renesas/r9a07g044-cpg.c +++ b/drivers/clk/renesas/r9a07g044-cpg.c @@ -22,6 +22,10 @@ #define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2) #define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2) +/* Clock status configuration. */ +#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1) +#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1) + enum clk_ids { /* Core Clock Outputs exported to DT */ LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A, @@ -105,6 +109,8 @@ static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" }; static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" }; static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" }; +static const u32 mtable_sdhi[] = { 1, 2, 3 }; + static const struct { struct cpg_core_clk common[56]; #ifdef CONFIG_CLK_R9A07G054 @@ -170,8 +176,10 @@ static const struct { DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, sel_pll6_2), DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2), DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4), - DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, sel_shdi), - DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, sel_shdi), + DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), + DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi, + mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8), diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 6ca81d22c669..8f927568a3c8 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -61,31 +61,37 @@ #define GET_REG_SAMPLL_CLK1(val) ((val >> 22) & 0xfff) #define GET_REG_SAMPLL_CLK2(val) ((val >> 12) & 0xfff) +#define CPG_WEN_BIT BIT(16) + #define MAX_VCLK_FREQ (148500000) /** * struct clk_hw_data - clock hardware data * @hw: clock hw * @conf: clock configuration (register offset, shift, width) + * @sconf: clock status configuration (register offset, shift, width) * @priv: CPG private data structure */ struct clk_hw_data { struct clk_hw hw; u32 conf; + u32 sconf; struct rzg2l_cpg_priv *priv; }; #define to_clk_hw_data(_hw) container_of(_hw, struct clk_hw_data, hw) /** - * struct sd_hw_data - SD clock hardware data + * struct sd_mux_hw_data - SD MUX clock hardware data * @hw_data: clock hw data + * @mtable: clock mux table */ -struct sd_hw_data { +struct sd_mux_hw_data { struct clk_hw_data hw_data; + const u32 *mtable; }; -#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw_data) +#define to_sd_mux_hw_data(_hw) container_of(_hw, struct sd_mux_hw_data, hw_data) struct rzg2l_pll5_param { u32 pl5_fracin; @@ -142,6 +148,76 @@ static void rzg2l_cpg_del_clk_provider(void *data) of_clk_del_provider(data); } +/* Must be called in atomic context. */ +static int rzg2l_cpg_wait_clk_update_done(void __iomem *base, u32 conf) +{ + u32 bitmask = GENMASK(GET_WIDTH(conf) - 1, 0) << GET_SHIFT(conf); + u32 off = GET_REG_OFFSET(conf); + u32 val; + + return readl_poll_timeout_atomic(base + off, val, !(val & bitmask), 10, 200); +} + +int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct clk_notifier_data *cnd = data; + struct clk_hw *hw = __clk_get_hw(cnd->clk); + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct rzg2l_cpg_priv *priv = clk_hw_data->priv; + u32 off = GET_REG_OFFSET(clk_hw_data->conf); + u32 shift = GET_SHIFT(clk_hw_data->conf); + const u32 clk_src_266 = 3; + unsigned long flags; + int ret; + + if (event != PRE_RATE_CHANGE || (cnd->new_rate / MEGA == 266)) + return NOTIFY_DONE; + + spin_lock_irqsave(&priv->rmw_lock, flags); + + /* + * As per the HW manual, we should not directly switch from 533 MHz to + * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) + * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, + * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 + * (400 MHz)). + * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock + * switching register is prohibited. + * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and + * the index to value mapping is done by adding 1 to the index. + */ + + writel((CPG_WEN_BIT | clk_src_266) << shift, priv->base + off); + + /* Wait for the update done. */ + ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); + + spin_unlock_irqrestore(&priv->rmw_lock, flags); + + if (ret) + dev_err(priv->dev, "failed to switch to safe clk source\n"); + + return notifier_from_errno(ret); +} + +static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk *core, + struct rzg2l_cpg_priv *priv) +{ + struct notifier_block *nb; + + if (!core->notifier) + return 0; + + nb = devm_kzalloc(priv->dev, sizeof(*nb), GFP_KERNEL); + if (!nb) + return -ENOMEM; + + nb->notifier_call = core->notifier; + + return clk_notifier_register(hw->clk, nb); +} + static struct clk * __init rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks, @@ -205,48 +281,27 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) { struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data); struct rzg2l_cpg_priv *priv = clk_hw_data->priv; u32 off = GET_REG_OFFSET(clk_hw_data->conf); u32 shift = GET_SHIFT(clk_hw_data->conf); - const u32 clk_src_266 = 2; - u32 msk, val, bitmask; unsigned long flags; + u32 val; int ret; - /* - * As per the HW manual, we should not directly switch from 533 MHz to - * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) - * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, - * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 - * (400 MHz)). - * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock - * switching register is prohibited. - * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and - * the index to value mapping is done by adding 1 to the index. - */ - bitmask = (GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0) << shift) << 16; - msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; + val = clk_mux_index_to_val(sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, index); + spin_lock_irqsave(&priv->rmw_lock, flags); - if (index != clk_src_266) { - writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off); - ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, - !(val & msk), 10, - CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); - if (ret) - goto unlock; - } + writel((CPG_WEN_BIT | val) << shift, priv->base + off); - writel(bitmask | ((index + 1) << shift), priv->base + off); + /* Wait for the update done. */ + ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); - ret = readl_poll_timeout_atomic(priv->base + CPG_CLKSTATUS, val, - !(val & msk), 10, - CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); -unlock: spin_unlock_irqrestore(&priv->rmw_lock, flags); if (ret) - dev_err(priv->dev, "failed to switch clk source\n"); + dev_err(priv->dev, "Failed to switch parent\n"); return ret; } @@ -254,13 +309,15 @@ unlock: static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) { struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data); struct rzg2l_cpg_priv *priv = clk_hw_data->priv; - u32 val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); + u32 val; + val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); val >>= GET_SHIFT(clk_hw_data->conf); val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0); - return val ? val - 1 : 0; + return clk_mux_val_to_index(hw, sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, val); } static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { @@ -274,31 +331,40 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, void __iomem *base, struct rzg2l_cpg_priv *priv) { - struct sd_hw_data *sd_hw_data; + struct sd_mux_hw_data *sd_mux_hw_data; struct clk_init_data init; struct clk_hw *clk_hw; int ret; - sd_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_hw_data), GFP_KERNEL); - if (!sd_hw_data) + sd_mux_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_mux_hw_data), GFP_KERNEL); + if (!sd_mux_hw_data) return ERR_PTR(-ENOMEM); - sd_hw_data->hw_data.priv = priv; - sd_hw_data->hw_data.conf = core->conf; + sd_mux_hw_data->hw_data.priv = priv; + sd_mux_hw_data->hw_data.conf = core->conf; + sd_mux_hw_data->hw_data.sconf = core->sconf; + sd_mux_hw_data->mtable = core->mtable; init.name = core->name; init.ops = &rzg2l_cpg_sd_clk_mux_ops; - init.flags = 0; + init.flags = core->flag; init.num_parents = core->num_parents; init.parent_names = core->parent_names; - clk_hw = &sd_hw_data->hw_data.hw; + clk_hw = &sd_mux_hw_data->hw_data.hw; clk_hw->init = &init; ret = devm_clk_hw_register(priv->dev, clk_hw); if (ret) return ERR_PTR(ret); + ret = rzg2l_register_notifier(clk_hw, core, priv); + if (ret) { + dev_err(priv->dev, "Failed to register notifier for %s\n", + core->name); + return ERR_PTR(ret); + } + return clk_hw->clk; } diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index f5382333d327..f1910913b29a 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -9,6 +9,8 @@ #ifndef __RENESAS_RZG2L_CPG_H__ #define __RENESAS_RZG2L_CPG_H__ +#include + #define CPG_SIPLL5_STBY (0x140) #define CPG_SIPLL5_CLK1 (0x144) #define CPG_SIPLL5_CLK3 (0x14C) @@ -42,8 +44,6 @@ #define CPG_CLKSTATUS_SELSDHI0_STS BIT(28) #define CPG_CLKSTATUS_SELSDHI1_STS BIT(29) -#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 200 - /* n = 0/1/2 for PLL1/4/6 */ #define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n)) #define CPG_SAMPLL_CLK2(n) (0x08 + (16 * n)) @@ -86,8 +86,11 @@ struct cpg_core_clk { unsigned int mult; unsigned int type; unsigned int conf; + unsigned int sconf; const struct clk_div_table *dtable; + const u32 *mtable; const char * const *parent_names; + notifier_fn_t notifier; u32 flag; u32 mux_flags; int num_parents; @@ -150,10 +153,11 @@ enum clk_types { .parent_names = _parent_names, \ .num_parents = ARRAY_SIZE(_parent_names), \ .mux_flags = CLK_MUX_READ_ONLY) -#define DEF_SD_MUX(_name, _id, _conf, _parent_names) \ - DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, \ +#define DEF_SD_MUX(_name, _id, _conf, _sconf, _parent_names, _mtable, _clk_flags, _notifier) \ + DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, .sconf = _sconf, \ .parent_names = _parent_names, \ - .num_parents = ARRAY_SIZE(_parent_names)) + .num_parents = ARRAY_SIZE(_parent_names), \ + .mtable = _mtable, .flag = _clk_flags, .notifier = _notifier) #define DEF_PLL5_FOUTPOSTDIV(_name, _id, _parent) \ DEF_TYPE(_name, _id, CLK_TYPE_SIPLL5, .parent = _parent) #define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names) \ @@ -272,4 +276,6 @@ extern const struct rzg2l_cpg_info r9a07g044_cpg_info; extern const struct rzg2l_cpg_info r9a07g054_cpg_info; extern const struct rzg2l_cpg_info r9a09g011_cpg_info; +int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, void *data); + #endif From 62b1feac485866494f111e3a6aa4a9ae03a7a2b9 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 6 Oct 2023 13:39:58 +0300 Subject: [PATCH 226/396] clk: renesas: rzg2l: Add divider clock for RZ/G3S Add a divider clock driver for RZ/G3S. This will be used on RZ/G3S for the SDHI, SPI, OCTA, I, I2, I3, P0, P1, P2, and P3 core clocks. The divider has some limitation for SDHI, OCTA and SPI clocks: - SDHI div cannot be 1 if parent rate is 800MHz, - OCTA, SPI div cannot be 1 if parent rate is 400MHz. To handle these limitations, a notifier is registered from platform specific clock driver, which makes sure proper actions are taken before the clock rate is changed, when needed. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231006103959.197485-4-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 186 ++++++++++++++++++++++++++++++++ drivers/clk/renesas/rzg2l-cpg.h | 11 ++ 2 files changed, 197 insertions(+) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 8f927568a3c8..49dc6c5c0b0c 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -93,6 +93,24 @@ struct sd_mux_hw_data { #define to_sd_mux_hw_data(_hw) container_of(_hw, struct sd_mux_hw_data, hw_data) +/** + * struct div_hw_data - divider clock hardware data + * @hw_data: clock hw data + * @dtable: pointer to divider table + * @invalid_rate: invalid rate for divider + * @max_rate: maximum rate for divider + * @width: divider width + */ +struct div_hw_data { + struct clk_hw_data hw_data; + const struct clk_div_table *dtable; + unsigned long invalid_rate; + unsigned long max_rate; + u32 width; +}; + +#define to_div_hw_data(_hw) container_of(_hw, struct div_hw_data, hw_data) + struct rzg2l_pll5_param { u32 pl5_fracin; u8 pl5_refdiv; @@ -201,6 +219,53 @@ int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event return notifier_from_errno(ret); } +int rzg3s_cpg_div_clk_notifier(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct clk_notifier_data *cnd = data; + struct clk_hw *hw = __clk_get_hw(cnd->clk); + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data); + struct rzg2l_cpg_priv *priv = clk_hw_data->priv; + u32 off = GET_REG_OFFSET(clk_hw_data->conf); + u32 shift = GET_SHIFT(clk_hw_data->conf); + unsigned long flags; + int ret = 0; + u32 val; + + if (event != PRE_RATE_CHANGE || !div_hw_data->invalid_rate || + div_hw_data->invalid_rate % cnd->new_rate) + return NOTIFY_DONE; + + spin_lock_irqsave(&priv->rmw_lock, flags); + + val = readl(priv->base + off); + val >>= shift; + val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0); + + /* + * There are different constraints for the user of this notifiers as follows: + * 1/ SD div cannot be 1 (val == 0) if parent rate is 800MHz + * 2/ OCTA / SPI div cannot be 1 (val == 0) if parent rate is 400MHz + * As SD can have only one parent having 800MHz and OCTA div can have + * only one parent having 400MHz we took into account the parent rate + * at the beginning of function (by checking invalid_rate % new_rate). + * Now it is time to check the hardware divider and update it accordingly. + */ + if (!val) { + writel((CPG_WEN_BIT | 1) << shift, priv->base + off); + /* Wait for the update done. */ + ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); + } + + spin_unlock_irqrestore(&priv->rmw_lock, flags); + + if (ret) + dev_err(priv->dev, "Failed to downgrade the div\n"); + + return notifier_from_errno(ret); +} + static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { @@ -218,6 +283,124 @@ static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk return clk_notifier_register(hw->clk, nb); } +static unsigned long rzg3s_div_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data); + struct rzg2l_cpg_priv *priv = clk_hw_data->priv; + u32 val; + + val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf)); + val >>= GET_SHIFT(clk_hw_data->conf); + val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0); + + return divider_recalc_rate(hw, parent_rate, val, div_hw_data->dtable, + CLK_DIVIDER_ROUND_CLOSEST, div_hw_data->width); +} + +static int rzg3s_div_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data); + + if (div_hw_data->max_rate && req->rate > div_hw_data->max_rate) + req->rate = div_hw_data->max_rate; + + return divider_determine_rate(hw, req, div_hw_data->dtable, div_hw_data->width, + CLK_DIVIDER_ROUND_CLOSEST); +} + +static int rzg3s_div_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw); + struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data); + struct rzg2l_cpg_priv *priv = clk_hw_data->priv; + u32 off = GET_REG_OFFSET(clk_hw_data->conf); + u32 shift = GET_SHIFT(clk_hw_data->conf); + unsigned long flags; + u32 val; + int ret; + + val = divider_get_val(rate, parent_rate, div_hw_data->dtable, div_hw_data->width, + CLK_DIVIDER_ROUND_CLOSEST); + + spin_lock_irqsave(&priv->rmw_lock, flags); + writel((CPG_WEN_BIT | val) << shift, priv->base + off); + /* Wait for the update done. */ + ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf); + spin_unlock_irqrestore(&priv->rmw_lock, flags); + + return ret; +} + +static const struct clk_ops rzg3s_div_clk_ops = { + .recalc_rate = rzg3s_div_clk_recalc_rate, + .determine_rate = rzg3s_div_clk_determine_rate, + .set_rate = rzg3s_div_clk_set_rate, +}; + +static struct clk * __init +rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks, + void __iomem *base, struct rzg2l_cpg_priv *priv) +{ + struct div_hw_data *div_hw_data; + struct clk_init_data init = {}; + const struct clk_div_table *clkt; + struct clk_hw *clk_hw; + const struct clk *parent; + const char *parent_name; + u32 max = 0; + int ret; + + parent = clks[core->parent & 0xffff]; + if (IS_ERR(parent)) + return ERR_CAST(parent); + + parent_name = __clk_get_name(parent); + + div_hw_data = devm_kzalloc(priv->dev, sizeof(*div_hw_data), GFP_KERNEL); + if (!div_hw_data) + return ERR_PTR(-ENOMEM); + + init.name = core->name; + init.flags = core->flag; + init.ops = &rzg3s_div_clk_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + + /* Get the maximum divider to retrieve div width. */ + for (clkt = core->dtable; clkt->div; clkt++) { + if (max < clkt->div) + max = clkt->div; + } + + div_hw_data->hw_data.priv = priv; + div_hw_data->hw_data.conf = core->conf; + div_hw_data->hw_data.sconf = core->sconf; + div_hw_data->dtable = core->dtable; + div_hw_data->invalid_rate = core->invalid_rate; + div_hw_data->max_rate = core->max_rate; + div_hw_data->width = fls(max) - 1; + + clk_hw = &div_hw_data->hw_data.hw; + clk_hw->init = &init; + + ret = devm_clk_hw_register(priv->dev, clk_hw); + if (ret) + return ERR_PTR(ret); + + ret = rzg2l_register_notifier(clk_hw, core, priv); + if (ret) { + dev_err(priv->dev, "Failed to register notifier for %s\n", + core->name); + return ERR_PTR(ret); + } + + return clk_hw->clk; +} + static struct clk * __init rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks, @@ -963,6 +1146,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, clk = rzg2l_cpg_div_clk_register(core, priv->clks, priv->base, priv); break; + case CLK_TYPE_G3S_DIV: + clk = rzg3s_cpg_div_clk_register(core, priv->clks, priv->base, priv); + break; case CLK_TYPE_MUX: clk = rzg2l_cpg_mux_clk_register(core, priv->base, priv); break; diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index f1910913b29a..4755befaf38e 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -89,6 +89,8 @@ struct cpg_core_clk { unsigned int sconf; const struct clk_div_table *dtable; const u32 *mtable; + const unsigned long invalid_rate; + const unsigned long max_rate; const char * const *parent_names; notifier_fn_t notifier; u32 flag; @@ -105,6 +107,7 @@ enum clk_types { /* Clock with divider */ CLK_TYPE_DIV, + CLK_TYPE_G3S_DIV, /* Clock with clock source selector */ CLK_TYPE_MUX, @@ -143,6 +146,13 @@ enum clk_types { DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \ .parent = _parent, .dtable = _dtable, \ .flag = CLK_DIVIDER_READ_ONLY) +#define DEF_G3S_DIV(_name, _id, _parent, _conf, _sconf, _dtable, _invalid_rate, \ + _max_rate, _clk_flags, _notif) \ + DEF_TYPE(_name, _id, CLK_TYPE_G3S_DIV, .conf = _conf, .sconf = _sconf, \ + .parent = _parent, .dtable = _dtable, \ + .invalid_rate = _invalid_rate, \ + .max_rate = _max_rate, .flag = (_clk_flags), \ + .notifier = _notif) #define DEF_MUX(_name, _id, _conf, _parent_names) \ DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = _conf, \ .parent_names = _parent_names, \ @@ -277,5 +287,6 @@ extern const struct rzg2l_cpg_info r9a07g054_cpg_info; extern const struct rzg2l_cpg_info r9a09g011_cpg_info; int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, void *data); +int rzg3s_cpg_div_clk_notifier(struct notifier_block *nb, unsigned long event, void *data); #endif From de60a3ebe410670ffdbbc95faa25a820da44ab11 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Fri, 6 Oct 2023 13:39:59 +0300 Subject: [PATCH 227/396] clk: renesas: Add minimal boot support for RZ/G3S SoC Add minimal clock and reset support for the RZ/G3S SoC to be able to boot Linux from SD Card/eMMC. This includes necessary core clocks for booting and GIC, SCIF, GPIO, and SD0 module clocks and resets. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231006103959.197485-5-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/Kconfig | 7 +- drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/r9a08g045-cpg.c | 214 ++++++++++++++++++++++++++++ drivers/clk/renesas/rzg2l-cpg.c | 6 + drivers/clk/renesas/rzg2l-cpg.h | 1 + 5 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/renesas/r9a08g045-cpg.c diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 37632a0659d8..69396e197959 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -37,6 +37,7 @@ config CLK_RENESAS select CLK_R9A07G043 if ARCH_R9A07G043 select CLK_R9A07G044 if ARCH_R9A07G044 select CLK_R9A07G054 if ARCH_R9A07G054 + select CLK_R9A08G045 if ARCH_R9A08G045 select CLK_R9A09G011 if ARCH_R9A09G011 select CLK_SH73A0 if ARCH_SH73A0 @@ -179,6 +180,10 @@ config CLK_R9A07G054 bool "RZ/V2L clock support" if COMPILE_TEST select CLK_RZG2L +config CLK_R9A08G045 + bool "RZ/G3S clock support" if COMPILE_TEST + select CLK_RZG2L + config CLK_R9A09G011 bool "RZ/V2M clock support" if COMPILE_TEST select CLK_RZG2L @@ -215,7 +220,7 @@ config CLK_RCAR_USB2_CLOCK_SEL This is a driver for R-Car USB2 clock selector config CLK_RZG2L - bool "Renesas RZ/{G2L,G2UL,V2L} family clock support" if COMPILE_TEST + bool "Renesas RZ/{G2L,G2UL,G3S,V2L} family clock support" if COMPILE_TEST select RESET_CONTROLLER # Generic diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index de907623fe3f..879a07d445f9 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o obj-$(CONFIG_CLK_R9A07G043) += r9a07g043-cpg.o obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o obj-$(CONFIG_CLK_R9A07G054) += r9a07g044-cpg.o +obj-$(CONFIG_CLK_R9A08G045) += r9a08g045-cpg.o obj-$(CONFIG_CLK_R9A09G011) += r9a09g011-cpg.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c new file mode 100644 index 000000000000..389d32b32168 --- /dev/null +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RZ/G3S CPG driver + * + * Copyright (C) 2023 Renesas Electronics Corp. + */ + +#include +#include +#include +#include + +#include + +#include "rzg2l-cpg.h" + +/* RZ/G3S Specific registers. */ +#define G3S_CPG_PL2_DDIV (0x204) +#define G3S_CPG_SDHI_DDIV (0x218) +#define G3S_CPG_PLL_DSEL (0x240) +#define G3S_CPG_SDHI_DSEL (0x244) +#define G3S_CLKDIVSTATUS (0x280) +#define G3S_CLKSELSTATUS (0x284) + +/* RZ/G3S Specific division configuration. */ +#define G3S_DIVPL2B DDIV_PACK(G3S_CPG_PL2_DDIV, 4, 3) +#define G3S_DIV_SDHI0 DDIV_PACK(G3S_CPG_SDHI_DDIV, 0, 1) + +/* RZ/G3S Clock status configuration. */ +#define G3S_DIVPL1A_STS DDIV_PACK(G3S_CLKDIVSTATUS, 0, 1) +#define G3S_DIVPL2B_STS DDIV_PACK(G3S_CLKDIVSTATUS, 5, 1) +#define G3S_DIVPL3A_STS DDIV_PACK(G3S_CLKDIVSTATUS, 8, 1) +#define G3S_DIVPL3B_STS DDIV_PACK(G3S_CLKDIVSTATUS, 9, 1) +#define G3S_DIVPL3C_STS DDIV_PACK(G3S_CLKDIVSTATUS, 10, 1) +#define G3S_DIV_SDHI0_STS DDIV_PACK(G3S_CLKDIVSTATUS, 24, 1) + +#define G3S_SEL_PLL4_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 6, 1) +#define G3S_SEL_SDHI0_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 16, 1) + +/* RZ/G3S Specific clocks select. */ +#define G3S_SEL_PLL4 SEL_PLL_PACK(G3S_CPG_PLL_DSEL, 6, 1) +#define G3S_SEL_SDHI0 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 0, 2) + +/* PLL 1/4/6 configuration registers macro. */ +#define G3S_PLL146_CONF(clk1, clk2) ((clk1) << 22 | (clk2) << 12) + +#define DEF_G3S_MUX(_name, _id, _conf, _parent_names, _mux_flags, _clk_flags) \ + DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = (_conf), \ + .parent_names = (_parent_names), \ + .num_parents = ARRAY_SIZE((_parent_names)), \ + .mux_flags = CLK_MUX_HIWORD_MASK | (_mux_flags), \ + .flag = (_clk_flags)) + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A08G045_SWD, + + /* External Input Clocks */ + CLK_EXTAL, + + /* Internal Core Clocks */ + CLK_OSC_DIV1000, + CLK_PLL1, + CLK_PLL2, + CLK_PLL2_DIV2, + CLK_PLL2_DIV2_8, + CLK_PLL2_DIV6, + CLK_PLL3, + CLK_PLL3_DIV2, + CLK_PLL3_DIV2_4, + CLK_PLL3_DIV2_8, + CLK_PLL3_DIV6, + CLK_PLL4, + CLK_PLL6, + CLK_PLL6_DIV2, + CLK_SEL_SDHI0, + CLK_SEL_PLL4, + CLK_P1_DIV2, + CLK_P3_DIV2, + CLK_SD0_DIV4, + + /* Module Clocks */ + MOD_CLK_BASE, +}; + +/* Divider tables */ +static const struct clk_div_table dtable_1_2[] = { + { 0, 1 }, + { 1, 2 }, + { 0, 0 }, +}; + +static const struct clk_div_table dtable_1_8[] = { + { 0, 1 }, + { 1, 2 }, + { 2, 4 }, + { 3, 8 }, + { 0, 0 }, +}; + +static const struct clk_div_table dtable_1_32[] = { + { 0, 1 }, + { 1, 2 }, + { 2, 4 }, + { 3, 8 }, + { 4, 32 }, + { 0, 0 }, +}; + +/* Mux clock names tables. */ +static const char * const sel_sdhi[] = { ".pll2_div2", ".pll6", ".pll2_div6" }; +static const char * const sel_pll4[] = { ".osc_div1000", ".pll4" }; + +/* Mux clock indices tables. */ +static const u32 mtable_sd[] = { 0, 2, 3 }; +static const u32 mtable_pll4[] = { 0, 1 }; + +static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + + /* Internal Core Clocks */ + DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000), + DEF_G3S_PLL(".pll1", CLK_PLL1, CLK_EXTAL, G3S_PLL146_CONF(0x4, 0x8)), + DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3), + DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3), + DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 100, 3), + DEF_FIXED(".pll6", CLK_PLL6, CLK_EXTAL, 125, 6), + DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2), + DEF_FIXED(".pll2_div2_8", CLK_PLL2_DIV2_8, CLK_PLL2_DIV2, 1, 8), + DEF_FIXED(".pll2_div6", CLK_PLL2_DIV6, CLK_PLL2, 1, 6), + DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2), + DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4), + DEF_FIXED(".pll3_div2_8", CLK_PLL3_DIV2_8, CLK_PLL3_DIV2, 1, 8), + DEF_FIXED(".pll3_div6", CLK_PLL3_DIV6, CLK_PLL3, 1, 6), + DEF_FIXED(".pll6_div2", CLK_PLL6_DIV2, CLK_PLL6, 1, 2), + DEF_SD_MUX(".sel_sd0", CLK_SEL_SDHI0, G3S_SEL_SDHI0, G3S_SEL_SDHI0_STS, sel_sdhi, + mtable_sd, 0, NULL), + DEF_SD_MUX(".sel_pll4", CLK_SEL_PLL4, G3S_SEL_PLL4, G3S_SEL_PLL4_STS, sel_pll4, + mtable_pll4, CLK_SET_PARENT_GATE, NULL), + + /* Core output clk */ + DEF_G3S_DIV("I", R9A08G045_CLK_I, CLK_PLL1, DIVPL1A, G3S_DIVPL1A_STS, dtable_1_8, + 0, 0, 0, NULL), + DEF_G3S_DIV("P0", R9A08G045_CLK_P0, CLK_PLL2_DIV2_8, G3S_DIVPL2B, G3S_DIVPL2B_STS, + dtable_1_32, 0, 0, 0, NULL), + DEF_G3S_DIV("SD0", R9A08G045_CLK_SD0, CLK_SEL_SDHI0, G3S_DIV_SDHI0, G3S_DIV_SDHI0_STS, + dtable_1_2, 800000000UL, 500000000UL, CLK_SET_RATE_PARENT, + rzg3s_cpg_div_clk_notifier), + DEF_FIXED(".sd0_div4", CLK_SD0_DIV4, R9A08G045_CLK_SD0, 1, 4), + DEF_FIXED("M0", R9A08G045_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), + DEF_G3S_DIV("P1", R9A08G045_CLK_P1, CLK_PLL3_DIV2_4, DIVPL3A, G3S_DIVPL3A_STS, + dtable_1_32, 0, 0, 0, NULL), + DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A08G045_CLK_P1, 1, 2), + DEF_G3S_DIV("P2", R9A08G045_CLK_P2, CLK_PLL3_DIV2_8, DIVPL3B, G3S_DIVPL3B_STS, + dtable_1_32, 0, 0, 0, NULL), + DEF_G3S_DIV("P3", R9A08G045_CLK_P3, CLK_PLL3_DIV2_4, DIVPL3C, G3S_DIVPL3C_STS, + dtable_1_32, 0, 0, 0, NULL), + DEF_FIXED("P3_DIV2", CLK_P3_DIV2, R9A08G045_CLK_P3, 1, 2), + DEF_FIXED("S0", R9A08G045_CLK_S0, CLK_SEL_PLL4, 1, 2), + DEF_FIXED("OSC", R9A08G045_OSCCLK, CLK_EXTAL, 1, 1), + DEF_FIXED("OSC2", R9A08G045_OSCCLK2, CLK_EXTAL, 1, 3), +}; + +static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { + DEF_MOD("gic_gicclk", R9A08G045_GIC600_GICCLK, R9A08G045_CLK_P1, 0x514, 0), + DEF_MOD("ia55_clk", R9A08G045_IA55_CLK, R9A08G045_CLK_P1, 0x518, 1), + DEF_MOD("dmac_aclk", R9A08G045_DMAC_ACLK, R9A08G045_CLK_P3, 0x52c, 0), + DEF_MOD("sdhi0_imclk", R9A08G045_SDHI0_IMCLK, CLK_SD0_DIV4, 0x554, 0), + DEF_MOD("sdhi0_imclk2", R9A08G045_SDHI0_IMCLK2, CLK_SD0_DIV4, 0x554, 1), + DEF_MOD("sdhi0_clk_hs", R9A08G045_SDHI0_CLK_HS, R9A08G045_CLK_SD0, 0x554, 2), + DEF_MOD("sdhi0_aclk", R9A08G045_SDHI0_ACLK, R9A08G045_CLK_P1, 0x554, 3), + DEF_MOD("scif0_clk_pck", R9A08G045_SCIF0_CLK_PCK, R9A08G045_CLK_P0, 0x584, 0), + DEF_MOD("gpio_hclk", R9A08G045_GPIO_HCLK, R9A08G045_OSCCLK, 0x598, 0), +}; + +static const struct rzg2l_reset r9a08g045_resets[] = { + DEF_RST(R9A08G045_GIC600_GICRESET_N, 0x814, 0), + DEF_RST(R9A08G045_GIC600_DBG_GICRESET_N, 0x814, 1), + DEF_RST(R9A08G045_SDHI0_IXRST, 0x854, 0), + DEF_RST(R9A08G045_SCIF0_RST_SYSTEM_N, 0x884, 0), + DEF_RST(R9A08G045_GPIO_RSTN, 0x898, 0), + DEF_RST(R9A08G045_GPIO_PORT_RESETN, 0x898, 1), + DEF_RST(R9A08G045_GPIO_SPARE_RESETN, 0x898, 2), +}; + +static const unsigned int r9a08g045_crit_mod_clks[] __initconst = { + MOD_CLK_BASE + R9A08G045_GIC600_GICCLK, + MOD_CLK_BASE + R9A08G045_IA55_CLK, + MOD_CLK_BASE + R9A08G045_DMAC_ACLK, +}; + +const struct rzg2l_cpg_info r9a08g045_cpg_info = { + /* Core Clocks */ + .core_clks = r9a08g045_core_clks, + .num_core_clks = ARRAY_SIZE(r9a08g045_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Critical Module Clocks */ + .crit_mod_clks = r9a08g045_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r9a08g045_crit_mod_clks), + + /* Module Clocks */ + .mod_clks = r9a08g045_mod_clks, + .num_mod_clks = ARRAY_SIZE(r9a08g045_mod_clks), + .num_hw_mod_clks = R9A08G045_VBAT_BCLK + 1, + + /* Resets */ + .resets = r9a08g045_resets, + .num_resets = R9A08G045_VBAT_BRESETN + 1, /* Last reset ID + 1 */ + + .has_clk_mon_regs = true, +}; diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 49dc6c5c0b0c..d62f1bc1f60e 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1706,6 +1706,12 @@ static const struct of_device_id rzg2l_cpg_match[] = { .data = &r9a07g054_cpg_info, }, #endif +#ifdef CONFIG_CLK_R9A08G045 + { + .compatible = "renesas,r9a08g045-cpg", + .data = &r9a08g045_cpg_info, + }, +#endif #ifdef CONFIG_CLK_R9A09G011 { .compatible = "renesas,r9a09g011-cpg", diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 4755befaf38e..6e38c8fc888c 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -284,6 +284,7 @@ struct rzg2l_cpg_info { extern const struct rzg2l_cpg_info r9a07g043_cpg_info; extern const struct rzg2l_cpg_info r9a07g044_cpg_info; extern const struct rzg2l_cpg_info r9a07g054_cpg_info; +extern const struct rzg2l_cpg_info r9a08g045_cpg_info; extern const struct rzg2l_cpg_info r9a09g011_cpg_info; int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, void *data); From 01d2adcfe0f1bc0f08d822a04b2c354c106d4d2f Mon Sep 17 00:00:00 2001 From: Suma Hegde Date: Tue, 10 Oct 2023 12:03:08 +0000 Subject: [PATCH 228/396] platform/x86/amd/hsmp: create plat specific struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having a separate platform device structure helps in future, to contain platform specific variables and other data. Also, define macros for dev nodes Signed-off-by: Suma Hegde Reviewed-by: Naveen Krishna Chatradhi Link: https://lore.kernel.org/r/20231010120310.3464066-1-suma.hegde@amd.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/hsmp.c | 61 ++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/drivers/platform/x86/amd/hsmp.c b/drivers/platform/x86/amd/hsmp.c index 31382ef52efb..99727cd705cf 100644 --- a/drivers/platform/x86/amd/hsmp.c +++ b/drivers/platform/x86/amd/hsmp.c @@ -47,9 +47,22 @@ #define HSMP_INDEX_REG 0xc4 #define HSMP_DATA_REG 0xc8 -static struct semaphore *hsmp_sem; +#define HSMP_CDEV_NAME "hsmp_cdev" +#define HSMP_DEVNODE_NAME "hsmp" -static struct miscdevice hsmp_device; +struct hsmp_socket { + struct semaphore hsmp_sem; + u16 sock_ind; +}; + +struct hsmp_plat_device { + struct miscdevice hsmp_device; + struct hsmp_socket *sock; + struct device *dev; + u16 num_sockets; +}; + +static struct hsmp_plat_device plat_dev; static int amd_hsmp_rdwr(struct pci_dev *root, u32 address, u32 *value, bool write) @@ -188,6 +201,7 @@ static int validate_message(struct hsmp_message *msg) int hsmp_send_message(struct hsmp_message *msg) { + struct hsmp_socket *sock = &plat_dev.sock[msg->sock_ind]; struct amd_northbridge *nb; int ret; @@ -208,14 +222,13 @@ int hsmp_send_message(struct hsmp_message *msg) * In SMP system timeout of 100 millisecs should * be enough for the previous thread to finish the operation */ - ret = down_timeout(&hsmp_sem[msg->sock_ind], - msecs_to_jiffies(HSMP_MSG_TIMEOUT)); + ret = down_timeout(&sock->hsmp_sem, msecs_to_jiffies(HSMP_MSG_TIMEOUT)); if (ret < 0) return ret; ret = __hsmp_send_message(nb->root, msg); - up(&hsmp_sem[msg->sock_ind]); + up(&sock->hsmp_sem); return ret; } @@ -321,28 +334,31 @@ static int hsmp_pltdrv_probe(struct platform_device *pdev) { int i; - hsmp_sem = devm_kzalloc(&pdev->dev, - (amd_nb_num() * sizeof(struct semaphore)), - GFP_KERNEL); - if (!hsmp_sem) + plat_dev.sock = devm_kzalloc(&pdev->dev, + (plat_dev.num_sockets * sizeof(struct hsmp_socket)), + GFP_KERNEL); + if (!plat_dev.sock) return -ENOMEM; + plat_dev.dev = &pdev->dev; - for (i = 0; i < amd_nb_num(); i++) - sema_init(&hsmp_sem[i], 1); + for (i = 0; i < plat_dev.num_sockets; i++) { + sema_init(&plat_dev.sock[i].hsmp_sem, 1); + plat_dev.sock[i].sock_ind = i; + } - hsmp_device.name = "hsmp_cdev"; - hsmp_device.minor = MISC_DYNAMIC_MINOR; - hsmp_device.fops = &hsmp_fops; - hsmp_device.parent = &pdev->dev; - hsmp_device.nodename = "hsmp"; - hsmp_device.mode = 0644; + plat_dev.hsmp_device.name = HSMP_CDEV_NAME; + plat_dev.hsmp_device.minor = MISC_DYNAMIC_MINOR; + plat_dev.hsmp_device.fops = &hsmp_fops; + plat_dev.hsmp_device.parent = &pdev->dev; + plat_dev.hsmp_device.nodename = HSMP_DEVNODE_NAME; + plat_dev.hsmp_device.mode = 0644; - return misc_register(&hsmp_device); + return misc_register(&plat_dev.hsmp_device); } static void hsmp_pltdrv_remove(struct platform_device *pdev) { - misc_deregister(&hsmp_device); + misc_deregister(&plat_dev.hsmp_device); } static struct platform_driver amd_hsmp_driver = { @@ -358,7 +374,6 @@ static struct platform_device *amd_hsmp_platdev; static int __init hsmp_plt_init(void) { int ret = -ENODEV; - u16 num_sockets; int i; if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD || boot_cpu_data.x86 < 0x19) { @@ -371,12 +386,12 @@ static int __init hsmp_plt_init(void) * amd_nb_num() returns number of SMN/DF interfaces present in the system * if we have N SMN/DF interfaces that ideally means N sockets */ - num_sockets = amd_nb_num(); - if (num_sockets == 0) + plat_dev.num_sockets = amd_nb_num(); + if (plat_dev.num_sockets == 0) return ret; /* Test the hsmp interface on each socket */ - for (i = 0; i < num_sockets; i++) { + for (i = 0; i < plat_dev.num_sockets; i++) { ret = hsmp_test(i, 0xDEADBEEF); if (ret) { pr_err("HSMP is not supported on Fam:%x model:%x\n", From 5150542b8ec5fb561be080ed0ef3bab8598154c3 Mon Sep 17 00:00:00 2001 From: Suma Hegde Date: Tue, 10 Oct 2023 12:03:09 +0000 Subject: [PATCH 229/396] platform/x86/amd/hsmp: add support for metrics tbl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AMD MI300 MCM provides GET_METRICS_TABLE message to retrieve all the system management information from SMU. The metrics table is made available as hexadecimal sysfs binary file under per socket sysfs directory created at /sys/devices/platform/amd_hsmp/socket%d/metrics_bin Metrics table definitions will be documented as part of Public PPR. The same is defined in the amd_hsmp.h header. Signed-off-by: Suma Hegde Reviewed-by: Naveen Krishna Chatradhi Link: https://lore.kernel.org/r/20231010120310.3464066-2-suma.hegde@amd.com [ij: lseek -> lseek(), dram -> DRAM in dev_err()] [ij: added period to terminate a documentation sentence] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- Documentation/arch/x86/amd_hsmp.rst | 18 +++ arch/x86/include/uapi/asm/amd_hsmp.h | 109 +++++++++++++++++ drivers/platform/x86/amd/hsmp.c | 174 ++++++++++++++++++++++++++- 3 files changed, 299 insertions(+), 2 deletions(-) diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst index 440e4b645a1c..c92bfd55359f 100644 --- a/Documentation/arch/x86/amd_hsmp.rst +++ b/Documentation/arch/x86/amd_hsmp.rst @@ -41,6 +41,24 @@ In-kernel integration: * Locking across callers is taken care by the driver. +HSMP sysfs interface +==================== + +1. Metrics table binary sysfs + +AMD MI300A MCM provides GET_METRICS_TABLE message to retrieve +most of the system management information from SMU in one go. + +The metrics table is made available as hexadecimal sysfs binary file +under per socket sysfs directory created at +/sys/devices/platform/amd_hsmp/socket%d/metrics_bin + +Note: lseek() is not supported as entire metrics table is read. + +Metrics table definitions will be documented as part of Public PPR. +The same is defined in the amd_hsmp.h header. + + An example ========== diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h index 769b939444ae..fce22686c834 100644 --- a/arch/x86/include/uapi/asm/amd_hsmp.h +++ b/arch/x86/include/uapi/asm/amd_hsmp.h @@ -47,6 +47,9 @@ enum hsmp_message_ids { HSMP_SET_PCI_RATE, /* 20h Control link rate on PCIe devices */ HSMP_SET_POWER_MODE, /* 21h Select power efficiency profile policy */ HSMP_SET_PSTATE_MAX_MIN, /* 22h Set the max and min DF P-State */ + HSMP_GET_METRIC_TABLE_VER, /* 23h Get metrics table version */ + HSMP_GET_METRIC_TABLE, /* 24h Get metrics table */ + HSMP_GET_METRIC_TABLE_DRAM_ADDR,/* 25h Get metrics table dram address */ HSMP_MSG_ID_MAX, }; @@ -64,6 +67,14 @@ enum hsmp_msg_type { HSMP_GET = 1, }; +enum hsmp_proto_versions { + HSMP_PROTO_VER2 = 2, + HSMP_PROTO_VER3, + HSMP_PROTO_VER4, + HSMP_PROTO_VER5, + HSMP_PROTO_VER6 +}; + struct hsmp_msg_desc { int num_args; int response_sz; @@ -295,6 +306,104 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] = { * input: args[0] = min df pstate[15:8] + max df pstate[7:0] */ {1, 0, HSMP_SET}, + + /* + * HSMP_GET_METRIC_TABLE_VER, num_args = 0, response_sz = 1 + * output: args[0] = metrics table version + */ + {0, 1, HSMP_GET}, + + /* + * HSMP_GET_METRIC_TABLE, num_args = 0, response_sz = 0 + */ + {0, 0, HSMP_GET}, + + /* + * HSMP_GET_METRIC_TABLE_DRAM_ADDR, num_args = 0, response_sz = 2 + * output: args[0] = lower 32 bits of the address + * output: args[1] = upper 32 bits of the address + */ + {0, 2, HSMP_GET}, +}; + +/* Metrics table (supported only with proto version 6) */ +struct hsmp_metric_table { + __u32 accumulation_counter; + + /* TEMPERATURE */ + __u32 max_socket_temperature; + __u32 max_vr_temperature; + __u32 max_hbm_temperature; + __u64 max_socket_temperature_acc; + __u64 max_vr_temperature_acc; + __u64 max_hbm_temperature_acc; + + /* POWER */ + __u32 socket_power_limit; + __u32 max_socket_power_limit; + __u32 socket_power; + + /* ENERGY */ + __u64 timestamp; + __u64 socket_energy_acc; + __u64 ccd_energy_acc; + __u64 xcd_energy_acc; + __u64 aid_energy_acc; + __u64 hbm_energy_acc; + + /* FREQUENCY */ + __u32 cclk_frequency_limit; + __u32 gfxclk_frequency_limit; + __u32 fclk_frequency; + __u32 uclk_frequency; + __u32 socclk_frequency[4]; + __u32 vclk_frequency[4]; + __u32 dclk_frequency[4]; + __u32 lclk_frequency[4]; + __u64 gfxclk_frequency_acc[8]; + __u64 cclk_frequency_acc[96]; + + /* FREQUENCY RANGE */ + __u32 max_cclk_frequency; + __u32 min_cclk_frequency; + __u32 max_gfxclk_frequency; + __u32 min_gfxclk_frequency; + __u32 fclk_frequency_table[4]; + __u32 uclk_frequency_table[4]; + __u32 socclk_frequency_table[4]; + __u32 vclk_frequency_table[4]; + __u32 dclk_frequency_table[4]; + __u32 lclk_frequency_table[4]; + __u32 max_lclk_dpm_range; + __u32 min_lclk_dpm_range; + + /* XGMI */ + __u32 xgmi_width; + __u32 xgmi_bitrate; + __u64 xgmi_read_bandwidth_acc[8]; + __u64 xgmi_write_bandwidth_acc[8]; + + /* ACTIVITY */ + __u32 socket_c0_residency; + __u32 socket_gfx_busy; + __u32 dram_bandwidth_utilization; + __u64 socket_c0_residency_acc; + __u64 socket_gfx_busy_acc; + __u64 dram_bandwidth_acc; + __u32 max_dram_bandwidth; + __u64 dram_bandwidth_utilization_acc; + __u64 pcie_bandwidth_acc[4]; + + /* THROTTLERS */ + __u32 prochot_residency_acc; + __u32 ppt_residency_acc; + __u32 socket_thm_residency_acc; + __u32 vr_thm_residency_acc; + __u32 hbm_thm_residency_acc; + __u32 spare; + + /* New items at the end to maintain driver compatibility */ + __u32 gfxclk_frequency[8]; }; /* Reset to default packing */ diff --git a/drivers/platform/x86/amd/hsmp.c b/drivers/platform/x86/amd/hsmp.c index 99727cd705cf..af8adfbd9369 100644 --- a/drivers/platform/x86/amd/hsmp.c +++ b/drivers/platform/x86/amd/hsmp.c @@ -20,7 +20,7 @@ #include #define DRIVER_NAME "amd_hsmp" -#define DRIVER_VERSION "1.0" +#define DRIVER_VERSION "2.0" /* HSMP Status / Error codes */ #define HSMP_STATUS_NOT_READY 0x00 @@ -49,9 +49,15 @@ #define HSMP_CDEV_NAME "hsmp_cdev" #define HSMP_DEVNODE_NAME "hsmp" +#define HSMP_METRICS_TABLE_NAME "metrics_bin" + +#define HSMP_ATTR_GRP_NAME_SIZE 10 struct hsmp_socket { + struct bin_attribute hsmp_attr; + void __iomem *metric_tbl_addr; struct semaphore hsmp_sem; + char name[HSMP_ATTR_GRP_NAME_SIZE]; u16 sock_ind; }; @@ -59,6 +65,7 @@ struct hsmp_plat_device { struct miscdevice hsmp_device; struct hsmp_socket *sock; struct device *dev; + u32 proto_ver; u16 num_sockets; }; @@ -330,9 +337,162 @@ static const struct file_operations hsmp_fops = { .compat_ioctl = hsmp_ioctl, }; +static ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t off, size_t count) +{ + struct hsmp_socket *sock = bin_attr->private; + struct hsmp_message msg = { 0 }; + int ret; + + /* Do not support lseek(), reads entire metric table */ + if (count < bin_attr->size) { + dev_err(plat_dev.dev, "Wrong buffer size\n"); + return -EINVAL; + } + + if (!sock) { + dev_err(plat_dev.dev, "Failed to read attribute private data\n"); + return -EINVAL; + } + + msg.msg_id = HSMP_GET_METRIC_TABLE; + msg.sock_ind = sock->sock_ind; + + ret = hsmp_send_message(&msg); + if (ret) + return ret; + memcpy(buf, sock->metric_tbl_addr, bin_attr->size); + + return bin_attr->size; +} + +static int hsmp_get_tbl_dram_base(u16 sock_ind) +{ + struct hsmp_socket *sock = &plat_dev.sock[sock_ind]; + struct hsmp_message msg = { 0 }; + phys_addr_t dram_addr; + int ret; + + msg.sock_ind = sock_ind; + msg.response_sz = hsmp_msg_desc_table[HSMP_GET_METRIC_TABLE_DRAM_ADDR].response_sz; + msg.msg_id = HSMP_GET_METRIC_TABLE_DRAM_ADDR; + + ret = hsmp_send_message(&msg); + if (ret) + return ret; + + /* + * calculate the metric table DRAM address from lower and upper 32 bits + * sent from SMU and ioremap it to virtual address. + */ + dram_addr = msg.args[0] | ((u64)(msg.args[1]) << 32); + if (!dram_addr) { + dev_err(plat_dev.dev, "Invalid DRAM address for metric table\n"); + return -ENOMEM; + } + sock->metric_tbl_addr = devm_ioremap(plat_dev.dev, dram_addr, + sizeof(struct hsmp_metric_table)); + if (!sock->metric_tbl_addr) { + dev_err(plat_dev.dev, "Failed to ioremap metric table addr\n"); + return -ENOMEM; + } + return 0; +} + +static umode_t hsmp_is_sock_attr_visible(struct kobject *kobj, + struct bin_attribute *battr, int id) +{ + if (plat_dev.proto_ver == HSMP_PROTO_VER6) + return battr->attr.mode; + else + return 0; +} + +static int hsmp_init_metric_tbl_bin_attr(struct bin_attribute **hattrs, u16 sock_ind) +{ + struct bin_attribute *hattr = &plat_dev.sock[sock_ind].hsmp_attr; + + sysfs_bin_attr_init(hattr); + hattr->attr.name = HSMP_METRICS_TABLE_NAME; + hattr->attr.mode = 0444; + hattr->read = hsmp_metric_tbl_read; + hattr->size = sizeof(struct hsmp_metric_table); + hattr->private = &plat_dev.sock[sock_ind]; + hattrs[0] = hattr; + + if (plat_dev.proto_ver == HSMP_PROTO_VER6) + return (hsmp_get_tbl_dram_base(sock_ind)); + else + return 0; +} + +/* One bin sysfs for metrics table*/ +#define NUM_HSMP_ATTRS 1 + +static int hsmp_create_sysfs_interface(void) +{ + const struct attribute_group **hsmp_attr_grps; + struct bin_attribute **hsmp_bin_attrs; + struct attribute_group *attr_grp; + int ret; + u16 i; + + /* String formatting is currently limited to u8 sockets */ + if (WARN_ON(plat_dev.num_sockets > U8_MAX)) + return -ERANGE; + + hsmp_attr_grps = devm_kzalloc(plat_dev.dev, sizeof(struct attribute_group *) * + (plat_dev.num_sockets + 1), GFP_KERNEL); + if (!hsmp_attr_grps) + return -ENOMEM; + + /* Create a sysfs directory for each socket */ + for (i = 0; i < plat_dev.num_sockets; i++) { + attr_grp = devm_kzalloc(plat_dev.dev, sizeof(struct attribute_group), GFP_KERNEL); + if (!attr_grp) + return -ENOMEM; + + snprintf(plat_dev.sock[i].name, HSMP_ATTR_GRP_NAME_SIZE, "socket%u", (u8)i); + attr_grp->name = plat_dev.sock[i].name; + + /* Null terminated list of attributes */ + hsmp_bin_attrs = devm_kzalloc(plat_dev.dev, sizeof(struct bin_attribute *) * + (NUM_HSMP_ATTRS + 1), GFP_KERNEL); + if (!hsmp_bin_attrs) + return -ENOMEM; + + attr_grp->bin_attrs = hsmp_bin_attrs; + attr_grp->is_bin_visible = hsmp_is_sock_attr_visible; + hsmp_attr_grps[i] = attr_grp; + + /* Now create the leaf nodes */ + ret = hsmp_init_metric_tbl_bin_attr(hsmp_bin_attrs, i); + if (ret) + return ret; + } + return devm_device_add_groups(plat_dev.dev, hsmp_attr_grps); +} + +static int hsmp_cache_proto_ver(void) +{ + struct hsmp_message msg = { 0 }; + int ret; + + msg.msg_id = HSMP_GET_PROTO_VER; + msg.sock_ind = 0; + msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; + + ret = hsmp_send_message(&msg); + if (!ret) + plat_dev.proto_ver = msg.args[0]; + + return ret; +} + static int hsmp_pltdrv_probe(struct platform_device *pdev) { - int i; + int ret, i; plat_dev.sock = devm_kzalloc(&pdev->dev, (plat_dev.num_sockets * sizeof(struct hsmp_socket)), @@ -353,6 +513,16 @@ static int hsmp_pltdrv_probe(struct platform_device *pdev) plat_dev.hsmp_device.nodename = HSMP_DEVNODE_NAME; plat_dev.hsmp_device.mode = 0644; + ret = hsmp_cache_proto_ver(); + if (ret) { + dev_err(plat_dev.dev, "Failed to read HSMP protocol version\n"); + return ret; + } + + ret = hsmp_create_sysfs_interface(); + if (ret) + dev_err(plat_dev.dev, "Failed to create HSMP sysfs interface\n"); + return misc_register(&plat_dev.hsmp_device); } From 48173b0003c5dc556e262e1b57c25efc36db1c6a Mon Sep 17 00:00:00 2001 From: Suma Hegde Date: Tue, 10 Oct 2023 12:03:10 +0000 Subject: [PATCH 230/396] platform/x86/amd/hsmp: improve the error log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Change print message during platform init to a more meaningful clear message. 2. Return the error code returned by hsmp_test() itself, rather then returning a common EOPNOTSUPP error. Signed-off-by: Suma Hegde Reviewed-by: Naveen Krishna Chatradhi Link: https://lore.kernel.org/r/20231010120310.3464066-3-suma.hegde@amd.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/hsmp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/amd/hsmp.c b/drivers/platform/x86/amd/hsmp.c index af8adfbd9369..b056a5c8654a 100644 --- a/drivers/platform/x86/amd/hsmp.c +++ b/drivers/platform/x86/amd/hsmp.c @@ -564,10 +564,10 @@ static int __init hsmp_plt_init(void) for (i = 0; i < plat_dev.num_sockets; i++) { ret = hsmp_test(i, 0xDEADBEEF); if (ret) { - pr_err("HSMP is not supported on Fam:%x model:%x\n", + pr_err("HSMP test message failed on Fam:%x model:%x\n", boot_cpu_data.x86, boot_cpu_data.x86_model); - pr_err("Or Is HSMP disabled in BIOS ?\n"); - return -EOPNOTSUPP; + pr_err("Is HSMP disabled in BIOS ?\n"); + return ret; } } From 39789590cff4043d81774d03777dabf7ba263176 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Oct 2023 16:39:36 +0300 Subject: [PATCH 231/396] platform/x86: xo15-ebook: Replace open coded acpi_match_acpi_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace open coded acpi_match_acpi_device() in ebook_switch_add(). Note, while it is a bit longer it is more robust in case more IDs will be added. Reviewed-by: Hans de Goede Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231010133936.3891996-1-andriy.shevchenko@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/xo15-ebook.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c index 391f7ea4431e..df2bf1c58523 100644 --- a/drivers/platform/x86/xo15-ebook.c +++ b/drivers/platform/x86/xo15-ebook.c @@ -81,9 +81,9 @@ static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume); static int ebook_switch_add(struct acpi_device *device) { + const struct acpi_device_id *id; struct ebook_switch *button; struct input_dev *input; - const char *hid = acpi_device_hid(device); char *name, *class; int error; @@ -102,8 +102,9 @@ static int ebook_switch_add(struct acpi_device *device) name = acpi_device_name(device); class = acpi_device_class(device); - if (strcmp(hid, XO15_EBOOK_HID)) { - pr_err("Unsupported hid [%s]\n", hid); + id = acpi_match_acpi_device(ebook_device_ids, device); + if (!id) { + dev_err(&device->dev, "Unsupported hid\n"); error = -ENODEV; goto err_free_input; } @@ -111,7 +112,7 @@ static int ebook_switch_add(struct acpi_device *device) strcpy(name, XO15_EBOOK_DEVICE_NAME); sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS); - snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); + snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id); input->name = name; input->phys = button->phys; From 5a026767275ef0ba6d7aba37629d9ec638aabb7d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Oct 2023 16:40:19 +0300 Subject: [PATCH 232/396] platform/x86: asus-wireless: Replace open coded acpi_match_acpi_device() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace open coded acpi_match_acpi_device() in asus_wireless_add(). Reviewed-by: Hans de Goede Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20231010134019.3892062-1-andriy.shevchenko@linux.intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-wireless.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index abf01e00b799..41227bf95878 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -148,16 +148,12 @@ static int asus_wireless_add(struct acpi_device *adev) if (err) return err; - for (id = device_ids; id->id[0]; id++) { - if (!strcmp((char *) id->id, acpi_device_hid(adev))) { - data->hswc_params = - (const struct hswc_params *)id->driver_data; - break; - } - } - if (!data->hswc_params) + id = acpi_match_acpi_device(device_ids, adev); + if (!id) return 0; + data->hswc_params = (const struct hswc_params *)id->driver_data; + data->wq = create_singlethread_workqueue("asus_wireless_workqueue"); if (!data->wq) return -ENOMEM; From d9f421da6b9287000f8253628d54cf89b0c14da5 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 10 Oct 2023 20:20:01 +0530 Subject: [PATCH 233/396] platform/x86/amd/pmc: Use flex array when calling amd_pmc_stb_debugfs_open_v2() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently in amd_pmc_stb_debugfs_open_v2() the buffer size is assumed to be fixed and a second call to amd_pmc_stb_debugfs_open_v2() may race with a process holding open another fd. This could change "fsize" to a bigger size causing an out of bounds read. Instead create a struct with a flexarray to solve this. Suggested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20231010145003.139932-1-Shyam-sundar.S-k@amd.com [ij: renamed flex_arr -> stb_data_arr] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmc/pmc.c | 32 ++++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index 922932a71233..77dca9a1f00f 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -52,7 +52,7 @@ #define AMD_S2D_REGISTER_ARGUMENT 0xA88 /* STB Spill to DRAM Parameters */ -#define S2D_TELEMETRY_BYTES_MAX 0x100000 +#define S2D_TELEMETRY_BYTES_MAX 0x100000U #define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000 /* STB Spill to DRAM Message Definition */ @@ -122,6 +122,11 @@ enum s2d_arg { S2D_DRAM_SIZE, }; +struct amd_pmc_stb_v2_data { + size_t size; + u8 data[] __counted_by(size); +}; + struct amd_pmc_bit_map { const char *name; u32 bit_mask; @@ -239,7 +244,8 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = { static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) { struct amd_pmc_dev *dev = filp->f_inode->i_private; - u32 *buf, fsize, num_samples, val, stb_rdptr_offset = 0; + u32 fsize, num_samples, val, stb_rdptr_offset = 0; + struct amd_pmc_stb_v2_data *stb_data_arr; int ret; /* Write dummy postcode while reading the STB buffer */ @@ -247,10 +253,6 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) if (ret) dev_err(dev->dev, "error writing to STB: %d\n", ret); - buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL); - if (!buf) - return -ENOMEM; - /* Spill to DRAM num_samples uses separate SMU message port */ dev->msg_port = 1; @@ -264,10 +266,16 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) dev->msg_port = 0; if (ret) { dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret); - kfree(buf); return ret; } + fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX); + stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); + if (!stb_data_arr) + return -ENOMEM; + + stb_data_arr->size = fsize; + /* Start capturing data from the last push location */ if (num_samples > S2D_TELEMETRY_BYTES_MAX) { fsize = S2D_TELEMETRY_BYTES_MAX; @@ -277,8 +285,8 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) stb_rdptr_offset = 0; } - memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize); - filp->private_data = buf; + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize); + filp->private_data = stb_data_arr; return 0; } @@ -286,11 +294,9 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) static ssize_t amd_pmc_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size, loff_t *pos) { - if (!filp->private_data) - return -EINVAL; + struct amd_pmc_stb_v2_data *data = filp->private_data; - return simple_read_from_buffer(buf, size, pos, filp->private_data, - S2D_TELEMETRY_BYTES_MAX); + return simple_read_from_buffer(buf, size, pos, data->data, data->size); } static int amd_pmc_stb_debugfs_release_v2(struct inode *inode, struct file *filp) From b136225746a9793bdff9c78b215eac4f64bf21f2 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 10 Oct 2023 20:20:02 +0530 Subject: [PATCH 234/396] platform/x86/amd/pmc: Handle overflow cases where the num_samples range is higher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In amd_pmc_stb_debugfs_open_v2(), the stb buffer is created based on the num_samples and the read/write pointer offset. This holds good when the num_samples reported by PMFW is less than S2D_TELEMETRY_BYTES_MAX; where the stb buffer gets filled from 0th position until S2D_TELEMETRY_BYTES_MAX - 1 based on the read/write pointer offset. But when the num_samples exceeds the S2D_TELEMETRY_BYTES_MAX, the current code does not handle it well as it does not account for the cases where the stb buffer has to filled up as a circular buffer. Handle this scenario into two cases, where first memcpy will have the samples from location: (num_samples % S2D_TELEMETRY_BYTES_MAX) - (S2D_TELEMETRY_BYTES_MAX - 1) and next memcpy will have the newest ones i.e. 0 - (num_samples % S2D_TELEMETRY_BYTES_MAX - 1) Suggested-by: Hans de Goede Reviewed-by: Hans de Goede Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20231010145003.139932-2-Shyam-sundar.S-k@amd.com [ij: renamed flex_arr -> stb_data_arr] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmc/pmc.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index 77dca9a1f00f..bc254e1fa71a 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -276,16 +276,23 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) stb_data_arr->size = fsize; - /* Start capturing data from the last push location */ + /* + * Start capturing data from the last push location. + * This is for general cases, where the stb limits + * are meant for standard usage. + */ if (num_samples > S2D_TELEMETRY_BYTES_MAX) { - fsize = S2D_TELEMETRY_BYTES_MAX; - stb_rdptr_offset = num_samples - fsize; + /* First read oldest data starting 1 behind last write till end of ringbuffer */ + stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX; + fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset; + + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize); + /* Second copy the newer samples from offset 0 - last write */ + memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset); } else { - fsize = num_samples; - stb_rdptr_offset = 0; + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); } - memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize); filp->private_data = stb_data_arr; return 0; From 3f720b21ec5af466e50e99dc517af267b67d248c Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Tue, 10 Oct 2023 20:20:03 +0530 Subject: [PATCH 235/396] platform/x86/amd/pmc: Add dump_custom_stb module parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There have been instances when the default size (1M) of the STB is not sufficient to get the complete traces of the failure. In such scenarios we can use a module_param to enable full trace that shall contain more debugging data. This is not a regular case and hence not enabling this capability by default. With this change, there will be two cases on how the driver fetches the stb data: 1) A special case (proposed now) - which is required only for certain platforms. Here, a new module param will be supplied to the driver that will have a special PMFW supporting enhanced dram sizes for getting the stb data. Without the special PMFW support, just setting the module param will not help to get the enhanced stb data. To adapt to this change, we will have a new amd_pmc_stb_handle_efr() to handle enhanced firmware reporting mechanism. Note that, since num_samples based r/w pointer offset calculation is not required for enhanced firmware reporting we will have this mailbox command sent only in case of regular STB cases. 2) Current code branch which fetches the stb data based on the parameters like the num_samples, fsize and the r/w pointer. Reviewed-by: Ilpo Järvinen Reviewed-by: Hans de Goede Co-developed-by: Harsh Jain Signed-off-by: Harsh Jain Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20231010145003.139932-3-Shyam-sundar.S-k@amd.com [ij: Renamed flex_arr -> stb_data_arr] Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/pmc/pmc.c | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index bc254e1fa71a..cd6ac04c1468 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -53,6 +53,7 @@ /* STB Spill to DRAM Parameters */ #define S2D_TELEMETRY_BYTES_MAX 0x100000U +#define S2D_RSVD_RAM_SPACE 0x100000 #define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000 /* STB Spill to DRAM Message Definition */ @@ -165,6 +166,10 @@ static bool disable_workarounds; module_param(disable_workarounds, bool, 0644); MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs"); +static bool dump_custom_stb; +module_param(dump_custom_stb, bool, 0644); +MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer"); + static struct amd_pmc_dev pmc; static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret); static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf); @@ -241,6 +246,25 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = { .release = amd_pmc_stb_debugfs_release, }; +/* Enhanced STB Firmware Reporting Mechanism */ +static int amd_pmc_stb_handle_efr(struct file *filp) +{ + struct amd_pmc_dev *dev = filp->f_inode->i_private; + struct amd_pmc_stb_v2_data *stb_data_arr; + u32 fsize; + + fsize = dev->dram_size - S2D_RSVD_RAM_SPACE; + stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); + if (!stb_data_arr) + return -ENOMEM; + + stb_data_arr->size = fsize; + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); + filp->private_data = stb_data_arr; + + return 0; +} + static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) { struct amd_pmc_dev *dev = filp->f_inode->i_private; @@ -260,6 +284,14 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) if (ret) dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret); + /* + * We have a custom stb size and the PMFW is supposed to give + * the enhanced dram size. Note that we land here only for the + * platforms that support enhanced dram size reporting. + */ + if (dump_custom_stb) + return amd_pmc_stb_handle_efr(filp); + /* Get the num_samples to calculate the last push location */ ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->s2d_msg_id, true); /* Clear msg_port for other SMU operation */ From 0b40f91d43f72d52fb2a3f04c018d703e0477cc3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 11 Oct 2023 23:26:37 +0300 Subject: [PATCH 236/396] hte: tegra194: Remove redundant dev_err() There is no need to call the dev_err() function directly to print a custom message when handling an error from platform_get_irq() function as it is going to display an appropriate error message in case of a failure. Reviewed-by: Dipen Patel Tested-by: Dipen Patel Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20231010151709.4104747-4-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Dipen Patel --- drivers/hte/hte-tegra194.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hte/hte-tegra194.c b/drivers/hte/hte-tegra194.c index 9fd3c00ff695..698573e25436 100644 --- a/drivers/hte/hte-tegra194.c +++ b/drivers/hte/hte-tegra194.c @@ -731,10 +731,8 @@ static int tegra_hte_probe(struct platform_device *pdev) return -ENOMEM; ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err_probe(dev, ret, "failed to get irq\n"); + if (ret < 0) return ret; - } hte_dev->hte_irq = ret; ret = devm_request_irq(dev, hte_dev->hte_irq, tegra_hte_isr, 0, dev_name(dev), hte_dev); From 091ac92dc79e35ba208b022936dc9f13e0bbad7c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 11 Oct 2023 23:26:38 +0300 Subject: [PATCH 237/396] hte: tegra194: Switch to LATE_SIMPLE_DEV_PM_OPS() SET_LATE_SYSTEM_SLEEP_PM_OPS is deprecated, replace it with LATE_SYSTEM_SLEEP_PM_OPS() and use pm_sleep_ptr() for setting the driver's pm routines. We can now remove the __maybe_unused qualifier in the suspend and resume functions. Tested-by: Dipen Patel Reviewed-by: Dipen Patel Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20231010151709.4104747-5-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Dipen Patel --- drivers/hte/hte-tegra194.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/hte/hte-tegra194.c b/drivers/hte/hte-tegra194.c index 698573e25436..ac0480c11f42 100644 --- a/drivers/hte/hte-tegra194.c +++ b/drivers/hte/hte-tegra194.c @@ -810,7 +810,7 @@ static int tegra_hte_probe(struct platform_device *pdev) return 0; } -static int __maybe_unused tegra_hte_resume_early(struct device *dev) +static int tegra_hte_resume_early(struct device *dev) { u32 i; struct tegra_hte_soc *gs = dev_get_drvdata(dev); @@ -831,7 +831,7 @@ static int __maybe_unused tegra_hte_resume_early(struct device *dev) return 0; } -static int __maybe_unused tegra_hte_suspend_late(struct device *dev) +static int tegra_hte_suspend_late(struct device *dev) { u32 i; struct tegra_hte_soc *gs = dev_get_drvdata(dev); @@ -851,15 +851,14 @@ static int __maybe_unused tegra_hte_suspend_late(struct device *dev) } static const struct dev_pm_ops tegra_hte_pm = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra_hte_suspend_late, - tegra_hte_resume_early) + LATE_SYSTEM_SLEEP_PM_OPS(tegra_hte_suspend_late, tegra_hte_resume_early) }; static struct platform_driver tegra_hte_driver = { .probe = tegra_hte_probe, .driver = { .name = "tegra_hte", - .pm = &tegra_hte_pm, + .pm = pm_sleep_ptr(&tegra_hte_pm), .of_match_table = tegra_hte_of_match, }, }; From fd627207aaa782c1fd4224076b56a03a1059f516 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 10 Oct 2023 16:26:56 +0300 Subject: [PATCH 238/396] clk: renesas: rzg2l: Use %x format specifier to print CLK_ON_R() Use the %x format specifier to print CLK_ON_R(). This makes debugging easier as the value printed will be hexadecimal like in the hardware manual. Along with it add "0x" in front of the printed value. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231010132701.1658737-2-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index d62f1bc1f60e..764bd72cf059 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1213,7 +1213,7 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable) return 0; } - dev_dbg(dev, "CLK_ON %u/%pC %s\n", CLK_ON_R(reg), hw->clk, + dev_dbg(dev, "CLK_ON 0x%x/%pC %s\n", CLK_ON_R(reg), hw->clk, enable ? "ON" : "OFF"); value = bitmask << 16; From 4bce4bedbe6daa54cf701184601f913a0c00bb1c Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 10 Oct 2023 16:26:57 +0300 Subject: [PATCH 239/396] clk: renesas: r9a08g045: Add clock and reset support for SDHI1 and SDHI2 Add clock and reset support for the SDHI1 and SDHI2 blocks on the RZ/G3S (R9A08G045) SoC. Signed-off-by: Claudiu Beznea Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20231010132701.1658737-3-claudiu.beznea.uj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g045-cpg.c | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c index 389d32b32168..4394cb241d99 100644 --- a/drivers/clk/renesas/r9a08g045-cpg.c +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -25,6 +25,8 @@ /* RZ/G3S Specific division configuration. */ #define G3S_DIVPL2B DDIV_PACK(G3S_CPG_PL2_DDIV, 4, 3) #define G3S_DIV_SDHI0 DDIV_PACK(G3S_CPG_SDHI_DDIV, 0, 1) +#define G3S_DIV_SDHI1 DDIV_PACK(G3S_CPG_SDHI_DDIV, 4, 1) +#define G3S_DIV_SDHI2 DDIV_PACK(G3S_CPG_SDHI_DDIV, 8, 1) /* RZ/G3S Clock status configuration. */ #define G3S_DIVPL1A_STS DDIV_PACK(G3S_CLKDIVSTATUS, 0, 1) @@ -33,13 +35,19 @@ #define G3S_DIVPL3B_STS DDIV_PACK(G3S_CLKDIVSTATUS, 9, 1) #define G3S_DIVPL3C_STS DDIV_PACK(G3S_CLKDIVSTATUS, 10, 1) #define G3S_DIV_SDHI0_STS DDIV_PACK(G3S_CLKDIVSTATUS, 24, 1) +#define G3S_DIV_SDHI1_STS DDIV_PACK(G3S_CLKDIVSTATUS, 25, 1) +#define G3S_DIV_SDHI2_STS DDIV_PACK(G3S_CLKDIVSTATUS, 26, 1) #define G3S_SEL_PLL4_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 6, 1) #define G3S_SEL_SDHI0_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 16, 1) +#define G3S_SEL_SDHI1_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 17, 1) +#define G3S_SEL_SDHI2_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 18, 1) /* RZ/G3S Specific clocks select. */ #define G3S_SEL_PLL4 SEL_PLL_PACK(G3S_CPG_PLL_DSEL, 6, 1) #define G3S_SEL_SDHI0 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 0, 2) +#define G3S_SEL_SDHI1 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 4, 2) +#define G3S_SEL_SDHI2 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 8, 2) /* PLL 1/4/6 configuration registers macro. */ #define G3S_PLL146_CONF(clk1, clk2) ((clk1) << 22 | (clk2) << 12) @@ -74,10 +82,14 @@ enum clk_ids { CLK_PLL6, CLK_PLL6_DIV2, CLK_SEL_SDHI0, + CLK_SEL_SDHI1, + CLK_SEL_SDHI2, CLK_SEL_PLL4, CLK_P1_DIV2, CLK_P3_DIV2, CLK_SD0_DIV4, + CLK_SD1_DIV4, + CLK_SD2_DIV4, /* Module Clocks */ MOD_CLK_BASE, @@ -136,6 +148,10 @@ static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = { DEF_FIXED(".pll6_div2", CLK_PLL6_DIV2, CLK_PLL6, 1, 2), DEF_SD_MUX(".sel_sd0", CLK_SEL_SDHI0, G3S_SEL_SDHI0, G3S_SEL_SDHI0_STS, sel_sdhi, mtable_sd, 0, NULL), + DEF_SD_MUX(".sel_sd1", CLK_SEL_SDHI1, G3S_SEL_SDHI1, G3S_SEL_SDHI1_STS, sel_sdhi, + mtable_sd, 0, NULL), + DEF_SD_MUX(".sel_sd2", CLK_SEL_SDHI2, G3S_SEL_SDHI2, G3S_SEL_SDHI2_STS, sel_sdhi, + mtable_sd, 0, NULL), DEF_SD_MUX(".sel_pll4", CLK_SEL_PLL4, G3S_SEL_PLL4, G3S_SEL_PLL4_STS, sel_pll4, mtable_pll4, CLK_SET_PARENT_GATE, NULL), @@ -147,7 +163,15 @@ static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = { DEF_G3S_DIV("SD0", R9A08G045_CLK_SD0, CLK_SEL_SDHI0, G3S_DIV_SDHI0, G3S_DIV_SDHI0_STS, dtable_1_2, 800000000UL, 500000000UL, CLK_SET_RATE_PARENT, rzg3s_cpg_div_clk_notifier), + DEF_G3S_DIV("SD1", R9A08G045_CLK_SD1, CLK_SEL_SDHI1, G3S_DIV_SDHI1, G3S_DIV_SDHI1_STS, + dtable_1_2, 800000000UL, 500000000UL, CLK_SET_RATE_PARENT, + rzg3s_cpg_div_clk_notifier), + DEF_G3S_DIV("SD2", R9A08G045_CLK_SD2, CLK_SEL_SDHI2, G3S_DIV_SDHI2, G3S_DIV_SDHI2_STS, + dtable_1_2, 800000000UL, 500000000UL, CLK_SET_RATE_PARENT, + rzg3s_cpg_div_clk_notifier), DEF_FIXED(".sd0_div4", CLK_SD0_DIV4, R9A08G045_CLK_SD0, 1, 4), + DEF_FIXED(".sd1_div4", CLK_SD1_DIV4, R9A08G045_CLK_SD1, 1, 4), + DEF_FIXED(".sd2_div4", CLK_SD2_DIV4, R9A08G045_CLK_SD2, 1, 4), DEF_FIXED("M0", R9A08G045_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), DEF_G3S_DIV("P1", R9A08G045_CLK_P1, CLK_PLL3_DIV2_4, DIVPL3A, G3S_DIVPL3A_STS, dtable_1_32, 0, 0, 0, NULL), @@ -170,6 +194,14 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { DEF_MOD("sdhi0_imclk2", R9A08G045_SDHI0_IMCLK2, CLK_SD0_DIV4, 0x554, 1), DEF_MOD("sdhi0_clk_hs", R9A08G045_SDHI0_CLK_HS, R9A08G045_CLK_SD0, 0x554, 2), DEF_MOD("sdhi0_aclk", R9A08G045_SDHI0_ACLK, R9A08G045_CLK_P1, 0x554, 3), + DEF_MOD("sdhi1_imclk", R9A08G045_SDHI1_IMCLK, CLK_SD1_DIV4, 0x554, 4), + DEF_MOD("sdhi1_imclk2", R9A08G045_SDHI1_IMCLK2, CLK_SD1_DIV4, 0x554, 5), + DEF_MOD("sdhi1_clk_hs", R9A08G045_SDHI1_CLK_HS, R9A08G045_CLK_SD1, 0x554, 6), + DEF_MOD("sdhi1_aclk", R9A08G045_SDHI1_ACLK, R9A08G045_CLK_P1, 0x554, 7), + DEF_MOD("sdhi2_imclk", R9A08G045_SDHI2_IMCLK, CLK_SD2_DIV4, 0x554, 8), + DEF_MOD("sdhi2_imclk2", R9A08G045_SDHI2_IMCLK2, CLK_SD2_DIV4, 0x554, 9), + DEF_MOD("sdhi2_clk_hs", R9A08G045_SDHI2_CLK_HS, R9A08G045_CLK_SD2, 0x554, 10), + DEF_MOD("sdhi2_aclk", R9A08G045_SDHI2_ACLK, R9A08G045_CLK_P1, 0x554, 11), DEF_MOD("scif0_clk_pck", R9A08G045_SCIF0_CLK_PCK, R9A08G045_CLK_P0, 0x584, 0), DEF_MOD("gpio_hclk", R9A08G045_GPIO_HCLK, R9A08G045_OSCCLK, 0x598, 0), }; @@ -178,6 +210,8 @@ static const struct rzg2l_reset r9a08g045_resets[] = { DEF_RST(R9A08G045_GIC600_GICRESET_N, 0x814, 0), DEF_RST(R9A08G045_GIC600_DBG_GICRESET_N, 0x814, 1), DEF_RST(R9A08G045_SDHI0_IXRST, 0x854, 0), + DEF_RST(R9A08G045_SDHI1_IXRST, 0x854, 1), + DEF_RST(R9A08G045_SDHI2_IXRST, 0x854, 2), DEF_RST(R9A08G045_SCIF0_RST_SYSTEM_N, 0x884, 0), DEF_RST(R9A08G045_GPIO_RSTN, 0x898, 0), DEF_RST(R9A08G045_GPIO_PORT_RESETN, 0x898, 1), From 2e9abc6ec108370ad341f98d0e05e02e4e165b5a Mon Sep 17 00:00:00 2001 From: Frank Oltmanns Date: Sat, 17 Jun 2023 15:10:40 +0200 Subject: [PATCH 240/396] clk: fractional-divider: Improve approximation when zero based and export Consider the CLK_FRAC_DIVIDER_ZERO_BASED flag when finding the best approximation for m and n. By doing so, increase the range of valid values for the numerator and denominator by 1. Furthermore, export the approximation function so that users of this function can be compiled as modules. Cc: A.s. Dong Signed-off-by: Frank Oltmanns Link: https://lore.kernel.org/r/20230617131041.18313-2-frank@oltmanns.dev Signed-off-by: Stephen Boyd --- drivers/clk/clk-fractional-divider.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 479297763e70..5067e067e906 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -123,6 +123,7 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw, unsigned long *m, unsigned long *n) { struct clk_fractional_divider *fd = to_clk_fd(hw); + unsigned long max_m, max_n; /* * Get rate closer to *parent_rate to guarantee there is no overflow @@ -138,10 +139,17 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw, rate <<= scale - fd->nwidth; } - rational_best_approximation(rate, *parent_rate, - GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), - m, n); + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + max_m = 1 << fd->mwidth; + max_n = 1 << fd->nwidth; + } else { + max_m = GENMASK(fd->mwidth - 1, 0); + max_n = GENMASK(fd->nwidth - 1, 0); + } + + rational_best_approximation(rate, *parent_rate, max_m, max_n, m, n); } +EXPORT_SYMBOL_GPL(clk_fractional_divider_general_approximation); static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) @@ -169,13 +177,18 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_fractional_divider *fd = to_clk_fd(hw); unsigned long flags = 0; - unsigned long m, n; + unsigned long m, n, max_m, max_n; u32 mmask, nmask; u32 val; - rational_best_approximation(rate, parent_rate, - GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0), - &m, &n); + if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { + max_m = 1 << fd->mwidth; + max_n = 1 << fd->nwidth; + } else { + max_m = GENMASK(fd->mwidth - 1, 0); + max_n = GENMASK(fd->nwidth - 1, 0); + } + rational_best_approximation(rate, parent_rate, max_m, max_n, &m, &n); if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) { m--; From 2790e2a33aa9e0710354aaabce8ae1a92925348f Mon Sep 17 00:00:00 2001 From: Frank Oltmanns Date: Sat, 17 Jun 2023 15:10:41 +0200 Subject: [PATCH 241/396] clk: fractional-divider: tests: Add test suite for edge cases In light of the recent discovery that the fractional divisor approximation does not utilize the full available range for clocks that are flagged CLK_FRAC_DIVIDER_ZERO_BASED [1], implement tests for the edge cases of this clock type. Signed-off-by: Frank Oltmanns Link: https://lore.kernel.org/lkml/20230529133433.56215-1-frank@oltmanns.dev [1] Link: https://lore.kernel.org/r/20230617131041.18313-3-frank@oltmanns.dev [sboyd@kernel.org: Rename suite and tests slightly, drop unused includes, store parent rate to compare instead of repeating equation] Signed-off-by: Stephen Boyd --- drivers/clk/.kunitconfig | 1 + drivers/clk/Kconfig | 7 ++ drivers/clk/Makefile | 1 + drivers/clk/clk-fractional-divider_test.c | 147 ++++++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 drivers/clk/clk-fractional-divider_test.c diff --git a/drivers/clk/.kunitconfig b/drivers/clk/.kunitconfig index 2fbeb71316f8..efa12ac2b3f2 100644 --- a/drivers/clk/.kunitconfig +++ b/drivers/clk/.kunitconfig @@ -2,4 +2,5 @@ CONFIG_KUNIT=y CONFIG_COMMON_CLK=y CONFIG_CLK_KUNIT_TEST=y CONFIG_CLK_GATE_KUNIT_TEST=y +CONFIG_CLK_FD_KUNIT_TEST=y CONFIG_UML_PCI_OVER_VIRTIO=n diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c30099866174..5ac8f0692d75 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -517,4 +517,11 @@ config CLK_GATE_KUNIT_TEST help Kunit test for the basic clk gate type. +config CLK_FD_KUNIT_TEST + tristate "Basic fractional divider type Kunit test" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Kunit test for the clk-fractional-divider type. + endif diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 18969cbd4bb1..fde9ceb53ce4 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_COMMON_CLK) += clk-composite.o obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o +obj-$(CONFIG_CLK_FD_KUNIT_TEST) += clk-fractional-divider_test.o obj-$(CONFIG_COMMON_CLK) += clk-gpio.o ifeq ($(CONFIG_OF), y) obj-$(CONFIG_COMMON_CLK) += clk-conf.o diff --git a/drivers/clk/clk-fractional-divider_test.c b/drivers/clk/clk-fractional-divider_test.c new file mode 100644 index 000000000000..929eec927548 --- /dev/null +++ b/drivers/clk/clk-fractional-divider_test.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Kunit test for clock fractional divider + */ +#include +#include + +#include "clk-fractional-divider.h" + +/* + * Test the maximum denominator case for fd clock without flags. + * + * Expect the highest possible denominator to be used in order to get as close as possible to the + * requested rate. + */ +static void clk_fd_test_approximation_max_denominator(struct kunit *test) +{ + struct clk_fractional_divider *fd; + unsigned long rate, parent_rate, parent_rate_before, m, n, max_n; + + fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fd); + + fd->mwidth = 3; + fd->nwidth = 3; + max_n = 7; + + rate = 240000000; + parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */ + parent_rate_before = parent_rate; + + clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n); + KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before); + + KUNIT_EXPECT_EQ(test, m, 1); + KUNIT_EXPECT_EQ(test, n, max_n); +} + +/* + * Test the maximum numerator case for fd clock without flags. + * + * Expect the highest possible numerator to be used in order to get as close as possible to the + * requested rate. + */ +static void clk_fd_test_approximation_max_numerator(struct kunit *test) +{ + struct clk_fractional_divider *fd; + unsigned long rate, parent_rate, parent_rate_before, m, n, max_m; + + fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fd); + + fd->mwidth = 3; + max_m = 7; + fd->nwidth = 3; + + rate = 240000000; + parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */ + parent_rate_before = parent_rate; + + clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n); + KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before); + + KUNIT_EXPECT_EQ(test, m, max_m); + KUNIT_EXPECT_EQ(test, n, 1); +} + +/* + * Test the maximum denominator case for zero based fd clock. + * + * Expect the highest possible denominator to be used in order to get as close as possible to the + * requested rate. + */ +static void clk_fd_test_approximation_max_denominator_zero_based(struct kunit *test) +{ + struct clk_fractional_divider *fd; + unsigned long rate, parent_rate, parent_rate_before, m, n, max_n; + + fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fd); + + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; + fd->mwidth = 3; + fd->nwidth = 3; + max_n = 8; + + rate = 240000000; + parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */ + parent_rate_before = parent_rate; + + clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n); + KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before); + + KUNIT_EXPECT_EQ(test, m, 1); + KUNIT_EXPECT_EQ(test, n, max_n); +} + +/* + * Test the maximum numerator case for zero based fd clock. + * + * Expect the highest possible numerator to be used in order to get as close as possible to the + * requested rate. + */ +static void clk_fd_test_approximation_max_numerator_zero_based(struct kunit *test) +{ + struct clk_fractional_divider *fd; + unsigned long rate, parent_rate, parent_rate_before, m, n, max_m; + + fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fd); + + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; + fd->mwidth = 3; + max_m = 8; + fd->nwidth = 3; + + rate = 240000000; + parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */ + parent_rate_before = parent_rate; + + clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n); + KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before); + + KUNIT_EXPECT_EQ(test, m, max_m); + KUNIT_EXPECT_EQ(test, n, 1); +} + +static struct kunit_case clk_fd_approximation_test_cases[] = { + KUNIT_CASE(clk_fd_test_approximation_max_denominator), + KUNIT_CASE(clk_fd_test_approximation_max_numerator), + KUNIT_CASE(clk_fd_test_approximation_max_denominator_zero_based), + KUNIT_CASE(clk_fd_test_approximation_max_numerator_zero_based), + {} +}; + +/* + * Test suite for clk_fractional_divider_general_approximation(). + */ +static struct kunit_suite clk_fd_approximation_suite = { + .name = "clk-fd-approximation", + .test_cases = clk_fd_approximation_test_cases, +}; + +kunit_test_suites( + &clk_fd_approximation_suite +); +MODULE_LICENSE("GPL"); From 13b4c6964665cadb9b06c085029710c43a0c662e Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Fri, 6 Oct 2023 10:04:25 -0300 Subject: [PATCH 242/396] power: reset: gpio-poweroff: use a struct to store the module variables Use a struct to store the module variables. This is required to later move to notifier_blocks where we can have several instances. Signed-off-by: Stefan Eichenberger Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20231006130428.11259-2-francesco@dolcini.it Signed-off-by: Sebastian Reichel --- drivers/power/reset/gpio-poweroff.c | 50 ++++++++++++++++++----------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index b28f24da1b3c..dea550e422f3 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c @@ -17,32 +17,37 @@ #include #define DEFAULT_TIMEOUT_MS 3000 + +struct gpio_poweroff { + struct gpio_desc *reset_gpio; + u32 timeout_ms; + u32 active_delay_ms; + u32 inactive_delay_ms; +}; + /* * Hold configuration here, cannot be more than one instance of the driver * since pm_power_off itself is global. */ -static struct gpio_desc *reset_gpio; -static u32 timeout = DEFAULT_TIMEOUT_MS; -static u32 active_delay = 100; -static u32 inactive_delay = 100; +static struct gpio_poweroff *gpio_poweroff; static void gpio_poweroff_do_poweroff(void) { - BUG_ON(!reset_gpio); + BUG_ON(!gpio_poweroff); /* drive it active, also inactive->active edge */ - gpiod_direction_output(reset_gpio, 1); - mdelay(active_delay); + gpiod_direction_output(gpio_poweroff->reset_gpio, 1); + mdelay(gpio_poweroff->active_delay_ms); /* drive inactive, also active->inactive edge */ - gpiod_set_value_cansleep(reset_gpio, 0); - mdelay(inactive_delay); + gpiod_set_value_cansleep(gpio_poweroff->reset_gpio, 0); + mdelay(gpio_poweroff->inactive_delay_ms); /* drive it active, also inactive->active edge */ - gpiod_set_value_cansleep(reset_gpio, 1); + gpiod_set_value_cansleep(gpio_poweroff->reset_gpio, 1); /* give it some time */ - mdelay(timeout); + mdelay(gpio_poweroff->timeout_ms); WARN_ON(1); } @@ -60,20 +65,29 @@ static int gpio_poweroff_probe(struct platform_device *pdev) return -EBUSY; } + gpio_poweroff = devm_kzalloc(&pdev->dev, sizeof(*gpio_poweroff), GFP_KERNEL); + if (!gpio_poweroff) + return -ENOMEM; + input = device_property_read_bool(&pdev->dev, "input"); if (input) flags = GPIOD_IN; else flags = GPIOD_OUT_LOW; - device_property_read_u32(&pdev->dev, "active-delay-ms", &active_delay); - device_property_read_u32(&pdev->dev, "inactive-delay-ms", - &inactive_delay); - device_property_read_u32(&pdev->dev, "timeout-ms", &timeout); - reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags); - if (IS_ERR(reset_gpio)) - return PTR_ERR(reset_gpio); + gpio_poweroff->active_delay_ms = 100; + gpio_poweroff->inactive_delay_ms = 100; + gpio_poweroff->timeout_ms = DEFAULT_TIMEOUT_MS; + + device_property_read_u32(&pdev->dev, "active-delay-ms", &gpio_poweroff->active_delay_ms); + device_property_read_u32(&pdev->dev, "inactive-delay-ms", + &gpio_poweroff->inactive_delay_ms); + device_property_read_u32(&pdev->dev, "timeout-ms", &gpio_poweroff->timeout_ms); + + gpio_poweroff->reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags); + if (IS_ERR(gpio_poweroff->reset_gpio)) + return PTR_ERR(gpio_poweroff->reset_gpio); pm_power_off = &gpio_poweroff_do_poweroff; return 0; From b16d9f49735f3d26e23f0ba4a2cf21668fc6b66b Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Fri, 6 Oct 2023 10:04:26 -0300 Subject: [PATCH 243/396] power: reset: gpio-poweroff: use sys-off handler API Use the new sys-off handler API for gpio-poweroff. This allows us to have more than one poweroff handler and prioritise them. Signed-off-by: Stefan Eichenberger Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20231006130428.11259-3-francesco@dolcini.it Signed-off-by: Sebastian Reichel --- drivers/power/reset/gpio-poweroff.c | 37 ++++++++++------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index dea550e422f3..0deb293eb2d6 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c @@ -15,6 +15,7 @@ #include #include #include +#include #define DEFAULT_TIMEOUT_MS 3000 @@ -25,15 +26,9 @@ struct gpio_poweroff { u32 inactive_delay_ms; }; -/* - * Hold configuration here, cannot be more than one instance of the driver - * since pm_power_off itself is global. - */ -static struct gpio_poweroff *gpio_poweroff; - -static void gpio_poweroff_do_poweroff(void) +static int gpio_poweroff_do_poweroff(struct sys_off_data *data) { - BUG_ON(!gpio_poweroff); + struct gpio_poweroff *gpio_poweroff = data->cb_data; /* drive it active, also inactive->active edge */ gpiod_direction_output(gpio_poweroff->reset_gpio, 1); @@ -50,20 +45,16 @@ static void gpio_poweroff_do_poweroff(void) mdelay(gpio_poweroff->timeout_ms); WARN_ON(1); + + return NOTIFY_DONE; } static int gpio_poweroff_probe(struct platform_device *pdev) { + struct gpio_poweroff *gpio_poweroff; bool input = false; enum gpiod_flags flags; - - /* If a pm_power_off function has already been added, leave it alone */ - if (pm_power_off != NULL) { - dev_err(&pdev->dev, - "%s: pm_power_off function already registered\n", - __func__); - return -EBUSY; - } + int ret; gpio_poweroff = devm_kzalloc(&pdev->dev, sizeof(*gpio_poweroff), GFP_KERNEL); if (!gpio_poweroff) @@ -89,14 +80,11 @@ static int gpio_poweroff_probe(struct platform_device *pdev) if (IS_ERR(gpio_poweroff->reset_gpio)) return PTR_ERR(gpio_poweroff->reset_gpio); - pm_power_off = &gpio_poweroff_do_poweroff; - return 0; -} - -static int gpio_poweroff_remove(struct platform_device *pdev) -{ - if (pm_power_off == &gpio_poweroff_do_poweroff) - pm_power_off = NULL; + ret = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, gpio_poweroff_do_poweroff, + gpio_poweroff); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Cannot register poweroff handler\n"); return 0; } @@ -109,7 +97,6 @@ MODULE_DEVICE_TABLE(of, of_gpio_poweroff_match); static struct platform_driver gpio_poweroff_driver = { .probe = gpio_poweroff_probe, - .remove = gpio_poweroff_remove, .driver = { .name = "poweroff-gpio", .of_match_table = of_gpio_poweroff_match, From 4ee17bd30788496a279ceaabc7ecaaf39f61cfc4 Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Fri, 6 Oct 2023 10:04:27 -0300 Subject: [PATCH 244/396] dt-bindings: power: reset: gpio-poweroff: Add priority property Add the priority property to the gpio-poweroff bindings description. Signed-off-by: Stefan Eichenberger Signed-off-by: Francesco Dolcini Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231006130428.11259-4-francesco@dolcini.it Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/power/reset/gpio-poweroff.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/power/reset/gpio-poweroff.yaml b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.yaml index b54ec003a1e0..a4b437fce37c 100644 --- a/Documentation/devicetree/bindings/power/reset/gpio-poweroff.yaml +++ b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.yaml @@ -18,6 +18,9 @@ description: > Finally the operating system assumes the power off failed if the system is still running after waiting some time (timeout-ms). +allOf: + - $ref: restart-handler.yaml# + properties: compatible: const: gpio-poweroff @@ -40,6 +43,9 @@ properties: default: 100 description: Delay to wait after driving gpio inactive + priority: + default: 0 + timeout-ms: default: 3000 description: Time to wait before assuming the power off sequence failed. From d03d2a8cdefe86f04cfb53934a708620e7dfbfcb Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Fri, 6 Oct 2023 10:04:28 -0300 Subject: [PATCH 245/396] power: reset: gpio-poweroff: make sys handler priority configurable Add a priority property equal to gpio-restart to allow increasing the priority of the gpio-poweroff handler. Signed-off-by: Stefan Eichenberger Signed-off-by: Francesco Dolcini Link: https://lore.kernel.org/r/20231006130428.11259-5-francesco@dolcini.it Signed-off-by: Sebastian Reichel --- drivers/power/reset/gpio-poweroff.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index 0deb293eb2d6..52cfeee2cb28 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c @@ -54,6 +54,7 @@ static int gpio_poweroff_probe(struct platform_device *pdev) struct gpio_poweroff *gpio_poweroff; bool input = false; enum gpiod_flags flags; + int priority = SYS_OFF_PRIO_DEFAULT; int ret; gpio_poweroff = devm_kzalloc(&pdev->dev, sizeof(*gpio_poweroff), GFP_KERNEL); @@ -75,14 +76,18 @@ static int gpio_poweroff_probe(struct platform_device *pdev) device_property_read_u32(&pdev->dev, "inactive-delay-ms", &gpio_poweroff->inactive_delay_ms); device_property_read_u32(&pdev->dev, "timeout-ms", &gpio_poweroff->timeout_ms); + device_property_read_u32(&pdev->dev, "priority", &priority); + if (priority > 255) { + dev_err(&pdev->dev, "Invalid priority property: %u\n", priority); + return -EINVAL; + } gpio_poweroff->reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags); if (IS_ERR(gpio_poweroff->reset_gpio)) return PTR_ERR(gpio_poweroff->reset_gpio); ret = devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_POWER_OFF, - SYS_OFF_PRIO_DEFAULT, gpio_poweroff_do_poweroff, - gpio_poweroff); + priority, gpio_poweroff_do_poweroff, gpio_poweroff); if (ret) return dev_err_probe(&pdev->dev, ret, "Cannot register poweroff handler\n"); From 3c693ac29e3fb4e1d88652e633a9dc16e1dd76e4 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Mon, 9 Oct 2023 14:58:18 +0100 Subject: [PATCH 246/396] power: reset: brcmstb: Depend on actual SoC dependencies Depend on the explicit SoC defines rather than generic architectures like most of the rest of the HW drivers do. This makes the drivers only available for the HW and for compile testing. Signed-off-by: Peter Robinson Cc: Sebastian Reichel Cc: linux-pm@vger.kernel.org Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20231009135833.17880-3-pbrobinson@gmail.com Signed-off-by: Sebastian Reichel --- drivers/power/reset/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 59e1ebb7842e..b9733fa40276 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -66,7 +66,7 @@ config POWER_RESET_BRCMKONA config POWER_RESET_BRCMSTB bool "Broadcom STB reset driver" - depends on ARM || ARM64 || MIPS || COMPILE_TEST + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST depends on MFD_SYSCON default ARCH_BRCMSTB || BMIPS_GENERIC help From b3c3a197baf23ca445ba74e3c7c40cfacfedd9fb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 9 Oct 2023 12:29:15 -0500 Subject: [PATCH 247/396] power: supply: cpcap: Drop non-DT driver matching Only DT based probing is used for the Motorola CPCAP charger driver, so drop the !CONFIG_OF parts and redundant of_match_device() call. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20231009172923.2457844-20-robh@kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/supply/cpcap-charger.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index 431e951cccf0..cebca34ff872 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -17,8 +17,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -865,7 +864,6 @@ static const struct power_supply_desc cpcap_charger_usb_desc = { .property_is_writeable = cpcap_charger_property_is_writeable, }; -#ifdef CONFIG_OF static const struct of_device_id cpcap_charger_id_table[] = { { .compatible = "motorola,mapphone-cpcap-charger", @@ -873,20 +871,13 @@ static const struct of_device_id cpcap_charger_id_table[] = { {}, }; MODULE_DEVICE_TABLE(of, cpcap_charger_id_table); -#endif static int cpcap_charger_probe(struct platform_device *pdev) { struct cpcap_charger_ddata *ddata; - const struct of_device_id *of_id; struct power_supply_config psy_cfg = {}; int error; - of_id = of_match_device(of_match_ptr(cpcap_charger_id_table), - &pdev->dev); - if (!of_id) - return -EINVAL; - ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); if (!ddata) return -ENOMEM; @@ -975,7 +966,7 @@ static struct platform_driver cpcap_charger_driver = { .probe = cpcap_charger_probe, .driver = { .name = "cpcap-charger", - .of_match_table = of_match_ptr(cpcap_charger_id_table), + .of_match_table = cpcap_charger_id_table, }, .shutdown = cpcap_charger_shutdown, .remove_new = cpcap_charger_remove, From 84aefafe6b294041b7fa0757414c4a29c1bdeea2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 30 Sep 2023 15:14:26 -0700 Subject: [PATCH 248/396] clk: linux/clk-provider.h: fix kernel-doc warnings and typos Fix spelling of "Structure". Fix multiple kernel-doc warnings: clk-provider.h:269: warning: Function parameter or member 'recalc_rate' not described in 'clk_ops' clk-provider.h:468: warning: Function parameter or member 'parent_data' not described in 'clk_hw_register_fixed_rate_with_accuracy_parent_data' clk-provider.h:468: warning: Excess function parameter 'parent_name' description in 'clk_hw_register_fixed_rate_with_accuracy_parent_data' clk-provider.h:482: warning: Function parameter or member 'parent_data' not described in 'clk_hw_register_fixed_rate_parent_accuracy' clk-provider.h:482: warning: Excess function parameter 'parent_name' description in 'clk_hw_register_fixed_rate_parent_accuracy' clk-provider.h:687: warning: Function parameter or member 'flags' not described in 'clk_divider' clk-provider.h:1164: warning: Function parameter or member 'flags' not described in 'clk_fractional_divider' clk-provider.h:1164: warning: Function parameter or member 'approximation' not described in 'clk_fractional_divider' clk-provider.h:1213: warning: Function parameter or member 'flags' not described in 'clk_multiplier' Fixes: 9fba738a53dd ("clk: add duty cycle support") Fixes: b2476490ef11 ("clk: introduce the common clock framework") Fixes: 2d34f09e79c9 ("clk: fixed-rate: Add support for specifying parents via DT/pointers") Fixes: f5290d8e4f0c ("clk: asm9260: use parent index to link the reference clock") Fixes: 9d9f78ed9af0 ("clk: basic clock hardware types") Fixes: e2d0e90fae82 ("clk: new basic clk type for fractional divider") Fixes: f2e0a53271a4 ("clk: Add a basic multiplier clock") Signed-off-by: Randy Dunlap Cc: Michael Turquette Cc: Stephen Boyd Cc: linux-clk@vger.kernel.org Link: https://lore.kernel.org/r/20230930221428.18463-1-rdunlap@infradead.org Signed-off-by: Stephen Boyd --- include/linux/clk-provider.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index ec32ec58c59f..ace3a4ce2fc9 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -74,7 +74,7 @@ void clk_hw_forward_rate_request(const struct clk_hw *core, unsigned long parent_rate); /** - * struct clk_duty - Struture encoding the duty cycle ratio of a clock + * struct clk_duty - Structure encoding the duty cycle ratio of a clock * * @num: Numerator of the duty cycle ratio * @den: Denominator of the duty cycle ratio @@ -129,7 +129,7 @@ struct clk_duty { * @restore_context: Restore the context of the clock after a restoration * of power. * - * @recalc_rate Recalculate the rate of this clock, by querying hardware. The + * @recalc_rate: Recalculate the rate of this clock, by querying hardware. The * parent rate is an input parameter. It is up to the caller to * ensure that the prepare_mutex is held across this call. If the * driver cannot figure out a rate for this clock, it must return @@ -456,7 +456,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, * clock with the clock framework * @dev: device that is registering this clock * @name: name of this clock - * @parent_name: name of clock's parent + * @parent_data: name of clock's parent * @flags: framework-specific flags * @fixed_rate: non-adjustable clock rate * @fixed_accuracy: non-adjustable clock accuracy @@ -471,7 +471,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, * the clock framework * @dev: device that is registering this clock * @name: name of this clock - * @parent_name: name of clock's parent + * @parent_data: name of clock's parent * @flags: framework-specific flags * @fixed_rate: non-adjustable clock rate */ @@ -649,7 +649,7 @@ struct clk_div_table { * Clock with an adjustable divider affecting its output frequency. Implements * .recalc_rate, .set_rate and .round_rate * - * Flags: + * @flags: * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is * the raw value read from the register, with the value of zero considered @@ -1130,11 +1130,12 @@ struct clk_hw *clk_hw_register_fixed_factor_parent_hw(struct device *dev, * @mwidth: width of the numerator bit field * @nshift: shift to the denominator bit field * @nwidth: width of the denominator bit field + * @approximation: clk driver's callback for calculating the divider clock * @lock: register lock * * Clock with adjustable fractional divider affecting its output frequency. * - * Flags: + * @flags: * CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator * is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED * is set then the numerator and denominator are both the value read @@ -1191,7 +1192,7 @@ void clk_hw_unregister_fractional_divider(struct clk_hw *hw); * Clock with an adjustable multiplier affecting its output frequency. * Implements .recalc_rate, .set_rate and .round_rate * - * Flags: + * @flags: * CLK_MULTIPLIER_ZERO_BYPASS - By default, the multiplier is the value read * from the register, with 0 being a valid value effectively * zeroing the output clock rate. If CLK_MULTIPLIER_ZERO_BYPASS is From d3b614d993781afca1832bd2cbc39da64306d0ba Mon Sep 17 00:00:00 2001 From: Edson Juliano Drosdeck Date: Mon, 16 Oct 2023 15:29:10 -0300 Subject: [PATCH 249/396] platform/x86: acer-wmi: Remove void function return MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adhere to Linux kernel coding style. Reported by checkpatch: WARNING: void function return statements are not generally useful Signed-off-by: Edson Juliano Drosdeck Link: https://lore.kernel.org/r/20231016182910.3344-1-edson.drosdeck@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/acer-wmi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 377a0becd1a1..0e472aa9bf41 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1922,7 +1922,6 @@ static void acer_rfkill_exit(void) rfkill_unregister(threeg_rfkill); rfkill_destroy(threeg_rfkill); } - return; } static void acer_wmi_notify(u32 value, void *context) @@ -2517,7 +2516,6 @@ static void __exit acer_wmi_exit(void) platform_driver_unregister(&acer_platform_driver); pr_info("Acer Laptop WMI Extras unloaded\n"); - return; } module_init(acer_wmi_init); From 61f3d868b3d6f5e23a6d25597133d76d2186eddd Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 7 Sep 2023 15:46:39 -0700 Subject: [PATCH 250/396] tools/power/x86/intel-speed-select: Sanitize integer arguments If the command takes some integer arguments, make sure the command contains only digits. Same for Hex arguments. Otherwise return error. Signed-off-by: Srinivas Pandruvada --- .../x86/intel-speed-select/isst-config.c | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 5fcc2a92957e..9992a1cbd95d 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -4,6 +4,7 @@ * Copyright (c) 2019 Intel Corporation. */ +#include #include #include @@ -2730,6 +2731,43 @@ error: exit(-1); } +static void check_optarg(char *option, int hex) +{ + if (optarg) { + char *start = optarg; + int i; + + if (hex && strlen(optarg) < 3) { + /* At least 0x plus one character must be present */ + fprintf(stderr, "malformed arguments for:%s [%s]\n", option, optarg); + exit(0); + } + + if (hex) { + if (optarg[0] != '0' || tolower(optarg[1]) != 'x') { + fprintf(stderr, "malformed arguments for:%s [%s]\n", + option, optarg); + exit(0); + } + start = &optarg[2]; + } + + for (i = 0; i < strlen(start); ++i) { + if (hex) { + if (!isxdigit(start[i])) { + fprintf(stderr, "malformed arguments for:%s [%s]\n", + option, optarg); + exit(0); + } + } else if (!isdigit(start[i])) { + fprintf(stderr, "malformed arguments for:%s [%s]\n", + option, optarg); + exit(0); + } + } + } +} + static void parse_cmd_args(int argc, int start, char **argv) { int opt; @@ -2763,18 +2801,21 @@ static void parse_cmd_args(int argc, int start, char **argv) auto_mode = 1; break; case 'b': + check_optarg("bucket", 0); fact_bucket = atoi(optarg); break; case 'h': cmd_help = 1; break; case 'l': + check_optarg("level", 0); tdp_level = atoi(optarg); break; case 'o': force_online_offline = 1; break; case 't': + check_optarg("trl", 1); sscanf(optarg, "0x%llx", &fact_trl); break; case 'r': @@ -2791,13 +2832,16 @@ static void parse_cmd_args(int argc, int start, char **argv) break; /* CLOS related */ case 'c': + check_optarg("clos", 0); current_clos = atoi(optarg); break; case 'd': + check_optarg("desired", 0); clos_desired = atoi(optarg); clos_desired /= isst_get_disp_freq_multiplier(); break; case 'e': + check_optarg("epp", 0); clos_epp = atoi(optarg); if (is_skx_based_platform()) { isst_display_error_info_message(1, "epp can't be specified on this platform", 0, 0); @@ -2805,14 +2849,17 @@ static void parse_cmd_args(int argc, int start, char **argv) } break; case 'n': + check_optarg("min", 0); clos_min = atoi(optarg); clos_min /= isst_get_disp_freq_multiplier(); break; case 'm': + check_optarg("max", 0); clos_max = atoi(optarg); clos_max /= isst_get_disp_freq_multiplier(); break; case 'p': + check_optarg("priority", 0); clos_priority_type = atoi(optarg); if (is_skx_based_platform() && !clos_priority_type) { isst_display_error_info_message(1, "Invalid clos priority type: proportional for this platform", 0, 0); @@ -2820,6 +2867,7 @@ static void parse_cmd_args(int argc, int start, char **argv) } break; case 'w': + check_optarg("weight", 0); clos_prop_prio = atoi(optarg); if (is_skx_based_platform()) { isst_display_error_info_message(1, "weight can't be specified on this platform", 0, 0); From 3076db34b5ba87bb7a3335d16415befdea056d57 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 7 Sep 2023 17:01:55 -0700 Subject: [PATCH 251/396] tools/power/x86/intel-speed-select: Update help for TRL TRL (turbo ratio limit) argument is passed in hex string. Clarify that in the help. Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-config.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 9992a1cbd95d..9306436bb5b0 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -2126,7 +2126,7 @@ static void set_fact_enable(int arg) fprintf(stderr, "Enable Intel Speed Select Technology Turbo frequency feature\n"); fprintf(stderr, - "Optional: -t|--trl : Specify turbo ratio limit\n"); + "Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n"); fprintf(stderr, "\tOptional Arguments: -a|--auto : Designate specified target CPUs with"); fprintf(stderr, @@ -2135,7 +2135,7 @@ static void set_fact_enable(int arg) fprintf(stderr, "Disable Intel Speed Select Technology turbo frequency feature\n"); fprintf(stderr, - "Optional: -t|--trl : Specify turbo ratio limit\n"); + "Optional: -t|--trl : Specify turbo ratio limit in hex starting with 0x\n"); fprintf(stderr, "\tOptional Arguments: -a|--auto : Also disable core-power associations\n"); } @@ -2597,7 +2597,7 @@ static void process_trl(int arg) if (cmd_help) { if (arg) { fprintf(stderr, "Set TRL (turbo ratio limits)\n"); - fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL\n"); + fprintf(stderr, "\t t|--trl: Specify turbo ratio limit for setting TRL in hex starting with 0x\n"); } else { fprintf(stderr, "Get TRL (turbo ratio limits)\n"); } From 7b00d1018c8c8ed55aa1393b2ca234400eb6ca86 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 7 Sep 2023 17:09:52 -0700 Subject: [PATCH 252/396] tools/power/x86/intel-speed-select: turbo-mode enable disable swapped The command for turbo-mode enable and disable is swapped. Fix that. Previously turbo-mode enable was actually disabling and disable was enabling. Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-config.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 9306436bb5b0..72be2d4db21c 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -2527,22 +2527,22 @@ static void set_turbo_mode_for_cpu(struct isst_id *id, int status) } if (status) { - isst_display_result(id, outf, "turbo-mode", "enable", 0); - } else { isst_display_result(id, outf, "turbo-mode", "disable", 0); + } else { + isst_display_result(id, outf, "turbo-mode", "enable", 0); } } static void set_turbo_mode(int arg) { - int i, enable = arg; + int i, disable = arg; struct isst_id id; if (cmd_help) { - if (enable) - fprintf(stderr, "Set turbo mode enable\n"); - else + if (disable) fprintf(stderr, "Set turbo mode disable\n"); + else + fprintf(stderr, "Set turbo mode enable\n"); exit(0); } @@ -2560,7 +2560,7 @@ static void set_turbo_mode(int arg) if (online) { set_isst_id(&id, i); - set_turbo_mode_for_cpu(&id, enable); + set_turbo_mode_for_cpu(&id, disable); } } From 2fe8d2d7911fb4e380c3dcb5655e1a62bb14f75e Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 7 Sep 2023 17:12:55 -0700 Subject: [PATCH 253/396] tools/power/x86/intel-speed-select: No TRL for non compute domains Don't call to set or get TRL for domains in which there are no CPUs. Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-config.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 72be2d4db21c..1afaaa833a54 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -2574,6 +2574,9 @@ static void get_set_trl(struct isst_id *id, void *arg1, void *arg2, void *arg3, int set = *(int *)arg4; int ret; + if (id->cpu < 0) + return; + if (set && !fact_trl) { isst_display_error_info_message(1, "Invalid TRL. Specify with [-t|--trl]", 0, 0); exit(0); From da4c1b9e8f22d0567e308428e588e1f9e004ce74 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 7 Sep 2023 17:07:19 -0700 Subject: [PATCH 254/396] tools/power/x86/intel-speed-select: Display error for core-power support When core-power is getting enabled, if the feaure is not supported, display error. Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-config.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 1afaaa833a54..b7bd14618128 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -2242,6 +2242,14 @@ static void enable_clos_qos_config(struct isst_id *id, void *arg1, void *arg2, v { int ret; int status = *(int *)arg4; + int cp_state, cp_cap; + + if (!isst_read_pm_config(id, &cp_state, &cp_cap)) { + if (!cp_cap) { + isst_display_error_info_message(1, "core-power not supported", 0, 0); + return; + } + } if (is_skx_based_platform()) clos_priority_type = 1; From bc5370cca03ba9d1634fecd85e0cf99a0a3c0483 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 13 Oct 2023 11:20:56 -0700 Subject: [PATCH 255/396] tools/power/x86/intel-speed-select: Increase max CPUs in one request With the increase in the CPU count, this count needs to be updated. Increase max CPU count to 512. Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index b7bd14618128..44e1302dd8f9 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -28,7 +28,7 @@ static FILE *outf; static int cpu_model; static int cpu_stepping; -#define MAX_CPUS_IN_ONE_REQ 256 +#define MAX_CPUS_IN_ONE_REQ 512 static short max_target_cpus; static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ]; From 3bc0f20a8c59daa79aee2da119564f668f458afd Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 3 Oct 2023 14:46:30 -0700 Subject: [PATCH 256/396] tools/power/x86/intel-speed-select: Use cgroup isolate for CPU 0 From kernel version 6.5, CPU 0 hotplug capability is deprecated. If some SST profile doesn't have CPU 0, then it is no longer possible to offline CPU 0. This means that user space threads will still run on CPU 0. To workaround this issue, use cgroup v2 isolation feature. Whenever there /sys/devices/system/cpu/cpu0/online file is absent or open fails, isolate CPU 0 via CPU cgroup v2 isolation. Also add a command line option to force even if the /sys/devices/system/cpu/cpu0/online is present. The previous commit "01bcb56f059e ("tools/power/x86/intel-speed-select: Prevent CPU 0 offline") was just warning about this issue based on the kernel version 6.5 and above. With this new approach, instead of warning take action to mitigate the issue. Signed-off-by: Srinivas Pandruvada --- .../x86/intel-speed-select/isst-config.c | 130 +++++++++++++----- .../x86/intel-speed-select/isst-daemon.c | 3 +- tools/power/x86/intel-speed-select/isst.h | 3 +- 3 files changed, 97 insertions(+), 39 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 44e1302dd8f9..b51c21ae2c83 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -6,7 +6,6 @@ #include #include -#include #include "isst.h" @@ -56,6 +55,8 @@ static int clos_min = -1; static int clos_max = -1; static int clos_desired = -1; static int clos_priority_type; +static int cpu_0_cgroupv2; +static int cpu_0_workaround(int isolate); struct _cpu_map { unsigned short core_id; @@ -475,42 +476,15 @@ static unsigned int is_cpu_online(int cpu) return online; } -static int get_kernel_version(int *major, int *minor) -{ - struct utsname buf; - int ret; - - ret = uname(&buf); - if (ret) - return ret; - - ret = sscanf(buf.release, "%d.%d", major, minor); - if (ret != 2) - return ret; - - return 0; -} - -#define CPU0_HOTPLUG_DEPRECATE_MAJOR_VER 6 -#define CPU0_HOTPLUG_DEPRECATE_MINOR_VER 5 - void set_cpu_online_offline(int cpu, int state) { char buffer[128]; int fd, ret; - if (!cpu) { - int major, minor; - - ret = get_kernel_version(&major, &minor); - if (!ret) { - if (major > CPU0_HOTPLUG_DEPRECATE_MAJOR_VER || (major == CPU0_HOTPLUG_DEPRECATE_MAJOR_VER && - minor >= CPU0_HOTPLUG_DEPRECATE_MINOR_VER)) { - debug_printf("Ignore CPU 0 offline/online for kernel version >= %d.%d\n", major, minor); - debug_printf("Use cgroups to isolate CPU 0\n"); - return; - } - } + if (cpu_0_cgroupv2 && !cpu) { + fprintf(stderr, "Will use cgroup v2 for CPU 0\n"); + cpu_0_workaround(!state); + return; } snprintf(buffer, sizeof(buffer), @@ -518,9 +492,10 @@ void set_cpu_online_offline(int cpu, int state) fd = open(buffer, O_WRONLY); if (fd < 0) { - if (!cpu && state) { + if (!cpu) { fprintf(stderr, "This system is not configured for CPU 0 online/offline\n"); - fprintf(stderr, "Ignoring online request for CPU 0 as this is already online\n"); + fprintf(stderr, "Will use cgroup v2\n"); + cpu_0_workaround(!state); return; } err(-1, "%s open failed", buffer); @@ -907,7 +882,7 @@ int enable_cpuset_controller(void) return 0; } -int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level) +int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level, int cpu_0_only) { int i, first, curr_index, index, ret, fd; static char str[512], dir_name[64]; @@ -950,6 +925,12 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev curr_index = 0; first = 1; str[0] = '\0'; + + if (cpu_0_only) { + snprintf(str, str_len, "0"); + goto create_partition; + } + for (i = 0; i < get_topo_max_cpus(); ++i) { if (!is_cpu_in_power_domain(i, id)) continue; @@ -972,6 +953,7 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev first = 0; } +create_partition: debug_printf("isolated CPUs list: package:%d curr_index:%d [%s]\n", id->pkg, curr_index ,str); snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus", dir_name); @@ -1012,6 +994,74 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev return 0; } +static int cpu_0_workaround(int isolate) +{ + int fd, fd1, len, ret; + cpu_set_t cpu_mask; + struct isst_id id; + char str[2]; + + debug_printf("isolate CPU 0 state: %d\n", isolate); + + if (isolate) + goto isolate; + + /* First check if CPU 0 was isolated to remove isolation. */ + + /* If the cpuset.cpus doesn't exist, that means that none of the CPUs are isolated*/ + fd = open("/sys/fs/cgroup/0-0-0/cpuset.cpus", O_RDONLY, 0); + if (fd < 0) + return 0; + + len = read(fd, str, sizeof(str)); + /* Error check, but unlikely to fail. If fails that means that not isolated */ + if (len == -1) + return 0; + + + /* Is CPU 0 is in isolate list, the display is sorted so first element will be CPU 0*/ + if (str[0] != '0') { + close(fd); + return 0; + } + + fd1 = open("/sys/fs/cgroup/0-0-0/cpuset.cpus.partition", O_RDONLY, 0); + /* Unlikely that, this attribute is not present, but handle error */ + if (fd1 < 0) { + close(fd); + return 0; + } + + /* Is CPU 0 already changed partition to "member" */ + len = read(fd1, str, sizeof(str)); + if (len != -1 && str[0] == 'm') { + close(fd1); + close(fd); + return 0; + } + + close(fd1); + close(fd); + + debug_printf("CPU 0 was isolated before, so remove isolation\n"); + +isolate: + ret = enable_cpuset_controller(); + if (ret) + goto isolate_fail; + + CPU_ZERO(&cpu_mask); + memset(&id, 0, sizeof(struct isst_id)); + CPU_SET(0, &cpu_mask); + + ret = isolate_cpus(&id, sizeof(cpu_mask), &cpu_mask, isolate, 1); +isolate_fail: + if (ret) + fprintf(stderr, "Can't isolate CPU 0\n"); + + return ret; +} + static int isst_fill_platform_info(void) { const char *pathname = "/dev/isst_interface"; @@ -1458,7 +1508,8 @@ display_result: if (ret) goto use_offline; - ret = isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, tdp_level); + ret = isolate_cpus(id, ctdp_level.core_cpumask_size, + ctdp_level.core_cpumask, tdp_level, 0); if (ret) goto use_offline; @@ -3054,6 +3105,7 @@ static void usage(void) printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n"); printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n"); printf("\t[-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline.\n"); + printf("\t[-u|--cpu0-workaround : Don't try to online/offline CPU0 instead use cgroup v2.\n"); printf("\nResult format\n"); printf("\tResult display uses a common format for each command:\n"); printf("\tResults are formatted in text/JSON with\n"); @@ -3107,6 +3159,7 @@ static void cmdline(int argc, char **argv) { "no-daemon", no_argument, 0, 'n' }, { "poll-interval", required_argument, 0, 'w' }, { "cgroupv2", required_argument, 0, 'g' }, + { "cpu0-workaround", required_argument, 0, 'u' }, { 0, 0, 0, 0 } }; @@ -3137,7 +3190,7 @@ static void cmdline(int argc, char **argv) goto out; progname = argv[0]; - while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ng", long_options, + while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ngu", long_options, &option_index)) != -1) { switch (opt) { case 'a': @@ -3199,6 +3252,9 @@ static void cmdline(int argc, char **argv) case 'g': cgroupv2 = 1; break; + case 'u': + cpu_0_cgroupv2 = 1; + break; default: usage(); } diff --git a/tools/power/x86/intel-speed-select/isst-daemon.c b/tools/power/x86/intel-speed-select/isst-daemon.c index 12053fa43542..66df21b2b573 100644 --- a/tools/power/x86/intel-speed-select/isst-daemon.c +++ b/tools/power/x86/intel-speed-select/isst-daemon.c @@ -90,7 +90,8 @@ void process_level_change(struct isst_id *id) if (ret) goto use_offline; - isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, pkg_dev.current_level); + isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, + pkg_dev.current_level, 0); goto free_mask; } diff --git a/tools/power/x86/intel-speed-select/isst.h b/tools/power/x86/intel-speed-select/isst.h index 8def22dec4a2..4bddd3c66bf7 100644 --- a/tools/power/x86/intel-speed-select/isst.h +++ b/tools/power/x86/intel-speed-select/isst.h @@ -318,7 +318,8 @@ extern struct isst_platform_ops *tpmi_get_platform_ops(void); /* Cgroup related interface */ extern int enable_cpuset_controller(void); -extern int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level); +extern int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, + int level, int cpu_0_only); extern int use_cgroupv2(void); #endif From a590ed62269a049a72484ce617fe2f34e2da66cf Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 13 Oct 2023 11:15:41 -0700 Subject: [PATCH 257/396] tools/power/x86/intel-speed-select: v1.18 release This version addresses issues with: - When CPU 0 hotplug is not possible, try cgroup v2 isolation without any user input - Fix turbo mode enable/disable swapped - Sanitize command line integer and hex arguments - Add more error messages - Increase CPU count in one request Signed-off-by: Srinivas Pandruvada --- tools/power/x86/intel-speed-select/isst-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index b51c21ae2c83..d865dc1f89ee 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -16,7 +16,7 @@ struct process_cmd_struct { int arg; }; -static const char *version_str = "v1.17"; +static const char *version_str = "v1.18"; static const int supported_api_ver = 2; static struct isst_if_platform_info isst_platform_info; From 619102313466eaf8a6ac188e711f5df749dac6d4 Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Sun, 27 Aug 2023 04:39:32 +0200 Subject: [PATCH 258/396] clk: ralink: mtmips: quiet unused variable warning When CONFIG_OF is disabled then the matching table is not referenced and the following warning appears: drivers/clk/ralink/clk-mtmips.c:821:34: warning: unused variable 'mtmips_of_match' [-Wunused-const-variable] 821 | static const struct of_device_id mtmips_of_match[] = { | ^ There are two match tables in the driver: one for the clock driver and the other for the reset driver. The only difference between them is that the clock driver uses 'data' and does not have 'ralink,rt2880-reset' compatible. Both just can be merged into a single one just by adding the compatible 'ralink,rt2880-reset' entry to 'mtmips_of_match[]', which will allow it to be used for 'mtmips_clk_driver' (which doesn't use the data) as well as for 'mtmips_clk_init()' (which doesn't need get called for 'ralink,rt2880-reset'). Doing in this way ensures that 'CONFIG_OF' is not disabled anymore so the above warning disapears. Fixes: 6f3b15586eef ("clk: ralink: add clock and reset driver for MTMIPS SoCs") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202307242310.CdOnd2py-lkp@intel.com/ Suggested-by: Arnd Bergmann Signed-off-by: Sergio Paracuellos Link: https://lore.kernel.org/r/20230827023932.501102-1-sergio.paracuellos@gmail.com Reviewed-by: Nathan Chancellor Signed-off-by: Stephen Boyd --- drivers/clk/ralink/clk-mtmips.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/clk/ralink/clk-mtmips.c b/drivers/clk/ralink/clk-mtmips.c index 1e7991439527..50a443bf79ec 100644 --- a/drivers/clk/ralink/clk-mtmips.c +++ b/drivers/clk/ralink/clk-mtmips.c @@ -821,6 +821,10 @@ static const struct mtmips_clk_data mt76x8_clk_data = { }; static const struct of_device_id mtmips_of_match[] = { + { + .compatible = "ralink,rt2880-reset", + .data = NULL, + }, { .compatible = "ralink,rt2880-sysc", .data = &rt2880_clk_data, @@ -1088,25 +1092,11 @@ static int mtmips_clk_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id mtmips_clk_of_match[] = { - { .compatible = "ralink,rt2880-reset" }, - { .compatible = "ralink,rt2880-sysc" }, - { .compatible = "ralink,rt3050-sysc" }, - { .compatible = "ralink,rt3052-sysc" }, - { .compatible = "ralink,rt3352-sysc" }, - { .compatible = "ralink,rt3883-sysc" }, - { .compatible = "ralink,rt5350-sysc" }, - { .compatible = "ralink,mt7620-sysc" }, - { .compatible = "ralink,mt7628-sysc" }, - { .compatible = "ralink,mt7688-sysc" }, - {} -}; - static struct platform_driver mtmips_clk_driver = { .probe = mtmips_clk_probe, .driver = { .name = "mtmips-clk", - .of_match_table = mtmips_clk_of_match, + .of_match_table = mtmips_of_match, }, }; From a5d14f8b551eb1551c10053653ee8e27f19672fa Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Oct 2023 17:01:57 +0300 Subject: [PATCH 259/396] clk: keystone: pll: fix a couple NULL vs IS_ERR() checks The clk_register_divider() and clk_register_mux() functions returns error pointers on error but this code checks for NULL. Fix that. Fixes: b9e0d40c0d83 ("clk: keystone: add Keystone PLL clock driver") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/d9da4c97-0da9-499f-9a21-1f8e3f148dc1@moroto.mountain Signed-off-by: Stephen Boyd --- drivers/clk/keystone/pll.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c index ee5c72369334..6bbdd4705d71 100644 --- a/drivers/clk/keystone/pll.c +++ b/drivers/clk/keystone/pll.c @@ -281,12 +281,13 @@ static void __init of_pll_div_clk_init(struct device_node *node) clk = clk_register_divider(NULL, clk_name, parent_name, 0, reg, shift, mask, 0, NULL); - if (clk) { - of_clk_add_provider(node, of_clk_src_simple_get, clk); - } else { + if (IS_ERR(clk)) { pr_err("%s: error registering divider %s\n", __func__, clk_name); iounmap(reg); + return; } + + of_clk_add_provider(node, of_clk_src_simple_get, clk); } CLK_OF_DECLARE(pll_divider_clock, "ti,keystone,pll-divider-clock", of_pll_div_clk_init); @@ -328,10 +329,12 @@ static void __init of_pll_mux_clk_init(struct device_node *node) clk = clk_register_mux(NULL, clk_name, (const char **)&parents, ARRAY_SIZE(parents) , 0, reg, shift, mask, 0, NULL); - if (clk) - of_clk_add_provider(node, of_clk_src_simple_get, clk); - else + if (IS_ERR(clk)) { pr_err("%s: error registering mux %s\n", __func__, clk_name); + return; + } + + of_clk_add_provider(node, of_clk_src_simple_get, clk); } CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init); From 7af5b9eadd64c9e02a71f97c45bcdf3b64841f6b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 2 Oct 2023 10:04:36 +0300 Subject: [PATCH 260/396] clk: ti: fix double free in of_ti_divider_clk_setup() The "div" pointer is freed in _register_divider() and again in of_ti_divider_clk_setup(). Delete the free in _register_divider() Fixes: fbbc18591585 ("clk: ti: divider: cleanup _register_divider and ti_clk_get_div_table") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/6d36eeec-6c8a-4f11-a579-aa3cd7c38749@moroto.mountain Reviewed-by: Tony Lindgren Signed-off-by: Stephen Boyd --- drivers/clk/ti/divider.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 768a1f3398b4..5d5bb123ba94 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -309,7 +309,6 @@ static struct clk *_register_divider(struct device_node *node, u32 flags, struct clk_omap_divider *div) { - struct clk *clk; struct clk_init_data init; const char *parent_name; const char *name; @@ -326,12 +325,7 @@ static struct clk *_register_divider(struct device_node *node, div->hw.init = &init; /* register the clock */ - clk = of_ti_clk_register(node, &div->hw, name); - - if (IS_ERR(clk)) - kfree(div); - - return clk; + return of_ti_clk_register(node, &div->hw, name); } int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div, From 43a354a21a6a21f050b95317148661a465108cba Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 17 Oct 2023 17:06:53 +0300 Subject: [PATCH 261/396] clk: at91: remove unnecessary conditions This code checks "if (parent_hw)" is non-NULL, but then it has more checks if parent_hw is non-NULL on the lines inside the if statement. It is a bit confusing. For the else statement, keep in mind that at the start of the function we checked: if (!(parent_name || parent_hw)) return ERR_PTR(-EINVAL); That check ensures that if parent_hw is NULL that means that parent_name is non-NULL. At least one must always be non-NULL. So here again, the checks inside the if statement can be removed. In the original code, it was a bit confusing and you could easily get the impression that "init.num_parents" could be zero. When we remove the unnecessary checking it's more obvious that it's always set to 1. Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/7782b4f1-deed-49dc-8207-b6ea06d7602f@moroto.mountain Reviewed-by: Claudiu Beznea Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-utmi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index 40c84f5af5e8..b991180beea1 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -161,13 +161,11 @@ at91_clk_register_utmi_internal(struct regmap *regmap_pmc, init.name = name; init.ops = ops; - if (parent_hw) { - init.parent_hws = parent_hw ? (const struct clk_hw **)&parent_hw : NULL; - init.num_parents = parent_hw ? 1 : 0; - } else { - init.parent_names = parent_name ? &parent_name : NULL; - init.num_parents = parent_name ? 1 : 0; - } + if (parent_hw) + init.parent_hws = (const struct clk_hw **)&parent_hw; + else + init.parent_names = &parent_name; + init.num_parents = 1; init.flags = flags; utmi->hw.init = &init; From bbc5080bef4a245106aa8e8d424ba8847ca7c0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Sat, 23 Sep 2023 15:31:27 +0200 Subject: [PATCH 262/396] clk: npcm7xx: Fix incorrect kfree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The corresponding allocation is: > npcm7xx_clk_data = kzalloc(struct_size(npcm7xx_clk_data, hws, > NPCM7XX_NUM_CLOCKS), GFP_KERNEL); ... so, kfree should be applied to npcm7xx_clk_data, not npcm7xx_clk_data->hws. Fixes: fcfd14369856 ("clk: npcm7xx: add clock controller") Signed-off-by: Jonathan Neuschäfer Link: https://lore.kernel.org/r/20230923133127.1815621-1-j.neuschaefer@gmx.net Signed-off-by: Stephen Boyd --- drivers/clk/clk-npcm7xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-npcm7xx.c b/drivers/clk/clk-npcm7xx.c index e319cfa51a8a..030186def9c6 100644 --- a/drivers/clk/clk-npcm7xx.c +++ b/drivers/clk/clk-npcm7xx.c @@ -510,7 +510,7 @@ static void __init npcm7xx_clk_init(struct device_node *clk_np) return; npcm7xx_init_fail: - kfree(npcm7xx_clk_data->hws); + kfree(npcm7xx_clk_data); npcm7xx_init_np_err: iounmap(clk_base); npcm7xx_init_error: From b82681042724924ae3ba0f2f2eeec217fa31e830 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Tue, 12 Sep 2023 17:34:03 +0800 Subject: [PATCH 263/396] clk: mediatek: clk-mt6765: Add check for mtk_alloc_clk_data Add the check for the return value of mtk_alloc_clk_data() in order to avoid NULL pointer dereference. Fixes: 1aca9939bf72 ("clk: mediatek: Add MT6765 clock support") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20230912093407.21505-1-jiasheng@iscas.ac.cn Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt6765.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c index 1f4c8d0c041a..9c7f7407d798 100644 --- a/drivers/clk/mediatek/clk-mt6765.c +++ b/drivers/clk/mediatek/clk-mt6765.c @@ -737,6 +737,8 @@ static int clk_mt6765_apmixed_probe(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); @@ -769,6 +771,8 @@ static int clk_mt6765_top_probe(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks), clk_data); @@ -807,6 +811,8 @@ static int clk_mt6765_ifr_probe(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_gates(&pdev->dev, node, ifr_clks, ARRAY_SIZE(ifr_clks), clk_data); From 1f57f78fbacf630430bf954e5a84caafdfea30c0 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Tue, 12 Sep 2023 17:34:04 +0800 Subject: [PATCH 264/396] clk: mediatek: clk-mt6779: Add check for mtk_alloc_clk_data Add the check for the return value of mtk_alloc_clk_data() in order to avoid NULL pointer dereference. Fixes: 710774e04861 ("clk: mediatek: Add MT6779 clock support") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20230912093407.21505-2-jiasheng@iscas.ac.cn Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt6779.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/mediatek/clk-mt6779.c b/drivers/clk/mediatek/clk-mt6779.c index 3ee2f5a2319a..ffedb1fe3c67 100644 --- a/drivers/clk/mediatek/clk-mt6779.c +++ b/drivers/clk/mediatek/clk-mt6779.c @@ -1217,6 +1217,8 @@ static int clk_mt6779_apmixed_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); @@ -1237,6 +1239,8 @@ static int clk_mt6779_top_probe(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), clk_data); From 606f6366a35a3329545e38129804d65ef26ed7d2 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Tue, 12 Sep 2023 17:34:05 +0800 Subject: [PATCH 265/396] clk: mediatek: clk-mt6797: Add check for mtk_alloc_clk_data Add the check for the return value of mtk_alloc_clk_data() in order to avoid NULL pointer dereference. Fixes: 96596aa06628 ("clk: mediatek: add clk support for MT6797") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20230912093407.21505-3-jiasheng@iscas.ac.cn Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt6797.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/mediatek/clk-mt6797.c b/drivers/clk/mediatek/clk-mt6797.c index 2ebd25f0ce71..f12d4e9ff0bb 100644 --- a/drivers/clk/mediatek/clk-mt6797.c +++ b/drivers/clk/mediatek/clk-mt6797.c @@ -390,6 +390,8 @@ static int mtk_topckgen_init(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_TOP_NR); + if (!clk_data) + return -ENOMEM; mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs), clk_data); @@ -545,6 +547,8 @@ static void mtk_infrasys_init_early(struct device_node *node) if (!infra_clk_data) { infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); + if (!infra_clk_data) + return; for (i = 0; i < CLK_INFRA_NR; i++) infra_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); @@ -570,6 +574,8 @@ static int mtk_infrasys_init(struct platform_device *pdev) if (!infra_clk_data) { infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); + if (!infra_clk_data) + return -ENOMEM; } else { for (i = 0; i < CLK_INFRA_NR; i++) { if (infra_clk_data->hws[i] == ERR_PTR(-EPROBE_DEFER)) From 0884393c63cc9a1772f7121a6645ba7bd76feeb9 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Tue, 12 Sep 2023 17:34:06 +0800 Subject: [PATCH 266/396] clk: mediatek: clk-mt7629-eth: Add check for mtk_alloc_clk_data Add the check for the return value of mtk_alloc_clk_data() in order to avoid NULL pointer dereference. Fixes: 3b5e748615e7 ("clk: mediatek: add clock support for MT7629 SoC") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20230912093407.21505-4-jiasheng@iscas.ac.cn Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt7629-eth.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/mediatek/clk-mt7629-eth.c b/drivers/clk/mediatek/clk-mt7629-eth.c index fe714debdc9e..1bfedc988cfe 100644 --- a/drivers/clk/mediatek/clk-mt7629-eth.c +++ b/drivers/clk/mediatek/clk-mt7629-eth.c @@ -77,6 +77,8 @@ static int clk_mt7629_ethsys_init(struct platform_device *pdev) int r; clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_gates(&pdev->dev, node, eth_clks, CLK_ETH_NR_CLK, clk_data); @@ -100,6 +102,8 @@ static int clk_mt7629_sgmiisys_init(struct platform_device *pdev) int r; clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_gates(&pdev->dev, node, sgmii_clks[id++], CLK_SGMII_NR_CLK, clk_data); From 2befa515c1bb6cdd33c262b909d93d1973a219aa Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Tue, 12 Sep 2023 17:34:07 +0800 Subject: [PATCH 267/396] clk: mediatek: clk-mt7629: Add check for mtk_alloc_clk_data Add the check for the return value of mtk_alloc_clk_data() in order to avoid NULL pointer dereference. Fixes: 3b5e748615e7 ("clk: mediatek: add clock support for MT7629 SoC") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20230912093407.21505-5-jiasheng@iscas.ac.cn Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt7629.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c index 2882107d0f24..b8a1f01bc974 100644 --- a/drivers/clk/mediatek/clk-mt7629.c +++ b/drivers/clk/mediatek/clk-mt7629.c @@ -555,6 +555,8 @@ static int mtk_topckgen_init(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), clk_data); @@ -579,6 +581,8 @@ static int mtk_infrasys_init(struct platform_device *pdev) struct clk_hw_onecell_data *clk_data; clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_gates(&pdev->dev, node, infra_clks, ARRAY_SIZE(infra_clks), clk_data); @@ -602,6 +606,8 @@ static int mtk_pericfg_init(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK); + if (!clk_data) + return -ENOMEM; mtk_clk_register_gates(&pdev->dev, node, peri_clks, ARRAY_SIZE(peri_clks), clk_data); From 0d6e24b422a2166a9297a8286ff2e6ab9a5e8cd3 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Fri, 1 Sep 2023 10:46:58 +0800 Subject: [PATCH 268/396] clk: mediatek: clk-mt2701: Add check for mtk_alloc_clk_data Add the check for the return value of mtk_alloc_clk_data() in order to avoid NULL pointer dereference. Fixes: e9862118272a ("clk: mediatek: Add MT2701 clock support") Signed-off-by: Jiasheng Jiang Link: https://lore.kernel.org/r/20230901024658.23405-1-jiasheng@iscas.ac.cn Reviewed-by: Markus Schneider-Pargmann Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt2701.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index c81f3e33ce56..12d9560eb4ba 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -667,6 +667,8 @@ static int mtk_topckgen_init(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_TOP_NR); + if (!clk_data) + return -ENOMEM; mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), clk_data); @@ -747,6 +749,8 @@ static void __init mtk_infrasys_init_early(struct device_node *node) if (!infra_clk_data) { infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); + if (!infra_clk_data) + return; for (i = 0; i < CLK_INFRA_NR; i++) infra_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER); @@ -774,6 +778,8 @@ static int mtk_infrasys_init(struct platform_device *pdev) if (!infra_clk_data) { infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR); + if (!infra_clk_data) + return -ENOMEM; } else { for (i = 0; i < CLK_INFRA_NR; i++) { if (infra_clk_data->hws[i] == ERR_PTR(-EPROBE_DEFER)) @@ -890,6 +896,8 @@ static int mtk_pericfg_init(struct platform_device *pdev) return PTR_ERR(base); clk_data = mtk_alloc_clk_data(CLK_PERI_NR); + if (!clk_data) + return -ENOMEM; mtk_clk_register_gates(&pdev->dev, node, peri_clks, ARRAY_SIZE(peri_clks), clk_data); From 4eb15b036367006ec7f0b9880993ceb6ae259ec8 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sat, 16 Sep 2023 12:05:14 +0200 Subject: [PATCH 269/396] clk: twl: add clock driver for TWL6032 The TWL6032 has some clock outputs which are controlled like fixed-voltage regulators, in some drivers for these chips found in the wild, just the regulator api is abused for controlling them, so simply use something similar to the regulator functions. Due to a lack of hardware available for testing, leave out the TWL6030-specific part of those functions. Signed-off-by: Andreas Kemnade Link: https://lore.kernel.org/r/20230916100515.1650336-5-andreas@kemnade.info Signed-off-by: Stephen Boyd --- drivers/clk/Kconfig | 9 ++ drivers/clk/Makefile | 1 + drivers/clk/clk-twl.c | 197 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+) create mode 100644 drivers/clk/clk-twl.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c30099866174..3944f081ebad 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -277,6 +277,15 @@ config COMMON_CLK_S2MPS11 clock. These multi-function devices have two (S2MPS14) or three (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each. +config CLK_TWL + tristate "Clock driver for the TWL PMIC family" + depends on TWL4030_CORE + help + Enable support for controlling the clock resources on TWL family + PMICs. These devices have some 32K clock outputs which can be + controlled by software. For now, only the TWL6032 clocks are + supported. + config CLK_TWL6040 tristate "External McPDM functional clock from twl6040" depends on TWL6040_CORE diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 18969cbd4bb1..86e46adcb619 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o +obj-$(CONFIG_CLK_TWL) += clk-twl.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_RS9_PCIE) += clk-renesas-pcie.o obj-$(CONFIG_COMMON_CLK_SI521XX) += clk-si521xx.o diff --git a/drivers/clk/clk-twl.c b/drivers/clk/clk-twl.c new file mode 100644 index 000000000000..eab9d3c8ed8a --- /dev/null +++ b/drivers/clk/clk-twl.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock driver for twl device. + * + * inspired by the driver for the Palmas device + */ + +#include +#include +#include +#include +#include + +#define VREG_STATE 2 +#define TWL6030_CFG_STATE_OFF 0x00 +#define TWL6030_CFG_STATE_ON 0x01 +#define TWL6030_CFG_STATE_MASK 0x03 + +struct twl_clock_info { + struct device *dev; + u8 base; + struct clk_hw hw; +}; + +static inline int +twlclk_read(struct twl_clock_info *info, unsigned int slave_subgp, + unsigned int offset) +{ + u8 value; + int status; + + status = twl_i2c_read_u8(slave_subgp, &value, + info->base + offset); + return (status < 0) ? status : value; +} + +static inline int +twlclk_write(struct twl_clock_info *info, unsigned int slave_subgp, + unsigned int offset, u8 value) +{ + return twl_i2c_write_u8(slave_subgp, value, + info->base + offset); +} + +static inline struct twl_clock_info *to_twl_clks_info(struct clk_hw *hw) +{ + return container_of(hw, struct twl_clock_info, hw); +} + +static unsigned long twl_clks_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 32768; +} + +static int twl6032_clks_prepare(struct clk_hw *hw) +{ + struct twl_clock_info *cinfo = to_twl_clks_info(hw); + int ret; + + ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE, + TWL6030_CFG_STATE_ON); + if (ret < 0) + dev_err(cinfo->dev, "clk prepare failed\n"); + + return ret; +} + +static void twl6032_clks_unprepare(struct clk_hw *hw) +{ + struct twl_clock_info *cinfo = to_twl_clks_info(hw); + int ret; + + ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE, + TWL6030_CFG_STATE_OFF); + if (ret < 0) + dev_err(cinfo->dev, "clk unprepare failed\n"); +} + +static int twl6032_clks_is_prepared(struct clk_hw *hw) +{ + struct twl_clock_info *cinfo = to_twl_clks_info(hw); + int val; + + val = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE); + if (val < 0) { + dev_err(cinfo->dev, "clk read failed\n"); + return val; + } + + val &= TWL6030_CFG_STATE_MASK; + + return val == TWL6030_CFG_STATE_ON; +} + +static const struct clk_ops twl6032_clks_ops = { + .prepare = twl6032_clks_prepare, + .unprepare = twl6032_clks_unprepare, + .is_prepared = twl6032_clks_is_prepared, + .recalc_rate = twl_clks_recalc_rate, +}; + +struct twl_clks_data { + struct clk_init_data init; + u8 base; +}; + +static const struct twl_clks_data twl6032_clks[] = { + { + .init = { + .name = "clk32kg", + .ops = &twl6032_clks_ops, + .flags = CLK_IGNORE_UNUSED, + }, + .base = 0x8C, + }, + { + .init = { + .name = "clk32kaudio", + .ops = &twl6032_clks_ops, + .flags = CLK_IGNORE_UNUSED, + }, + .base = 0x8F, + }, + { + /* sentinel */ + } +}; + +static int twl_clks_probe(struct platform_device *pdev) +{ + struct clk_hw_onecell_data *clk_data; + const struct twl_clks_data *hw_data; + + struct twl_clock_info *cinfo; + int ret; + int i; + int count; + + hw_data = twl6032_clks; + for (count = 0; hw_data[count].init.name; count++) + ; + + clk_data = devm_kzalloc(&pdev->dev, + struct_size(clk_data, hws, count), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = count; + cinfo = devm_kcalloc(&pdev->dev, count, sizeof(*cinfo), GFP_KERNEL); + if (!cinfo) + return -ENOMEM; + + for (i = 0; i < count; i++) { + cinfo[i].base = hw_data[i].base; + cinfo[i].dev = &pdev->dev; + cinfo[i].hw.init = &hw_data[i].init; + ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw); + if (ret) { + return dev_err_probe(&pdev->dev, ret, + "Fail to register clock %s\n", + hw_data[i].init.name); + } + clk_data->hws[i] = &cinfo[i].hw; + } + + ret = devm_of_clk_add_hw_provider(&pdev->dev, + of_clk_hw_onecell_get, clk_data); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Fail to add clock driver\n"); + + return 0; +} + +static const struct platform_device_id twl_clks_id[] = { + { + .name = "twl6032-clk", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, twl_clks_id); + +static struct platform_driver twl_clks_driver = { + .driver = { + .name = "twl-clk", + }, + .probe = twl_clks_probe, + .id_table = twl_clks_id, +}; + +module_platform_driver(twl_clks_driver); + +MODULE_DESCRIPTION("Clock driver for TWL Series Devices"); +MODULE_LICENSE("GPL"); From b0009b8bed98bd5d59449af48781703df261c247 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 20 Oct 2023 18:14:47 +0000 Subject: [PATCH 270/396] power: supply: bq24190_charger: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect bdi->model_name to be NUL-terminated based on its usage with sysfs_emit and format strings: val->strval is assigned to bdi->model_name in bq24190_charger_get_property(): 1186 | val->strval = bdi->model_name; ... then in power_supply_sysfs.c we use value.strval with a format string: 311 | ret = sysfs_emit(buf, "%s\n", value.strval); we assigned value.strval via: 285 | ret = power_supply_get_property(psy, psp, &value); ... which invokes psy->desc->get_property(): 1210 | return psy->desc->get_property(psy, psp, val); with bq24190_charger_get_property(): 1320 | static const struct power_supply_desc bq24190_charger_desc = { ... 1325 | .get_property = bq24190_charger_get_property, Moreover, no NUL-padding is required as bdi is zero-allocated in bq24190_charger.c: 1798 | bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL); Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231020-strncpy-drivers-power-supply-bq24190_charger-c-v1-1-e896223cb795@google.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 3f99cb9590ba..1db290ee2591 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -1803,7 +1803,7 @@ static int bq24190_probe(struct i2c_client *client) bdi->client = client; bdi->dev = dev; - strncpy(bdi->model_name, id->name, I2C_NAME_SIZE); + strscpy(bdi->model_name, id->name, sizeof(bdi->model_name)); mutex_init(&bdi->f_reg_lock); bdi->charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST; bdi->f_reg = 0; From e3c2af5d49bb96ad460ef6aa873975fb0f7c7f17 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 20 Oct 2023 18:59:34 +0000 Subject: [PATCH 271/396] power: supply: bq2515x: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect bq2515x->model_name to be NUL-terminated based on its usage with sysfs_emit and format strings: val->strval is assigned to bq2515x->model_name in bq2515x_mains_get_property(): | val->strval = bq2515x->model_name; ... then in power_supply_sysfs.c we use value.strval with a format string: | ret = sysfs_emit(buf, "%s\n", value.strval); we assigned value.strval via: | ret = power_supply_get_property(psy, psp, &value); ... which invokes psy->desc->get_property(): | return psy->desc->get_property(psy, psp, val); with bq2515x_mains_get_property(): | static const struct power_supply_desc bq2515x_mains_desc = { ... | .get_property = bq2515x_mains_get_property, Moreover, no NUL-padding is required as bq2515x is zero-allocated in bq2515x_charger.c: | bq2515x = devm_kzalloc(dev, sizeof(*bq2515x), GFP_KERNEL); Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also opt to use the more idiomatic strscpy() usage of (dest, src, sizeof(dest)) as this more closely ties the destination buffer and the length. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Similar-to: https://lore.kernel.org/all/20231020-strncpy-drivers-power-supply-bq24190_charger-c-v1-1-e896223cb795@google.com/ Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231020-strncpy-drivers-power-supply-bq2515x_charger-c-v1-1-46664c6edf78@google.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq2515x_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/bq2515x_charger.c b/drivers/power/supply/bq2515x_charger.c index 49fa6386a509..a3424f67f2b1 100644 --- a/drivers/power/supply/bq2515x_charger.c +++ b/drivers/power/supply/bq2515x_charger.c @@ -1089,7 +1089,7 @@ static int bq2515x_probe(struct i2c_client *client) bq2515x->dev = dev; - strncpy(bq2515x->model_name, id->name, I2C_NAME_SIZE); + strscpy(bq2515x->model_name, id->name, sizeof(bq2515x->model_name)); bq2515x->info = i2c_get_match_data(client); bq2515x->regmap = devm_regmap_init_i2c(client, From 056a75599f5e676d497bbf9b29157877f542e56b Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 20 Oct 2023 19:05:25 +0000 Subject: [PATCH 272/396] power: supply: bq256xx: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect bq->model_name to be NUL-terminated based on its usage with sysfs_emit and format strings: val->strval is assigned to bq->model_name in bq256xx_get_charger_property(): | val->strval = bq->model_name; ... then in power_supply_sysfs.c we use value.strval with a format string: | ret = sysfs_emit(buf, "%s\n", value.strval); we assigned value.strval via: | ret = power_supply_get_property(psy, psp, &value); ... which invokes psy->desc->get_property(): | return psy->desc->get_property(psy, psp, val); with bq256xx_get_charger_property(): | static const struct power_supply_desc bq256xx_power_supply_desc = { ... | .get_property = bq256xx_get_charger_property, Moreover, no NUL-padding is required as bq is zero-allocated in bq256xx_charger.c: | bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also opt to use the more idiomatic strscpy() usage of (dest, src, sizeof(dest)) as this more closely ties the destination buffer and the length. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Similar-to: https://lore.kernel.org/all/20231020-strncpy-drivers-power-supply-bq24190_charger-c-v1-1-e896223cb795@google.com/ Similar-to: https://lore.kernel.org/all/20231020-strncpy-drivers-power-supply-bq2515x_charger-c-v1-1-46664c6edf78@google.com/ Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231020-strncpy-drivers-power-supply-bq256xx_charger-c-v1-1-2fad856124f9@google.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq256xx_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/bq256xx_charger.c b/drivers/power/supply/bq256xx_charger.c index 474201815a27..789a31bd70c3 100644 --- a/drivers/power/supply/bq256xx_charger.c +++ b/drivers/power/supply/bq256xx_charger.c @@ -1706,7 +1706,7 @@ static int bq256xx_probe(struct i2c_client *client) mutex_init(&bq->lock); - strncpy(bq->model_name, id->name, I2C_NAME_SIZE); + strscpy(bq->model_name, id->name, sizeof(bq->model_name)); bq->regmap = devm_regmap_init_i2c(client, bq->chip_info->bq256xx_regmap_config); From afb0379b0f6657b9f626d23c3bb00b4e8823bd2d Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 20 Oct 2023 19:11:07 +0000 Subject: [PATCH 273/396] power: supply: bq25980: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect bq->model_name to be NUL-terminated based on its usage with sysfs_emit and format strings: val->strval is assigned to bq->model_name in bq25980_get_charger_property(): | val->strval = bq->model_name; ... then in power_supply_sysfs.c we use value.strval with a format string: | ret = sysfs_emit(buf, "%s\n", value.strval); we assigned value.strval via: | ret = power_supply_get_property(psy, psp, &value); ... which invokes psy->desc->get_property(): | return psy->desc->get_property(psy, psp, val); with bq25980_get_charger_property(): | static const struct power_supply_desc bq25980_power_supply_desc = { ... | .get_property = bq25980_get_charger_property, Moreover, no NUL-padding is required as bq is zero-allocated in bq25980_charger.c: | bq = devm_kzalloc(dev, sizeof(*bq), GFP_KERNEL); Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also opt to use the more idiomatic strscpy() usage of (dest, src, sizeof(dest)) as this more closely ties the destination buffer and the length. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Similar-to: https://lore.kernel.org/all/20231020-strncpy-drivers-power-supply-bq24190_charger-c-v1-1-e896223cb795@google.com/ Similar-to: https://lore.kernel.org/all/20231020-strncpy-drivers-power-supply-bq2515x_charger-c-v1-1-46664c6edf78@google.com/ Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231020-strncpy-drivers-power-supply-bq25980_charger-c-v1-1-7b93be54537b@google.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq25980_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/bq25980_charger.c b/drivers/power/supply/bq25980_charger.c index d8411722266f..0c5e2938bb36 100644 --- a/drivers/power/supply/bq25980_charger.c +++ b/drivers/power/supply/bq25980_charger.c @@ -1223,7 +1223,7 @@ static int bq25980_probe(struct i2c_client *client) mutex_init(&bq->lock); - strncpy(bq->model_name, id->name, I2C_NAME_SIZE); + strscpy(bq->model_name, id->name, sizeof(bq->model_name)); bq->chip_info = &bq25980_chip_info_tbl[id->driver_data]; bq->regmap = devm_regmap_init_i2c(client, From e1402bd297a3477c16eca4c1e4094372237f40a7 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 20 Oct 2023 19:21:46 +0000 Subject: [PATCH 274/396] power: supply: charger-manager: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect cm->psy_name_buf to be NUL-terminated based on its usage with format strings: 1522: cm->charger_psy_desc.name = cm->psy_name_buf; ... 1587: dev_err(&pdev->dev, "Cannot register charger-manager with name \"%s\"\n", 1587: cm->charger_psy_desc.name); Moreover, NUL-padding is not required as `cm` is already zero-allocated and thus any future NUL-byte assignments (like what strncpy() will do) are redundant: 1437: cm = devm_kzalloc(&pdev->dev, sizeof(*cm), GFP_KERNEL); Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also opt for the more idiomatic strscpy() usage of: strscpy(dest, src, sizeof(dest)). Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231020-strncpy-drivers-power-supply-charger-manager-c-v1-1-698f73bcad2a@google.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/charger-manager.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/charger-manager.c b/drivers/power/supply/charger-manager.c index 3936ff066600..96f0a7fbf105 100644 --- a/drivers/power/supply/charger-manager.c +++ b/drivers/power/supply/charger-manager.c @@ -1516,9 +1516,11 @@ static int charger_manager_probe(struct platform_device *pdev) memcpy(&cm->charger_psy_desc, &psy_default, sizeof(psy_default)); if (!desc->psy_name) - strncpy(cm->psy_name_buf, psy_default.name, PSY_NAME_MAX); + strscpy(cm->psy_name_buf, psy_default.name, + sizeof(cm->psy_name_buf)); else - strncpy(cm->psy_name_buf, desc->psy_name, PSY_NAME_MAX); + strscpy(cm->psy_name_buf, desc->psy_name, + sizeof(cm->psy_name_buf)); cm->charger_psy_desc.name = cm->psy_name_buf; /* Allocate for psy properties because they may vary */ From 81f07d2b0c4db3b6e53d90419db915c75beb6326 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 20 Oct 2023 19:39:02 +0000 Subject: [PATCH 275/396] power: supply: surface_battery: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect bat->name to be NUL-terminated based on its usage with strcmp(): power_supply_core.c: 445: return strcmp(psy->desc->name, name) == 0; ... and also by the manual `... - 1` for the length argument of the original strncpy() invocation. Furthermore, no NUL-padding is needed as bat is zero-allocated before calling spwr_battery_init(): 826: bat = devm_kzalloc(&sdev->dev, sizeof(*bat), GFP_KERNEL); 827: if (!bat) 828: return -ENOMEM; 829: 830: spwr_battery_init(bat, sdev, p->registry, p->name); ... this means any further NUL-byte assignments (like the ones that strncpy() does) are redundant. Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also opt to use the more idiomatic strscpy() usage of: (dest, src, sizeof(dest)). Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231020-strncpy-drivers-power-supply-surface_battery-c-v2-1-29ed16b2caf1@google.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/surface_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c index 19d2f8834e56..196d290dc596 100644 --- a/drivers/power/supply/surface_battery.c +++ b/drivers/power/supply/surface_battery.c @@ -722,7 +722,7 @@ static void spwr_battery_init(struct spwr_battery_device *bat, struct ssam_devic struct ssam_event_registry registry, const char *name) { mutex_init(&bat->lock); - strncpy(bat->name, name, ARRAY_SIZE(bat->name) - 1); + strscpy(bat->name, name, sizeof(bat->name)); bat->sdev = sdev; From afc88dfda013970bb1e214b331e99adca2f98312 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 20 Oct 2023 19:46:11 +0000 Subject: [PATCH 276/396] power: supply: surface-charger: replace deprecated strncpy with strscpy strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous string interfaces. We expect ac->name to be NUL-terminated based on its usage with format strings: surface_charger.c: 190: ac->psy_desc.name = ac->name; ... power_supply_core.c: 174: dev_dbg(&psy->dev, "%s: Found supply : %s\n", 175: psy->desc->name, epsy->desc->name); Moreover, NUL-padding is not required as ac is already zero-allocated before being passed to spwr_ac_init(): surface_charger.c: 240: ac = devm_kzalloc(&sdev->dev, sizeof(*ac), GFP_KERNEL); 241: if (!ac) 242: return -ENOMEM; 243: 244: spwr_ac_init(ac, sdev, p->registry, p->name); ... this means any future NUL-byte assignments (like the ones that strncpy() does) are redundant. Considering the above, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without unnecessarily NUL-padding. Let's also opt for the more idiomatic strscpy() usage of: (dest, src, sizeof(dest)) Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Link: https://lore.kernel.org/r/20231020-strncpy-drivers-power-supply-surface_charger-c-v1-1-93ddbf668e10@google.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/surface_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c index cabdd8da12d0..7a6c62d6f883 100644 --- a/drivers/power/supply/surface_charger.c +++ b/drivers/power/supply/surface_charger.c @@ -175,7 +175,7 @@ static void spwr_ac_init(struct spwr_ac_device *ac, struct ssam_device *sdev, struct ssam_event_registry registry, const char *name) { mutex_init(&ac->lock); - strncpy(ac->name, name, ARRAY_SIZE(ac->name) - 1); + strscpy(ac->name, name, sizeof(ac->name)); ac->sdev = sdev; From 469d31745b9fb3a87424b311abb7cb530611404f Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 9 Oct 2023 12:29:14 -0500 Subject: [PATCH 277/396] power: reset: vexpress: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Acked-by: Sudeep Holla Link: https://lore.kernel.org/r/20231009172923.2457844-19-robh@kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/reset/vexpress-poweroff.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c index 17064d7b19f6..bb22b2db5907 100644 --- a/drivers/power/reset/vexpress-poweroff.c +++ b/drivers/power/reset/vexpress-poweroff.c @@ -7,8 +7,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -108,20 +108,17 @@ static int _vexpress_register_restart_handler(struct device *dev) static int vexpress_reset_probe(struct platform_device *pdev) { - const struct of_device_id *match = - of_match_device(vexpress_reset_of_match, &pdev->dev); + enum vexpress_reset_func func; struct regmap *regmap; int ret = 0; - if (!match) - return -EINVAL; - regmap = devm_regmap_init_vexpress_config(&pdev->dev); if (IS_ERR(regmap)) return PTR_ERR(regmap); dev_set_drvdata(&pdev->dev, regmap); - switch ((uintptr_t)match->data) { + func = (uintptr_t)device_get_match_data(&pdev->dev); + switch (func) { case FUNC_SHUTDOWN: vexpress_power_off_device = &pdev->dev; pm_power_off = vexpress_power_off; From abaf59c470a7c9c59bda8da3517ec2ff0513f5a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 11 Sep 2023 17:15:48 +0200 Subject: [PATCH 278/396] clk: qcom: cbf-msm8996: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). qcom_msm8996_cbf_icc_remove() returned zero unconditionally. After changing this function to return void instead, the driver can be converted trivially to use .remove_new(). Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230911151548.672485-1-u.kleine-koenig@pengutronix.de Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-cbf-8996.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/clk/qcom/clk-cbf-8996.c b/drivers/clk/qcom/clk-cbf-8996.c index 53f205a3f183..fe24b4abeab4 100644 --- a/drivers/clk/qcom/clk-cbf-8996.c +++ b/drivers/clk/qcom/clk-cbf-8996.c @@ -250,13 +250,11 @@ static int qcom_msm8996_cbf_icc_register(struct platform_device *pdev, struct cl return 0; } -static int qcom_msm8996_cbf_icc_remove(struct platform_device *pdev) +static void qcom_msm8996_cbf_icc_remove(struct platform_device *pdev) { struct icc_provider *provider = platform_get_drvdata(pdev); icc_clk_unregister(provider); - - return 0; } #define qcom_msm8996_cbf_icc_sync_state icc_sync_state #else @@ -266,7 +264,7 @@ static int qcom_msm8996_cbf_icc_register(struct platform_device *pdev, struct c return 0; } -#define qcom_msm8996_cbf_icc_remove(pdev) (0) +#define qcom_msm8996_cbf_icc_remove(pdev) { } #define qcom_msm8996_cbf_icc_sync_state NULL #endif @@ -340,9 +338,9 @@ static int qcom_msm8996_cbf_probe(struct platform_device *pdev) return qcom_msm8996_cbf_icc_register(pdev, &cbf_mux.clkr.hw); } -static int qcom_msm8996_cbf_remove(struct platform_device *pdev) +static void qcom_msm8996_cbf_remove(struct platform_device *pdev) { - return qcom_msm8996_cbf_icc_remove(pdev); + qcom_msm8996_cbf_icc_remove(pdev); } static const struct of_device_id qcom_msm8996_cbf_match_table[] = { @@ -354,7 +352,7 @@ MODULE_DEVICE_TABLE(of, qcom_msm8996_cbf_match_table); static struct platform_driver qcom_msm8996_cbf_driver = { .probe = qcom_msm8996_cbf_probe, - .remove = qcom_msm8996_cbf_remove, + .remove_new = qcom_msm8996_cbf_remove, .driver = { .name = "qcom-msm8996-cbf", .of_match_table = qcom_msm8996_cbf_match_table, From 76ca22bd3d95cfb5113206894abbc80de6ceb1fe Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 25 Aug 2023 17:38:32 +0200 Subject: [PATCH 279/396] clk: qcom: smd-rpm: Move CPUSS_GNoC clock to interconnect As it turns out, it's yet another interconnect bus clock. Move it there. See [1] for reference. [1] https://android.googlesource.com/kernel/msm-extra/devicetree/+/02f8c342b23c20a5cf967df649814be37a08227c%5E%21/#F0 Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230726-topic-icc_coeff-v4-10-c04b60caa467@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-smd-rpm.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 0191fc0dd7da..8602c02047d0 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -574,6 +574,16 @@ static const struct clk_smd_rpm *sm_qnoc_icc_clks[] = { &clk_smd_rpm_bus_2_snoc_clk, }; +static const struct clk_smd_rpm *qcm2290_icc_clks[] = { + &clk_smd_rpm_bimc_clk, + &clk_smd_rpm_bus_1_cnoc_clk, + &clk_smd_rpm_mmnrt_clk, + &clk_smd_rpm_mmrt_clk, + &clk_smd_rpm_qup_clk, + &clk_smd_rpm_bus_2_snoc_clk, + &clk_smd_rpm_cpuss_gnoc_clk, +}; + static struct clk_smd_rpm *msm8909_clks[] = { [RPM_SMD_QPIC_CLK] = &clk_smd_rpm_qpic_clk, [RPM_SMD_QPIC_CLK_A] = &clk_smd_rpm_qpic_a_clk, @@ -1189,15 +1199,13 @@ static struct clk_smd_rpm *qcm2290_clks[] = { [RPM_SMD_PKA_A_CLK] = &clk_smd_rpm_pka_a_clk, [RPM_SMD_BIMC_GPU_CLK] = &clk_smd_rpm_bimc_gpu_clk, [RPM_SMD_BIMC_GPU_A_CLK] = &clk_smd_rpm_bimc_gpu_a_clk, - [RPM_SMD_CPUSS_GNOC_CLK] = &clk_smd_rpm_cpuss_gnoc_clk, - [RPM_SMD_CPUSS_GNOC_A_CLK] = &clk_smd_rpm_cpuss_gnoc_a_clk, }; static const struct rpm_smd_clk_desc rpm_clk_qcm2290 = { .clks = qcm2290_clks, .num_clks = ARRAY_SIZE(qcm2290_clks), - .icc_clks = sm_qnoc_icc_clks, - .num_icc_clks = ARRAY_SIZE(sm_qnoc_icc_clks) + .icc_clks = qcm2290_icc_clks, + .num_icc_clks = ARRAY_SIZE(qcm2290_icc_clks) }; static const struct of_device_id rpm_smd_clk_match_table[] = { From bff482ace43eebc5b4394cc9a7c7723f08413f80 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 10 Oct 2023 15:57:10 -0500 Subject: [PATCH 280/396] clk: qcom: Replace of_device.h with explicit includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other and pull in various other headers. In preparation to fix this, adjust the includes for what is actually needed. of_device.h isn't needed, but mod_devicetable.h and platform_device.h were implicitly included by it. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20231010205710.1585232-1-robh@kernel.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/camcc-sm8550.c | 3 ++- drivers/clk/qcom/gcc-ipq5018.c | 3 ++- drivers/clk/qcom/gcc-sm4450.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/clk/qcom/camcc-sm8550.c b/drivers/clk/qcom/camcc-sm8550.c index 2133e768b891..dd51ba4ea757 100644 --- a/drivers/clk/qcom/camcc-sm8550.c +++ b/drivers/clk/qcom/camcc-sm8550.c @@ -4,8 +4,9 @@ */ #include +#include #include -#include +#include #include #include diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c index 19dc2b71cacf..70f6ade3ac2a 100644 --- a/drivers/clk/qcom/gcc-ipq5018.c +++ b/drivers/clk/qcom/gcc-ipq5018.c @@ -3,8 +3,9 @@ * Copyright (c) 2023, The Linux Foundation. All rights reserved. */ #include +#include #include -#include +#include #include #include diff --git a/drivers/clk/qcom/gcc-sm4450.c b/drivers/clk/qcom/gcc-sm4450.c index 41c6357d09bc..31abe2775fc8 100644 --- a/drivers/clk/qcom/gcc-sm4450.c +++ b/drivers/clk/qcom/gcc-sm4450.c @@ -4,8 +4,9 @@ */ #include +#include #include -#include +#include #include #include From 21134ec8af94981b3127a691df2d73540ba4d8aa Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 16 Oct 2023 11:43:55 +0300 Subject: [PATCH 281/396] clk: qcom: gpucc-sm8550: switch to clk_lucid_ole_pll_configure Instead of manually specifying the RINGOSC_CAL_L and CAL_L values in the alpha_pll_config.l field, use the proper clk_lucid_ole_pll_configure() function to configure the PLL. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231016084356.1301854-1-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gpucc-sm8550.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/clk/qcom/gpucc-sm8550.c b/drivers/clk/qcom/gpucc-sm8550.c index 775e0b931923..420dcb27b47d 100644 --- a/drivers/clk/qcom/gpucc-sm8550.c +++ b/drivers/clk/qcom/gpucc-sm8550.c @@ -39,8 +39,7 @@ static const struct pll_vco lucid_ole_vco[] = { }; static const struct alpha_pll_config gpu_cc_pll0_config = { - /* .l includes RINGOSC_CAL_L_VAL, CAL_L_VAL, L_VAL fields */ - .l = 0x4444000d, + .l = 0x0d, .alpha = 0x0, .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00182261, @@ -71,8 +70,7 @@ static struct clk_alpha_pll gpu_cc_pll0 = { }; static const struct alpha_pll_config gpu_cc_pll1_config = { - /* .l includes RINGOSC_CAL_L_VAL, CAL_L_VAL, L_VAL fields */ - .l = 0x44440016, + .l = 0x16, .alpha = 0xeaaa, .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00182261, @@ -574,8 +572,8 @@ static int gpu_cc_sm8550_probe(struct platform_device *pdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); - clk_lucid_evo_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); - clk_lucid_evo_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + clk_lucid_ole_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_lucid_ole_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); /* * Keep clocks always enabled: From a2620539ae2529916a98585c6d7311c48fb67e9f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 16 Oct 2023 11:43:56 +0300 Subject: [PATCH 282/396] clk: qcom: videocc-sm8550: switch to clk_lucid_ole_pll_configure Instead of manually specifying the RINGOSC_CAL_L and CAL_L values in the alpha_pll_config.l field, use the proper clk_lucid_ole_pll_configure() function to configure the PLL. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231016084356.1301854-2-dmitry.baryshkov@linaro.org Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/videocc-sm8550.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/clk/qcom/videocc-sm8550.c b/drivers/clk/qcom/videocc-sm8550.c index 3bb136ec31b1..f3c9dfaee968 100644 --- a/drivers/clk/qcom/videocc-sm8550.c +++ b/drivers/clk/qcom/videocc-sm8550.c @@ -36,8 +36,7 @@ static const struct pll_vco lucid_ole_vco[] = { }; static const struct alpha_pll_config video_cc_pll0_config = { - /* .l includes RINGOSC_CAL_L_VAL, CAL_L_VAL, L_VAL fields */ - .l = 0x44440025, + .l = 0x25, .alpha = 0x8000, .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00182261, @@ -68,8 +67,7 @@ static struct clk_alpha_pll video_cc_pll0 = { }; static const struct alpha_pll_config video_cc_pll1_config = { - /* .l includes RINGOSC_CAL_L_VAL, CAL_L_VAL, L_VAL fields */ - .l = 0x44440036, + .l = 0x36, .alpha = 0xb000, .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00182261, @@ -427,8 +425,8 @@ static int video_cc_sm8550_probe(struct platform_device *pdev) return PTR_ERR(regmap); } - clk_lucid_evo_pll_configure(&video_cc_pll0, regmap, &video_cc_pll0_config); - clk_lucid_evo_pll_configure(&video_cc_pll1, regmap, &video_cc_pll1_config); + clk_lucid_ole_pll_configure(&video_cc_pll0, regmap, &video_cc_pll0_config); + clk_lucid_ole_pll_configure(&video_cc_pll1, regmap, &video_cc_pll1_config); /* * Keep clocks always enabled: From 6a15647d0adc686226045e8046369f34d6ab03ed Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 20 Oct 2023 11:49:31 +0530 Subject: [PATCH 283/396] clk: qcom: config IPQ_APSS_6018 should depend on QCOM_SMEM The config IPQ_APSS_6018 should depend on QCOM_SMEM, to avoid the following error reported by 'kernel test robot' loongarch64-linux-ld: drivers/clk/qcom/apss-ipq6018.o: in function `apss_ipq6018_probe': >> apss-ipq6018.c:(.text+0xd0): undefined reference to `qcom_smem_get_soc_id' Fixes: 5e77b4ef1b19 ("clk: qcom: Add ipq6018 apss clock controller") Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202310181650.g8THtfsm-lkp@intel.com/ Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/f4c4d65a7cb71e807d6d472c63c7718408c8f5f0.1697781921.git.quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 3194c8beb06d..ad1acd9b7426 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -131,6 +131,7 @@ config IPQ_APSS_6018 tristate "IPQ APSS Clock Controller" select IPQ_APSS_PLL depends on QCOM_APCS_IPC || COMPILE_TEST + depends on QCOM_SMEM help Support for APSS clock controller on IPQ platforms. The APSS clock controller manages the Mux and enable block that feeds the From 84da48921a97cee3dd1391659e93ee01d122b78b Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 20 Oct 2023 11:49:32 +0530 Subject: [PATCH 284/396] clk: qcom: clk-alpha-pll: introduce stromer plus ops Stromer plus APSS PLL does not support dynamic frequency scaling. To switch between frequencies, we have to shut down the PLL, configure the L and ALPHA values and turn on again. So introduce the separate set of ops for Stromer Plus PLL. Reviewed-by: Dmitry Baryshkov Signed-off-by: Kathiravan T Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/2affa6c63ff0c4342230623a7d4eef02ec7c02d4.1697781921.git.quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/clk-alpha-pll.c | 63 ++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-alpha-pll.h | 1 + 2 files changed, 64 insertions(+) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 4edbf77f3360..05898d2a8b22 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -2508,3 +2508,66 @@ const struct clk_ops clk_alpha_pll_stromer_ops = { .set_rate = clk_alpha_pll_stromer_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_ops); + +static int clk_alpha_pll_stromer_plus_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long prate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, alpha_width = pll_alpha_width(pll); + int ret, pll_mode; + u64 a; + + rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width); + + ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &pll_mode); + if (ret) + return ret; + + regmap_write(pll->clkr.regmap, PLL_MODE(pll), 0); + + /* Delay of 2 output clock ticks required until output is disabled */ + udelay(1); + + regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + + if (alpha_width > ALPHA_BITWIDTH) + a <<= alpha_width - ALPHA_BITWIDTH; + + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), + a >> ALPHA_BITWIDTH); + + regmap_write(pll->clkr.regmap, PLL_MODE(pll), PLL_BYPASSNL); + + /* Wait five micro seconds or more */ + udelay(5); + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, + PLL_RESET_N); + + /* The lock time should be less than 50 micro seconds worst case */ + usleep_range(50, 60); + + ret = wait_for_pll_enable_lock(pll); + if (ret) { + pr_err("Wait for PLL enable lock failed [%s] %d\n", + clk_hw_get_name(hw), ret); + return ret; + } + + if (pll_mode & PLL_OUTCTRL) + regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL, + PLL_OUTCTRL); + + return 0; +} + +const struct clk_ops clk_alpha_pll_stromer_plus_ops = { + .prepare = clk_alpha_pll_enable, + .unprepare = clk_alpha_pll_disable, + .is_enabled = clk_alpha_pll_is_enabled, + .recalc_rate = clk_alpha_pll_recalc_rate, + .determine_rate = clk_alpha_pll_stromer_determine_rate, + .set_rate = clk_alpha_pll_stromer_plus_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_plus_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index 3b24a660daac..a1a75bb12fe8 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -152,6 +152,7 @@ extern const struct clk_ops clk_alpha_pll_postdiv_ops; extern const struct clk_ops clk_alpha_pll_huayra_ops; extern const struct clk_ops clk_alpha_pll_postdiv_ro_ops; extern const struct clk_ops clk_alpha_pll_stromer_ops; +extern const struct clk_ops clk_alpha_pll_stromer_plus_ops; extern const struct clk_ops clk_alpha_pll_fabia_ops; extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops; From 267e29198436a8cb6770213471f72502c895096a Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 20 Oct 2023 11:49:33 +0530 Subject: [PATCH 285/396] clk: qcom: apss-ipq-pll: Use stromer plus ops for stromer plus pll The set rate and determine rate operations are different between Stromer and Stromer Plus PLLs. Since the programming sequence is different, the PLLs dont get configured properly and random, inexplicable crash/freeze is seen. Hence, use stromer plus ops for ipq_pll_stromer_plus. Reviewed-by: Dmitry Baryshkov Acked-by: Stephen Boyd Fixes: c7ef7fbb1ccf ("clk: qcom: apss-ipq-pll: add support for IPQ5332") Signed-off-by: Kathiravan T Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/c86ecaa23dc4f39650bcf4a3bd54a617a932e4fd.1697781921.git.quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/apss-ipq-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c index e170331858cc..18c4ffe153d6 100644 --- a/drivers/clk/qcom/apss-ipq-pll.c +++ b/drivers/clk/qcom/apss-ipq-pll.c @@ -68,7 +68,7 @@ static struct clk_alpha_pll ipq_pll_stromer_plus = { .fw_name = "xo", }, .num_parents = 1, - .ops = &clk_alpha_pll_stromer_ops, + .ops = &clk_alpha_pll_stromer_plus_ops, }, }, }; From 5b7a4d3d2b33398330aef69e0ff5656273483587 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 20 Oct 2023 11:49:34 +0530 Subject: [PATCH 286/396] clk: qcom: apss-ipq-pll: Fix 'l' value for ipq5332_pll_config The earlier 'l' value of 0x3e is for 1.5GHz. Not all SKUs support this frequency. Hence set it to 0x2d to get 1.1GHz which is supported in all SKUs. The frequency can still increase above this initial configuration made here when the cpufreq driver picks a different OPP. Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Fixes: c7ef7fbb1ccf ("clk: qcom: apss-ipq-pll: add support for IPQ5332") Signed-off-by: Kathiravan T Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/00e6be6cb9cee56628123a64ade118d0a752018b.1697781921.git.quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/apss-ipq-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c index 18c4ffe153d6..41279e5437a6 100644 --- a/drivers/clk/qcom/apss-ipq-pll.c +++ b/drivers/clk/qcom/apss-ipq-pll.c @@ -74,7 +74,7 @@ static struct clk_alpha_pll ipq_pll_stromer_plus = { }; static const struct alpha_pll_config ipq5332_pll_config = { - .l = 0x3e, + .l = 0x2d, .config_ctl_val = 0x4001075b, .config_ctl_hi_val = 0x304, .main_output_mask = BIT(0), From 00331227f42045314b3775957f2f7809fb3ac32f Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Fri, 20 Oct 2023 11:49:35 +0530 Subject: [PATCH 287/396] clk: qcom: apss-ipq6018: ipq5332: add safe source switch for a53pll Stromer Plus PLL found on IPQ53xx doesn't support dynamic frequency scaling. To achieve the same, we need to park the APPS PLL source to GPLL0, re configure the PLL and then switch the source to APSS_PLL_EARLY. To support this, register a clock notifier to get the PRE_RATE and POST_RATE notification. Change the APSS PLL source to GPLL0 when PRE_RATE notification is received, then configure the PLL and then change back the source to APSS_PLL_EARLY. Additionally, not all SKUs of IPQ53xx support scaling. Hence, do the above to the SKUs that support scaling. Reviewed-by: Dmitry Baryshkov Signed-off-by: Kathiravan T Signed-off-by: Varadarajan Narayanan Link: https://lore.kernel.org/r/49422d258d67d33a2547fbb7f4f6e72d489c2301.1697781921.git.quic_varada@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/apss-ipq6018.c | 58 ++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/apss-ipq6018.c b/drivers/clk/qcom/apss-ipq6018.c index f2f502e2d5a4..0783d1aa8efa 100644 --- a/drivers/clk/qcom/apss-ipq6018.c +++ b/drivers/clk/qcom/apss-ipq6018.c @@ -9,8 +9,11 @@ #include #include #include +#include +#include #include +#include #include "common.h" #include "clk-regmap.h" @@ -81,15 +84,68 @@ static const struct qcom_cc_desc apss_ipq6018_desc = { .num_clks = ARRAY_SIZE(apss_ipq6018_clks), }; +static int cpu_clk_notifier_fn(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct clk_hw *hw; + u8 index; + int err; + + if (action == PRE_RATE_CHANGE) + index = P_GPLL0; + else if (action == POST_RATE_CHANGE || action == ABORT_RATE_CHANGE) + index = P_APSS_PLL_EARLY; + else + return NOTIFY_OK; + + hw = &apcs_alias0_clk_src.clkr.hw; + err = clk_rcg2_mux_closest_ops.set_parent(hw, index); + + return notifier_from_errno(err); +} + static int apss_ipq6018_probe(struct platform_device *pdev) { + struct clk_hw *hw = &apcs_alias0_clk_src.clkr.hw; + struct notifier_block *cpu_clk_notifier; struct regmap *regmap; + u32 soc_id; + int ret; + + ret = qcom_smem_get_soc_id(&soc_id); + if (ret) + return ret; regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!regmap) return -ENODEV; - return qcom_cc_really_probe(pdev, &apss_ipq6018_desc, regmap); + ret = qcom_cc_really_probe(pdev, &apss_ipq6018_desc, regmap); + if (ret) + return ret; + + switch (soc_id) { + /* Only below variants of IPQ53xx support scaling */ + case QCOM_ID_IPQ5332: + case QCOM_ID_IPQ5322: + case QCOM_ID_IPQ5300: + cpu_clk_notifier = devm_kzalloc(&pdev->dev, + sizeof(*cpu_clk_notifier), + GFP_KERNEL); + if (!cpu_clk_notifier) + return -ENOMEM; + + cpu_clk_notifier->notifier_call = cpu_clk_notifier_fn; + + ret = devm_clk_notifier_register(&pdev->dev, hw->clk, cpu_clk_notifier); + if (ret) + return ret; + break; + default: + break; + } + + return 0; } static struct platform_driver apss_ipq6018_driver = { From 3dcf7b59393812a5fbd83f8cd8d34b94afb4c4d1 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Sat, 21 Oct 2023 13:55:18 +0200 Subject: [PATCH 288/396] clk: qcom: gcc-ipq6018: add QUP6 I2C clock QUP6 I2C clock is listed in the dt bindings but it was never included in the GCC driver. So lets add support for it, it is marked as criticial as it is used by RPM to communicate to the external PMIC over I2C so this clock must not be disabled. Signed-off-by: Robert Marko Reviewed-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20231021115545.229060-1-robimarko@gmail.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-ipq6018.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/clk/qcom/gcc-ipq6018.c b/drivers/clk/qcom/gcc-ipq6018.c index 6120fbbc5de0..bff878268fa6 100644 --- a/drivers/clk/qcom/gcc-ipq6018.c +++ b/drivers/clk/qcom/gcc-ipq6018.c @@ -2125,6 +2125,26 @@ static struct clk_branch gcc_blsp1_qup5_spi_apps_clk = { }, }; +static struct clk_branch gcc_blsp1_qup6_i2c_apps_clk = { + .halt_reg = 0x07010, + .clkr = { + .enable_reg = 0x07010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup6_i2c_apps_clk", + .parent_hws = (const struct clk_hw *[]){ + &blsp1_qup6_i2c_apps_clk_src.clkr.hw }, + .num_parents = 1, + /* + * RPM uses QUP6 I2C to communicate with the external + * PMIC so it must not be disabled. + */ + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_blsp1_qup6_spi_apps_clk = { .halt_reg = 0x0700c, .clkr = { @@ -4281,6 +4301,7 @@ static struct clk_regmap *gcc_ipq6018_clks[] = { [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, [GCC_BLSP1_QUP5_I2C_APPS_CLK] = &gcc_blsp1_qup5_i2c_apps_clk.clkr, [GCC_BLSP1_QUP5_SPI_APPS_CLK] = &gcc_blsp1_qup5_spi_apps_clk.clkr, + [GCC_BLSP1_QUP6_I2C_APPS_CLK] = &gcc_blsp1_qup6_i2c_apps_clk.clkr, [GCC_BLSP1_QUP6_SPI_APPS_CLK] = &gcc_blsp1_qup6_spi_apps_clk.clkr, [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, From e641a070137dd959932c7c222e000d9d941167a2 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:29:51 +0530 Subject: [PATCH 289/396] clk: qcom: ipq8074: drop the CLK_SET_RATE_PARENT flag from PLL clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPLL, NSS crypto PLL clock rates are fixed and shouldn't be scaled based on the request from dependent clocks. Doing so will result in the unexpected behaviour. So drop the CLK_SET_RATE_PARENT flag from the PLL clocks. Cc: stable@vger.kernel.org Fixes: b8e7e519625f ("clk: qcom: ipq8074: add remaining PLL’s") Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-1-c8ceb1a37680@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-ipq8074.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/clk/qcom/gcc-ipq8074.c b/drivers/clk/qcom/gcc-ipq8074.c index 63ac2ced76bb..b7faf12a511a 100644 --- a/drivers/clk/qcom/gcc-ipq8074.c +++ b/drivers/clk/qcom/gcc-ipq8074.c @@ -75,7 +75,6 @@ static struct clk_fixed_factor gpll0_out_main_div2 = { &gpll0_main.clkr.hw }, .num_parents = 1, .ops = &clk_fixed_factor_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -121,7 +120,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { &gpll2_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -154,7 +152,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { &gpll4_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -188,7 +185,6 @@ static struct clk_alpha_pll_postdiv gpll6 = { &gpll6_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -201,7 +197,6 @@ static struct clk_fixed_factor gpll6_out_main_div2 = { &gpll6_main.clkr.hw }, .num_parents = 1, .ops = &clk_fixed_factor_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -266,7 +261,6 @@ static struct clk_alpha_pll_postdiv nss_crypto_pll = { &nss_crypto_pll_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; From 99cd4935cb972d0aafb16838bb2aeadbcaf196ce Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:29:52 +0530 Subject: [PATCH 290/396] clk: qcom: ipq6018: drop the CLK_SET_RATE_PARENT flag from PLL clocks GPLL, NSS crypto PLL clock rates are fixed and shouldn't be scaled based on the request from dependent clocks. Doing so will result in the unexpected behaviour. So drop the CLK_SET_RATE_PARENT flag from the PLL clocks. Cc: stable@vger.kernel.org Fixes: d9db07f088af ("clk: qcom: Add ipq6018 Global Clock Controller support") Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-2-c8ceb1a37680@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-ipq6018.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/clk/qcom/gcc-ipq6018.c b/drivers/clk/qcom/gcc-ipq6018.c index bff878268fa6..b366912cd648 100644 --- a/drivers/clk/qcom/gcc-ipq6018.c +++ b/drivers/clk/qcom/gcc-ipq6018.c @@ -72,7 +72,6 @@ static struct clk_fixed_factor gpll0_out_main_div2 = { &gpll0_main.clkr.hw }, .num_parents = 1, .ops = &clk_fixed_factor_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -86,7 +85,6 @@ static struct clk_alpha_pll_postdiv gpll0 = { &gpll0_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -161,7 +159,6 @@ static struct clk_alpha_pll_postdiv gpll6 = { &gpll6_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -192,7 +189,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { &gpll4_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -243,7 +239,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { &gpll2_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -274,7 +269,6 @@ static struct clk_alpha_pll_postdiv nss_crypto_pll = { &nss_crypto_pll_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; From 01a5e4c6731ab6b4b74822661d296f8893fc1230 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:29:53 +0530 Subject: [PATCH 291/396] clk: qcom: ipq5018: drop the CLK_SET_RATE_PARENT flag from GPLL clocks GPLL clock rates are fixed and shouldn't be scaled based on the request from dependent clocks. Doing so will result in the unexpected behaviour. So drop the CLK_SET_RATE_PARENT flag from the GPLL clocks. ---- Changes in V2: - New patch Fixes: e3fdbef1bab8 ("clk: qcom: Add Global Clock controller (GCC) driver for IPQ5018") Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-3-c8ceb1a37680@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-ipq5018.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c index 70f6ade3ac2a..4aba47e8700d 100644 --- a/drivers/clk/qcom/gcc-ipq5018.c +++ b/drivers/clk/qcom/gcc-ipq5018.c @@ -129,7 +129,6 @@ static struct clk_alpha_pll_postdiv gpll0 = { }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -144,7 +143,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -159,7 +157,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; From 99a8f8764b70158a712992640a6be46a8fd79d15 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:29:54 +0530 Subject: [PATCH 292/396] clk: qcom: ipq9574: drop the CLK_SET_RATE_PARENT flag from GPLL clocks GPLL clock rates are fixed and shouldn't be scaled based on the request from dependent clocks. Doing so will result in the unexpected behaviour. So drop the CLK_SET_RATE_PARENT flag from the GPLL clocks. ---- Changes in V2: - No changes Fixes: d75b82cff488 ("clk: qcom: Add Global Clock Controller driver for IPQ9574") Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-4-c8ceb1a37680@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-ipq9574.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/clk/qcom/gcc-ipq9574.c b/drivers/clk/qcom/gcc-ipq9574.c index 8f430367299e..e8190108e1ae 100644 --- a/drivers/clk/qcom/gcc-ipq9574.c +++ b/drivers/clk/qcom/gcc-ipq9574.c @@ -87,7 +87,6 @@ static struct clk_fixed_factor gpll0_out_main_div2 = { &gpll0_main.clkr.hw }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_fixed_factor_ops, }, }; @@ -102,7 +101,6 @@ static struct clk_alpha_pll_postdiv gpll0 = { &gpll0_main.clkr.hw }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_alpha_pll_postdiv_ro_ops, }, }; @@ -132,7 +130,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { &gpll4_main.clkr.hw }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_alpha_pll_postdiv_ro_ops, }, }; @@ -162,7 +159,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { &gpll2_main.clkr.hw }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_alpha_pll_postdiv_ro_ops, }, }; From 5635ef0bd1052420bc659a00be6fd0c60cec5cb9 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:29:55 +0530 Subject: [PATCH 293/396] clk: qcom: ipq5332: drop the CLK_SET_RATE_PARENT flag from GPLL clocks GPLL clock rates are fixed and shouldn't be scaled based on the request from dependent clocks. Doing so will result in the unexpected behaviour. So drop the CLK_SET_RATE_PARENT flag from the GPLL clocks. Fixes: 3d89d52970fd ("clk: qcom: add Global Clock controller (GCC) driver for IPQ5332 SoC") Signed-off-by: Kathiravan Thirumoorthy Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-5-c8ceb1a37680@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/gcc-ipq5332.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/clk/qcom/gcc-ipq5332.c b/drivers/clk/qcom/gcc-ipq5332.c index b836159fbdef..f98591148a97 100644 --- a/drivers/clk/qcom/gcc-ipq5332.c +++ b/drivers/clk/qcom/gcc-ipq5332.c @@ -112,7 +112,6 @@ static struct clk_alpha_pll_postdiv gpll2 = { &gpll2_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; @@ -152,7 +151,6 @@ static struct clk_alpha_pll_postdiv gpll4 = { &gpll4_main.clkr.hw }, .num_parents = 1, .ops = &clk_alpha_pll_postdiv_ro_ops, - .flags = CLK_SET_RATE_PARENT, }, }; From e0e6373d653b7707bf042ecf1538884597c5d0da Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Thu, 14 Sep 2023 12:29:57 +0530 Subject: [PATCH 294/396] clk: qcom: apss-ipq6018: add the GPLL0 clock also as clock provider While the kernel is booting up, APSS PLL will be running at 800MHz with GPLL0 as source. Once the cpufreq driver is available, APSS PLL will be configured and select the rate based on the opp table and the source will be changed to APSS_PLL_EARLY. Without this patch, CPU Freq driver reports that CPU is running at 24MHz instead of the 800MHz. Reviewed-by: Konrad Dybcio Tested-by: Robert Marko Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20230913-gpll_cleanup-v2-7-c8ceb1a37680@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/clk/qcom/apss-ipq6018.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/qcom/apss-ipq6018.c b/drivers/clk/qcom/apss-ipq6018.c index 0783d1aa8efa..e6295b832686 100644 --- a/drivers/clk/qcom/apss-ipq6018.c +++ b/drivers/clk/qcom/apss-ipq6018.c @@ -23,16 +23,19 @@ enum { P_XO, + P_GPLL0, P_APSS_PLL_EARLY, }; static const struct clk_parent_data parents_apcs_alias0_clk_src[] = { { .fw_name = "xo" }, + { .fw_name = "gpll0" }, { .fw_name = "pll" }, }; static const struct parent_map parents_apcs_alias0_clk_src_map[] = { { P_XO, 0 }, + { P_GPLL0, 4 }, { P_APSS_PLL_EARLY, 5 }, }; From 98408df6ad1fa14ad352f8d28d68eacdc94ca382 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 23 Oct 2023 12:28:02 +0200 Subject: [PATCH 295/396] clk: meson: S4: select CONFIG_COMMON_CLK_MESON_CLKC_UTILS Without this, the newly added drivers fail to link: aarch64-linux-ld: drivers/clk/meson/s4-pll.o: in function `meson_s4_pll_probe': s4-pll.c:(.text+0x13c): undefined reference to `meson_clk_hw_get' aarch64-linux-ld: drivers/clk/meson/s4-peripherals.o: in function `meson_s4_periphs_probe': s4-peripherals.c:(.text+0xb0): undefined reference to `meson_clk_hw_get' Fixes: e787c9c55eda ("clk: meson: S4: add support for Amlogic S4 SoC PLL clock driver") Reviewed-by: Jerome Brunet Reviewed-by: Neil Armstrong Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20231023102810.4001943-1-arnd@kernel.org [jbrunet: use 12 char for the Fixes as recommended ] Signed-off-by: Jerome Brunet --- drivers/clk/meson/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index c5303e4c1604..29ffd14d267b 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -149,6 +149,7 @@ config COMMON_CLK_S4_PLL tristate "S4 SoC PLL clock controllers support" depends on ARM64 default y + select COMMON_CLK_MESON_CLKC_UTILS select COMMON_CLK_MESON_MPLL select COMMON_CLK_MESON_PLL select COMMON_CLK_MESON_REGMAP @@ -161,6 +162,7 @@ config COMMON_CLK_S4_PERIPHERALS tristate "S4 SoC peripherals clock controllers support" depends on ARM64 default y + select COMMON_CLK_MESON_CLKC_UTILS select COMMON_CLK_MESON_REGMAP select COMMON_CLK_MESON_DUALDIV select COMMON_CLK_MESON_VID_PLL_DIV From 942a4a61b64e182d756a1a5776aa500d3b3d862f Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Fri, 20 Oct 2023 17:52:43 +0000 Subject: [PATCH 296/396] platform/x86: thinkpad_acpi: replace deprecated strncpy with memcpy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit strncpy() is deprecated for use on NUL-terminated destination strings [1] and as such we should prefer more robust and less ambiguous interfaces. We expect ec_fw_string to be NUL-terminated based on its use with format strings in thinkpad_acpi.c: 11241 | pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n", 11242 | ec_fw_string); Moreover, NUL-padding is not required since ec_fw_string is explicitly zero-initialized: 11185 | char ec_fw_string[18] = {0}; When carefully copying bytes from one buffer to another in pre-determined blocks (like what's happening here with dmi_data): | static void find_new_ec_fwstr(const struct dmi_header *dm, void *private) | { | char *ec_fw_string = (char *) private; | const char *dmi_data = (const char *)dm; | /* | * ThinkPad Embedded Controller Program Table on newer models | * | * Offset | Name | Width | Description | * ---------------------------------------------------- | * 0x00 | Type | BYTE | 0x8C | * 0x01 | Length | BYTE | | * 0x02 | Handle | WORD | Varies | * 0x04 | Signature | BYTEx6 | ASCII for "LENOVO" | * 0x0A | OEM struct offset | BYTE | 0x0B | * 0x0B | OEM struct number | BYTE | 0x07, for this structure | * 0x0C | OEM struct revision | BYTE | 0x01, for this format | * 0x0D | ECP version ID | STR ID | | * 0x0E | ECP release date | STR ID | | */ | | /* Return if data structure not match */ | if (dm->type != 140 || dm->length < 0x0F || | memcmp(dmi_data + 4, "LENOVO", 6) != 0 || | dmi_data[0x0A] != 0x0B || dmi_data[0x0B] != 0x07 || | dmi_data[0x0C] != 0x01) | return; | | /* fwstr is the first 8byte string */ | strncpy(ec_fw_string, dmi_data + 0x0F, 8); ... we shouldn't be using a C string api. Let's instead use memcpy() as this more properly relays the intended behavior. Do note that ec_fw_string will still end up being NUL-terminated since we are memcpy'ing only 8 bytes into a buffer full of 18 zeroes. There's still some trailing NUL-bytes there. To ensure this behavior, let's add a BUILD_BUG_ON checking the length leaves space for at least one trailing NUL-byte. Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://github.com/KSPP/linux/issues/90 Cc: Kees Cook Signed-off-by: Justin Stitt Reviewed-by: Mark Pearson Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20231020-strncpy-drivers-platform-x86-thinkpad_acpi-c-v1-1-312f2e33034f@google.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/thinkpad_acpi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9c19624a7454..c3499bf60582 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -11226,6 +11226,8 @@ invalid: return '\0'; } +#define EC_FW_STRING_LEN 18 + static void find_new_ec_fwstr(const struct dmi_header *dm, void *private) { char *ec_fw_string = (char *) private; @@ -11254,7 +11256,8 @@ static void find_new_ec_fwstr(const struct dmi_header *dm, void *private) return; /* fwstr is the first 8byte string */ - strncpy(ec_fw_string, dmi_data + 0x0F, 8); + BUILD_BUG_ON(EC_FW_STRING_LEN <= 8); + memcpy(ec_fw_string, dmi_data + 0x0F, 8); } /* returns 0 - probe ok, or < 0 - probe error. @@ -11264,7 +11267,7 @@ static int __must_check __init get_thinkpad_model_data( struct thinkpad_id_data *tp) { const struct dmi_device *dev = NULL; - char ec_fw_string[18] = {0}; + char ec_fw_string[EC_FW_STRING_LEN] = {0}; char const *s; char t; From ebcae17f87b34f71e8e55512226c4da35a9e3233 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 9 Sep 2023 16:28:47 +0100 Subject: [PATCH 297/396] clk: si521xx: Use i2c_get_match_data() instead of device_get_match_data() The device_get_match_data(), is to get match data for firmware interfaces such as just OF/ACPI. This driver has I2C matching table as well. Use i2c_get_match_data() to get match data for I2C, ACPI and DT-based matching. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230909152847.16216-1-biju.das.jz@bp.renesas.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-si521xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index 4eaf1b53f06b..14c8741b9ba0 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -279,7 +279,7 @@ si521xx_of_clk_get(struct of_phandle_args *clkspec, void *data) static int si521xx_probe(struct i2c_client *client) { - const u16 chip_info = (u16)(uintptr_t)device_get_match_data(&client->dev); + const u16 chip_info = (u16)(uintptr_t)i2c_get_match_data(client); const struct clk_parent_data clk_parent_data = { .index = 0 }; struct si521xx *si; unsigned char name[6] = "DIFF0"; From b28f95c61965fd31ca15556e7ac65dfc84a15fad Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 9 Sep 2023 16:54:18 +0100 Subject: [PATCH 298/396] clk: clk-si544: Simplify probe() and is_valid_frequency() The driver has an OF match table, still, it uses an ID lookup table for retrieving match data. Currently, the driver is working on the assumption that an I2C device registered via OF will always match a legacy I2C device ID. The correct approach is to have an OF device ID table using i2c_get_match_data() if the devices are registered via OF/ID. Unify the OF/ID table by using max_freq as match data instead of enum si544_speed_grade and replace the ID lookup table for the match data by i2c_get_match_data(). This allows to simplify both probe() and is_valid_frequency(). Drop enum si544_speed_grade as there is no user. While at it, remove the trailing comma in the terminator entry for the OF table making code robust against (theoretical) misrebases or other similar things where the new entry goes _after_ the termination without the compiler noticing. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230909155418.24426-1-biju.das.jz@bp.renesas.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-si544.c | 51 ++++++++++++----------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c index 22925968aa35..4132db706144 100644 --- a/drivers/clk/clk-si544.c +++ b/drivers/clk/clk-si544.c @@ -56,17 +56,11 @@ #define DELTA_M_FRAC_NUM 19 #define DELTA_M_FRAC_DEN 20000 -enum si544_speed_grade { - si544a, - si544b, - si544c, -}; - struct clk_si544 { struct clk_hw hw; struct regmap *regmap; struct i2c_client *i2c_client; - enum si544_speed_grade speed_grade; + unsigned long max_freq; }; #define to_clk_si544(_hw) container_of(_hw, struct clk_si544, hw) @@ -196,24 +190,10 @@ static int si544_set_muldiv(struct clk_si544 *data, static bool is_valid_frequency(const struct clk_si544 *data, unsigned long frequency) { - unsigned long max_freq = 0; - if (frequency < SI544_MIN_FREQ) return false; - switch (data->speed_grade) { - case si544a: - max_freq = 1500000000; - break; - case si544b: - max_freq = 800000000; - break; - case si544c: - max_freq = 350000000; - break; - } - - return frequency <= max_freq; + return frequency <= data->max_freq; } /* Calculate divider settings for a given frequency */ @@ -451,19 +431,10 @@ static const struct regmap_config si544_regmap_config = { .volatile_reg = si544_regmap_is_volatile, }; -static const struct i2c_device_id si544_id[] = { - { "si544a", si544a }, - { "si544b", si544b }, - { "si544c", si544c }, - { } -}; -MODULE_DEVICE_TABLE(i2c, si544_id); - static int si544_probe(struct i2c_client *client) { struct clk_si544 *data; struct clk_init_data init; - const struct i2c_device_id *id = i2c_match_id(si544_id, client); int err; data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); @@ -475,7 +446,7 @@ static int si544_probe(struct i2c_client *client) init.num_parents = 0; data->hw.init = &init; data->i2c_client = client; - data->speed_grade = id->driver_data; + data->max_freq = (uintptr_t)i2c_get_match_data(client); if (of_property_read_string(client->dev.of_node, "clock-output-names", &init.name)) @@ -507,11 +478,19 @@ static int si544_probe(struct i2c_client *client) return 0; } +static const struct i2c_device_id si544_id[] = { + { "si544a", 1500000000 }, + { "si544b", 800000000 }, + { "si544c", 350000000 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si544_id); + static const struct of_device_id clk_si544_of_match[] = { - { .compatible = "silabs,si544a" }, - { .compatible = "silabs,si544b" }, - { .compatible = "silabs,si544c" }, - { }, + { .compatible = "silabs,si544a", .data = (void *)1500000000 }, + { .compatible = "silabs,si544b", .data = (void *)800000000 }, + { .compatible = "silabs,si544c", .data = (void *)350000000 }, + { } }; MODULE_DEVICE_TABLE(of, clk_si544_of_match); From 38a929ab128d7f0ac61f7cb506e6687d145b9eba Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 9 Sep 2023 17:02:18 +0100 Subject: [PATCH 299/396] clk: rs9: Use i2c_get_match_data() instead of device_get_match_data() The device_get_match_data(), is to get match data for firmware interfaces such as just OF/ACPI. This driver has I2C matching table as well. Use i2c_get_match_data() to get match data for I2C, ACPI and DT-based matching. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230909160218.33078-1-biju.das.jz@bp.renesas.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-renesas-pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c index 7d7b2cb75318..380245f635d6 100644 --- a/drivers/clk/clk-renesas-pcie.c +++ b/drivers/clk/clk-renesas-pcie.c @@ -298,7 +298,7 @@ static int rs9_probe(struct i2c_client *client) i2c_set_clientdata(client, rs9); rs9->client = client; - rs9->chip_info = device_get_match_data(&client->dev); + rs9->chip_info = i2c_get_match_data(client); if (!rs9->chip_info) return -EINVAL; From f234f028727f8634973f8a9ef2ec933eb0eade5b Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 9 Sep 2023 17:20:47 +0100 Subject: [PATCH 300/396] clk: si5351: Simplify probe The driver has an OF match table, still, it uses an ID lookup table for retrieving match data. Currently, the driver is working on the assumption that an I2C device registered via OF will always match a legacy I2C device ID. The correct approach is to have an OF device ID table using i2c_get_match_data() if the devices are registered via OF/ID. Simplify probe() by replacing ID lookup table for retrieving match data with i2c_get_match_data(). Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230909162047.41845-1-biju.das.jz@bp.renesas.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-si5351.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 00fb9b09e030..afe12d1a9ddc 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -1385,8 +1385,7 @@ MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids); static int si5351_i2c_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_match_id(si5351_i2c_ids, client); - enum si5351_variant variant = (enum si5351_variant)id->driver_data; + enum si5351_variant variant; struct si5351_platform_data *pdata; struct si5351_driver_data *drvdata; struct clk_init_data init; @@ -1394,6 +1393,7 @@ static int si5351_i2c_probe(struct i2c_client *client) u8 num_parents, num_clocks; int ret, n; + variant = (enum si5351_variant)(uintptr_t)i2c_get_match_data(client); ret = si5351_dt_parse(client, variant); if (ret) return ret; From 15f5e2e4225a94fe76302e87ecdf95e56e571382 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 9 Sep 2023 17:47:38 +0100 Subject: [PATCH 301/396] clk: si570: Simplify probe The driver has an OF match table, still, it uses an ID lookup table for retrieving match data. Currently, the driver is working on the assumption that an I2C device registered via OF will always match a legacy I2C device ID. The correct approach is to have an OF device ID table using i2c_get_match_data() if the devices are registered via OF/ID. Unify the OF/ID table by adding struct clk_si570_info as match data instead of clk_si570_variant and replace the ID lookup table for the match data by i2c_get_match_data(). This allows to simplify probe(). Drop enum clk_si570_variant as there is no user. While at it, remove the trailing comma in the terminator entry for the OF table making code robust against (theoretical) misrebases or other similar things where the new entry goes _after_ the termination without the compiler noticing. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230909164738.47708-1-biju.das.jz@bp.renesas.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-si570.c | 67 +++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index de0212fb5f87..ad053a922a42 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -49,12 +49,22 @@ #define SI570_FREEZE_DCO (1 << 4) +/** + * struct clk_si570_info: + * @max_freq: Maximum frequency for this device + * @has_temperature_stability: Device support temperature stability + */ +struct clk_si570_info { + u64 max_freq; + bool has_temperature_stability; +}; + /** * struct clk_si570: * @hw: Clock hw struct * @regmap: Device's regmap * @div_offset: Rgister offset for dividers - * @max_freq: Maximum frequency for this device + * @info: Device info * @fxtal: Factory xtal frequency * @n1: Clock divider N1 * @hs_div: Clock divider HSDIV @@ -66,7 +76,7 @@ struct clk_si570 { struct clk_hw hw; struct regmap *regmap; unsigned int div_offset; - u64 max_freq; + const struct clk_si570_info *info; u64 fxtal; unsigned int n1; unsigned int hs_div; @@ -76,11 +86,6 @@ struct clk_si570 { }; #define to_clk_si570(_hw) container_of(_hw, struct clk_si570, hw) -enum clk_si570_variant { - si57x, - si59x -}; - /** * si570_get_divs() - Read clock dividers from HW * @data: Pointer to struct clk_si570 @@ -341,7 +346,7 @@ static int si570_set_rate(struct clk_hw *hw, unsigned long rate, struct i2c_client *client = data->i2c_client; int err; - if (rate < SI570_MIN_FREQ || rate > data->max_freq) { + if (rate < SI570_MIN_FREQ || rate > data->info->max_freq) { dev_err(&client->dev, "requested frequency %lu Hz is out of range\n", rate); return -EINVAL; @@ -398,24 +403,13 @@ static const struct regmap_config si570_regmap_config = { .volatile_reg = si570_regmap_is_volatile, }; -static const struct i2c_device_id si570_id[] = { - { "si570", si57x }, - { "si571", si57x }, - { "si598", si59x }, - { "si599", si59x }, - { } -}; -MODULE_DEVICE_TABLE(i2c, si570_id); - static int si570_probe(struct i2c_client *client) { struct clk_si570 *data; struct clk_init_data init; - const struct i2c_device_id *id = i2c_match_id(si570_id, client); u32 initial_fout, factory_fout, stability; bool skip_recall; int err; - enum clk_si570_variant variant = id->driver_data; data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -427,7 +421,8 @@ static int si570_probe(struct i2c_client *client) data->hw.init = &init; data->i2c_client = client; - if (variant == si57x) { + data->info = i2c_get_match_data(client); + if (data->info->has_temperature_stability) { err = of_property_read_u32(client->dev.of_node, "temperature-stability", &stability); if (err) { @@ -438,10 +433,6 @@ static int si570_probe(struct i2c_client *client) /* adjust register offsets for 7ppm devices */ if (stability == 7) data->div_offset = SI570_DIV_OFFSET_7PPM; - - data->max_freq = SI570_MAX_FREQ; - } else { - data->max_freq = SI598_MAX_FREQ; } if (of_property_read_string(client->dev.of_node, "clock-output-names", @@ -496,12 +487,30 @@ static int si570_probe(struct i2c_client *client) return 0; } +static const struct clk_si570_info clk_si570_info = { + .max_freq = SI570_MAX_FREQ, + .has_temperature_stability = true, +}; + +static const struct clk_si570_info clk_si590_info = { + .max_freq = SI598_MAX_FREQ, +}; + +static const struct i2c_device_id si570_id[] = { + { "si570", (kernel_ulong_t)&clk_si570_info }, + { "si571", (kernel_ulong_t)&clk_si570_info }, + { "si598", (kernel_ulong_t)&clk_si590_info }, + { "si599", (kernel_ulong_t)&clk_si590_info }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si570_id); + static const struct of_device_id clk_si570_of_match[] = { - { .compatible = "silabs,si570" }, - { .compatible = "silabs,si571" }, - { .compatible = "silabs,si598" }, - { .compatible = "silabs,si599" }, - { }, + { .compatible = "silabs,si570", .data = &clk_si570_info }, + { .compatible = "silabs,si571", .data = &clk_si570_info }, + { .compatible = "silabs,si598", .data = &clk_si590_info }, + { .compatible = "silabs,si599", .data = &clk_si590_info }, + { } }; MODULE_DEVICE_TABLE(of, clk_si570_of_match); From faf6b92ee0091ff7a7bba03a1726a1a97112e9db Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 9 Sep 2023 16:05:16 +0100 Subject: [PATCH 302/396] clk: cdce925: Extend match support for OF tables The driver has an OF match table, still, it uses an ID lookup table for retrieving match data. Currently, the driver is working on the assumption that an I2C device registered via OF will always match a legacy I2C device ID. The correct approach is to have an OF device ID table using i2c_get_match_data() if the devices are registered via OF/ID. Unify the OF/ID table by using struct clk_cdce925_chip_info as match data for both these tables and replace the ID lookup table for the match data by i2c_get_match_data(). Split the array clk_cdce925_chip_info_tbl[] as individual variables, and make lines shorter by referring to e.g. &clk_cdce913_info instead of &clk_cdce925_chip_info_tbl[CDCE913]. Drop enum related to chip type as there is no user. While at it, remove the trailing comma in the terminator entry for the OF table making code robust against (theoretical) misrebases or other similar things where the new entry goes _after_ the termination without the compiler noticing. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230909150516.10353-1-biju.das.jz@bp.renesas.com Signed-off-by: Stephen Boyd --- drivers/clk/clk-cdce925.c | 65 +++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index cdee4958f26d..584c103394bb 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -25,25 +25,11 @@ * Model this as 2 PLL clocks which are parents to the outputs. */ -enum { - CDCE913, - CDCE925, - CDCE937, - CDCE949, -}; - struct clk_cdce925_chip_info { int num_plls; int num_outputs; }; -static const struct clk_cdce925_chip_info clk_cdce925_chip_info_tbl[] = { - [CDCE913] = { .num_plls = 1, .num_outputs = 3 }, - [CDCE925] = { .num_plls = 2, .num_outputs = 5 }, - [CDCE937] = { .num_plls = 3, .num_outputs = 7 }, - [CDCE949] = { .num_plls = 4, .num_outputs = 9 }, -}; - #define MAX_NUMBER_OF_PLLS 4 #define MAX_NUMBER_OF_OUTPUTS 9 @@ -621,20 +607,10 @@ static struct regmap_bus regmap_cdce925_bus = { .read = cdce925_regmap_i2c_read, }; -static const struct i2c_device_id cdce925_id[] = { - { "cdce913", CDCE913 }, - { "cdce925", CDCE925 }, - { "cdce937", CDCE937 }, - { "cdce949", CDCE949 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, cdce925_id); - static int cdce925_probe(struct i2c_client *client) { struct clk_cdce925_chip *data; struct device_node *node = client->dev.of_node; - const struct i2c_device_id *id = i2c_match_id(cdce925_id, client); const char *parent_name; const char *pll_clk_name[MAX_NUMBER_OF_PLLS] = {NULL,}; struct clk_init_data init; @@ -665,7 +641,7 @@ static int cdce925_probe(struct i2c_client *client) return -ENOMEM; data->i2c_client = client; - data->chip_info = &clk_cdce925_chip_info_tbl[id->driver_data]; + data->chip_info = i2c_get_match_data(client); config.max_register = CDCE925_OFFSET_PLL + data->chip_info->num_plls * 0x10 - 1; data->regmap = devm_regmap_init(&client->dev, ®map_cdce925_bus, @@ -822,12 +798,41 @@ error: return err; } +static const struct clk_cdce925_chip_info clk_cdce913_info = { + .num_plls = 1, + .num_outputs = 3, +}; + +static const struct clk_cdce925_chip_info clk_cdce925_info = { + .num_plls = 2, + .num_outputs = 5, +}; + +static const struct clk_cdce925_chip_info clk_cdce937_info = { + .num_plls = 3, + .num_outputs = 7, +}; + +static const struct clk_cdce925_chip_info clk_cdce949_info = { + .num_plls = 4, + .num_outputs = 9, +}; + +static const struct i2c_device_id cdce925_id[] = { + { "cdce913", (kernel_ulong_t)&clk_cdce913_info }, + { "cdce925", (kernel_ulong_t)&clk_cdce925_info }, + { "cdce937", (kernel_ulong_t)&clk_cdce937_info }, + { "cdce949", (kernel_ulong_t)&clk_cdce949_info }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cdce925_id); + static const struct of_device_id clk_cdce925_of_match[] = { - { .compatible = "ti,cdce913" }, - { .compatible = "ti,cdce925" }, - { .compatible = "ti,cdce937" }, - { .compatible = "ti,cdce949" }, - { }, + { .compatible = "ti,cdce913", .data = &clk_cdce913_info }, + { .compatible = "ti,cdce925", .data = &clk_cdce925_info }, + { .compatible = "ti,cdce937", .data = &clk_cdce937_info }, + { .compatible = "ti,cdce949", .data = &clk_cdce949_info }, + { } }; MODULE_DEVICE_TABLE(of, clk_cdce925_of_match); From 5ad1e217a2b23aa046b241183bd9452d259d70d0 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 16 Oct 2023 16:05:27 -0600 Subject: [PATCH 303/396] clk: visconti: Fix undefined behavior bug in struct visconti_pll_provider `struct clk_hw_onecell_data` is a flexible structure, which means that it contains flexible-array member at the bottom, in this case array `hws`: include/linux/clk-provider.h: 1380 struct clk_hw_onecell_data { 1381 unsigned int num; 1382 struct clk_hw *hws[] __counted_by(num); 1383 }; This could potentially lead to an overwrite of the objects following `clk_data` in `struct visconti_pll_provider`, in this case `struct device_node *node;`, at run-time: drivers/clk/visconti/pll.h: 16 struct visconti_pll_provider { 17 void __iomem *reg_base; 18 struct clk_hw_onecell_data clk_data; 19 struct device_node *node; 20 }; Notice that a total of 56 bytes are allocated for flexible-array `hws` at line 328. See below: include/dt-bindings/clock/toshiba,tmpv770x.h: 14 #define TMPV770X_NR_PLL 7 drivers/clk/visconti/pll-tmpv770x.c: 69 ctx = visconti_init_pll(np, reg_base, TMPV770X_NR_PLL); drivers/clk/visconti/pll.c: 321 struct visconti_pll_provider * __init visconti_init_pll(struct device_node *np, 322 void __iomem *base, 323 unsigned long nr_plls) 324 { 325 struct visconti_pll_provider *ctx; ... 328 ctx = kzalloc(struct_size(ctx, clk_data.hws, nr_plls), GFP_KERNEL); `struct_size(ctx, clk_data.hws, nr_plls)` above translates to sizeof(struct visconti_pll_provider) + sizeof(struct clk_hw *) * 7 == 24 + 8 * 7 == 24 + 56 ^^^^ | allocated bytes for flex array `hws` $ pahole -C visconti_pll_provider drivers/clk/visconti/pll.o struct visconti_pll_provider { void * reg_base; /* 0 8 */ struct clk_hw_onecell_data clk_data; /* 8 8 */ struct device_node * node; /* 16 8 */ /* size: 24, cachelines: 1, members: 3 */ /* last cacheline: 24 bytes */ }; And then, after the allocation, some data is written into all members of `struct visconti_pll_provider`: 332 for (i = 0; i < nr_plls; ++i) 333 ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); 334 335 ctx->node = np; 336 ctx->reg_base = base; 337 ctx->clk_data.num = nr_plls; Fix all these by placing the declaration of object `clk_data` at the end of `struct visconti_pll_provider`. Also, add a comment to make it clear that this object must always be last in the structure, and prevent this bug from being introduced again in the future. -Wflex-array-member-not-at-end is coming in GCC-14, and we are getting ready to enable it globally. Fixes: b4cbe606dc36 ("clk: visconti: Add support common clock driver and reset driver") Cc: stable@vger.kernel.org Reviewed-by: Kees Cook Acked-by: Nobuhiro Iwamatsu Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/57a831d94ee2b3889b11525d4ad500356f89576f.1697492890.git.gustavoars@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/visconti/pll.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/visconti/pll.h b/drivers/clk/visconti/pll.h index 01d07f1bf01b..c4bd40676da4 100644 --- a/drivers/clk/visconti/pll.h +++ b/drivers/clk/visconti/pll.h @@ -15,8 +15,10 @@ struct visconti_pll_provider { void __iomem *reg_base; - struct clk_hw_onecell_data clk_data; struct device_node *node; + + /* Must be last */ + struct clk_hw_onecell_data clk_data; }; #define VISCONTI_PLL_RATE(_rate, _dacen, _dsmen, \ From 397d887c1601a71e8a8abdb6beea67d58f0472d3 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 16 Oct 2023 16:06:16 -0600 Subject: [PATCH 304/396] clk: visconti: Add bounds-checking coverage for struct visconti_pll_provider In order to gain the bounds-checking coverage that __counted_by provides to flexible-array members at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions), we must make sure that the counter member, in this particular case `num`, is updated before the first access to the flex-array member, in this particular case array `hws`. See below: commit f316cdff8d67 ("clk: Annotate struct clk_hw_onecell_data with __counted_by") introduced `__counted_by` for `struct clk_hw_onecell_data` together with changes to relocate some of assignments of counter `num` before `hws` is accessed: include/linux/clk-provider.h: 1380 struct clk_hw_onecell_data { 1381 unsigned int num; 1382 struct clk_hw *hws[] __counted_by(num); 1383 }; However, this structure is used as a member in other structs, in this case in `struct visconti_pll_provider`: drivers/clk/visconti/pll.h: 16 struct visconti_pll_provider { 17 void __iomem *reg_base; 18 struct device_node *node; 19 20 /* Must be last */ 21 struct clk_hw_onecell_data clk_data; 22 }; Hence, we need to move the assignments to `ctx->clk_data.num` after allocation for `struct visconti_pll_provider` and before accessing the flexible array `ctx->clk_data.hws`. And, as assignments for all members in `struct visconti_pll_provider` are originally adjacent to each other, relocate all assignments together, so we don't split up `ctx->clk_data.hws = nr_plls` from the rest. :) Reviewed-by: Kees Cook Acked-by: Nobuhiro Iwamatsu Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/e3189f3e40e8723b6d794fb2260e2e9ab6b960bd.1697492890.git.gustavoars@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/visconti/pll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c index 1f3234f22667..e9cd80e085dc 100644 --- a/drivers/clk/visconti/pll.c +++ b/drivers/clk/visconti/pll.c @@ -329,12 +329,12 @@ struct visconti_pll_provider * __init visconti_init_pll(struct device_node *np, if (!ctx) return ERR_PTR(-ENOMEM); - for (i = 0; i < nr_plls; ++i) - ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); - ctx->node = np; ctx->reg_base = base; ctx->clk_data.num = nr_plls; + for (i = 0; i < nr_plls; ++i) + ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); + return ctx; } From 409c39ec92a35e3708f5b5798c78eae78512cd71 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 6 Oct 2023 16:39:58 -0500 Subject: [PATCH 305/396] clk: Use device_get_match_data() Use preferred device_get_match_data() instead of of_match_device() to get the driver match data. With this, adjust the includes to explicitly include the correct headers. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20231006213959.334439-1-robh@kernel.org Reviewed-by: Dmitry Baryshkov #msm part Acked-by: Krzysztof Kozlowski # Samsung Acked-by: David Lechner Acked-by: Chanwoo Choi Acked-by: Charles Keepax Reviewed-by: Bjorn Andersson Signed-off-by: Stephen Boyd --- drivers/clk/clk-lochnagar.c | 9 ++------- drivers/clk/davinci/da8xx-cfgchip.c | 8 +++----- drivers/clk/davinci/pll.c | 10 +++------- drivers/clk/davinci/psc.c | 10 +++------- drivers/clk/qcom/gcc-msm8960.c | 13 +++++-------- drivers/clk/qcom/gcc-msm8974.c | 10 +++------- drivers/clk/qcom/kpss-xcc.c | 9 ++------- drivers/clk/qcom/krait-cc.c | 14 +++++--------- drivers/clk/qcom/mmcc-msm8960.c | 16 +++++----------- drivers/clk/qcom/mmcc-sdm660.c | 8 ++------ drivers/clk/rockchip/clk-rk3399.c | 9 ++------- drivers/clk/samsung/clk-exynos-clkout.c | 8 +++----- drivers/clk/ti/adpll.c | 14 ++++---------- 13 files changed, 42 insertions(+), 96 deletions(-) diff --git a/drivers/clk/clk-lochnagar.c b/drivers/clk/clk-lochnagar.c index db468a62c8d7..5561a2c66b69 100644 --- a/drivers/clk/clk-lochnagar.c +++ b/drivers/clk/clk-lochnagar.c @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include #include #include @@ -242,22 +242,17 @@ static int lochnagar_clk_probe(struct platform_device *pdev) }; struct device *dev = &pdev->dev; struct lochnagar_clk_priv *priv; - const struct of_device_id *of_id; struct lochnagar_clk *lclk; struct lochnagar_config *conf; int ret, i; - of_id = of_match_device(lochnagar_of_match, dev); - if (!of_id) - return -EINVAL; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->dev = dev; priv->regmap = dev_get_regmap(dev->parent, NULL); - conf = (struct lochnagar_config *)of_id->data; + conf = (struct lochnagar_config *)device_get_match_data(dev); memcpy(priv->lclks, conf->clks, sizeof(priv->lclks)); diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index e5b2cdfe88ce..ad2d0df43dc6 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -11,10 +11,10 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -744,15 +744,13 @@ static int da8xx_cfgchip_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct da8xx_cfgchip_clk_platform_data *pdata = dev->platform_data; - const struct of_device_id *of_id; da8xx_cfgchip_init clk_init = NULL; struct regmap *regmap = NULL; - of_id = of_match_device(da8xx_cfgchip_of_match, dev); - if (of_id) { + clk_init = device_get_match_data(dev); + if (clk_init) { struct device_node *parent; - clk_init = of_id->data; parent = of_get_parent(dev->of_node); regmap = syscon_node_to_regmap(parent); of_node_put(parent); diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index 87bdf8879045..5bbbb3a66477 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -18,11 +18,10 @@ #include #include #include -#include -#include #include #include #include +#include #include #include #include @@ -892,14 +891,11 @@ static int davinci_pll_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct davinci_pll_platform_data *pdata; - const struct of_device_id *of_id; davinci_pll_init pll_init = NULL; void __iomem *base; - of_id = of_match_device(davinci_pll_of_match, dev); - if (of_id) - pll_init = of_id->data; - else if (pdev->id_entry) + pll_init = device_get_match_data(dev); + if (!pll_init && pdev->id_entry) pll_init = (void *)pdev->id_entry->driver_data; if (!pll_init) { diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index cd85d9f158b0..355d1be0b5d8 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -18,10 +18,9 @@ #include #include #include -#include -#include #include #include +#include #include #include #include @@ -517,15 +516,12 @@ static const struct platform_device_id davinci_psc_id_table[] = { static int davinci_psc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *of_id; const struct davinci_psc_init_data *init_data = NULL; void __iomem *base; int ret; - of_id = of_match_device(davinci_psc_of_match, dev); - if (of_id) - init_data = of_id->data; - else if (pdev->id_entry) + init_data = device_get_match_data(dev); + if (!init_data && pdev->id_entry) init_data = (void *)pdev->id_entry->driver_data; if (!init_data) { diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index dbc7093ab9cc..6236a458e4eb 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -7,9 +7,10 @@ #include #include #include +#include #include #include -#include +#include #include #include #include @@ -3716,14 +3717,10 @@ MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table); static int gcc_msm8960_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *match; struct platform_device *tsens; + const struct qcom_cc_desc *desc = device_get_match_data(dev); int ret; - match = of_match_device(gcc_msm8960_match_table, &pdev->dev); - if (!match) - return -EINVAL; - ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000); if (ret) return ret; @@ -3732,11 +3729,11 @@ static int gcc_msm8960_probe(struct platform_device *pdev) if (ret) return ret; - ret = qcom_cc_probe(pdev, match->data); + ret = qcom_cc_probe(pdev, desc); if (ret) return ret; - if (match->data == &gcc_apq8064_desc) { + if (desc == &gcc_apq8064_desc) { hfpll1.d = &hfpll1_8064_data; hfpll_l2.d = &hfpll_l2_8064_data; } diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index 0231c1efd286..b32e66714951 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -7,9 +7,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -2875,14 +2875,10 @@ static int gcc_msm8974_probe(struct platform_device *pdev) { int ret; struct device *dev = &pdev->dev; - const struct of_device_id *id; - - id = of_match_device(gcc_msm8974_match_table, dev); - if (!id) - return -ENODEV; + const void *data = device_get_match_data(dev); if (!of_device_is_compatible(dev->of_node, "qcom,gcc-msm8974")) { - if (id->data == &gcc_msm8226_desc) + if (data == &gcc_msm8226_desc) msm8226_clock_override(); else msm8974_pro_clock_override(); diff --git a/drivers/clk/qcom/kpss-xcc.c b/drivers/clk/qcom/kpss-xcc.c index 97358c98c6c9..23b0b11f0007 100644 --- a/drivers/clk/qcom/kpss-xcc.c +++ b/drivers/clk/qcom/kpss-xcc.c @@ -5,10 +5,10 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -32,20 +32,15 @@ MODULE_DEVICE_TABLE(of, kpss_xcc_match_table); static int kpss_xcc_driver_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *id; void __iomem *base; struct clk_hw *hw; const char *name; - id = of_match_device(kpss_xcc_match_table, dev); - if (!id) - return -ENODEV; - base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); - if (id->data) { + if (device_get_match_data(&pdev->dev)) { if (of_property_read_string_index(dev->of_node, "clock-output-names", 0, &name)) diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c index 410ae8390f1c..ae325f4e1047 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c @@ -5,10 +5,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -347,22 +347,18 @@ MODULE_DEVICE_TABLE(of, krait_cc_match_table); static int krait_cc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *id; unsigned long cur_rate, aux_rate; int cpu; struct clk_hw *mux, *l2_pri_mux; struct clk *clk, **clks; - - id = of_match_device(krait_cc_match_table, dev); - if (!id) - return -ENODEV; + bool unique_aux = !!device_get_match_data(dev); /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */ clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1); if (IS_ERR(clk)) return PTR_ERR(clk); - if (!id->data) { + if (!unique_aux) { clk = clk_register_fixed_factor(dev, "acpu_aux", "gpll0_vote", 0, 1, 2); if (IS_ERR(clk)) @@ -375,13 +371,13 @@ static int krait_cc_probe(struct platform_device *pdev) return -ENOMEM; for_each_possible_cpu(cpu) { - mux = krait_add_clks(dev, cpu, id->data); + mux = krait_add_clks(dev, cpu, unique_aux); if (IS_ERR(mux)) return PTR_ERR(mux); clks[cpu] = mux->clk; } - l2_pri_mux = krait_add_clks(dev, -1, id->data); + l2_pri_mux = krait_add_clks(dev, -1, unique_aux); if (IS_ERR(l2_pri_mux)) return PTR_ERR(l2_pri_mux); clks[l2_mux] = l2_pri_mux->clk; diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index 6bf908a51f53..50638ab341ec 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -8,9 +8,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -3105,30 +3105,24 @@ MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table); static int mmcc_msm8960_probe(struct platform_device *pdev) { - const struct of_device_id *match; struct regmap *regmap; - bool is_8064; struct device *dev = &pdev->dev; + const struct qcom_cc_desc *desc = device_get_match_data(dev); - match = of_match_device(mmcc_msm8960_match_table, dev); - if (!match) - return -EINVAL; - - is_8064 = of_device_is_compatible(dev->of_node, "qcom,mmcc-apq8064"); - if (is_8064) { + if (desc == &mmcc_apq8064_desc) { gfx3d_src.freq_tbl = clk_tbl_gfx3d_8064; gfx3d_src.clkr.hw.init = &gfx3d_8064_init; gfx3d_src.s[0].parent_map = mmcc_pxo_pll8_pll2_pll15_map; gfx3d_src.s[1].parent_map = mmcc_pxo_pll8_pll2_pll15_map; } - regmap = qcom_cc_map(pdev, match->data); + regmap = qcom_cc_map(pdev, desc); if (IS_ERR(regmap)) return PTR_ERR(regmap); clk_pll_configure_sr(&pll15, regmap, &pll15_config, false); - return qcom_cc_really_probe(pdev, match->data, regmap); + return qcom_cc_really_probe(pdev, desc, regmap); } static struct platform_driver mmcc_msm8960_driver = { diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index bc19a23e13f8..996bd01fb9ac 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -9,9 +9,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -2828,14 +2828,10 @@ static void sdm630_clock_override(void) static int mmcc_660_probe(struct platform_device *pdev) { - const struct of_device_id *id; struct regmap *regmap; bool is_sdm630; - id = of_match_device(mmcc_660_match_table, &pdev->dev); - if (!id) - return -ENODEV; - is_sdm630 = !!(id->data); + is_sdm630 = !!device_get_match_data(&pdev->dev); regmap = qcom_cc_map(pdev, &mmcc_660_desc); if (IS_ERR(regmap)) diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 9ebd6c451b3d..9316e5c8a0ea 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -9,8 +9,8 @@ #include #include #include -#include #include +#include #include #include #include "clk.h" @@ -1634,14 +1634,9 @@ static const struct of_device_id clk_rk3399_match_table[] = { static int __init clk_rk3399_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; const struct clk_rk3399_inits *init_data; - match = of_match_device(clk_rk3399_match_table, &pdev->dev); - if (!match || !match->data) - return -EINVAL; - - init_data = match->data; + init_data = device_get_match_data(&pdev->dev); if (init_data->inits) init_data->inits(np); diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index 72b6cf83aff4..3484e6cc80ad 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -13,9 +13,9 @@ #include #include #include -#include #include #include +#include #define EXYNOS_CLKOUT_NR_CLKS 1 #define EXYNOS_CLKOUT_PARENTS 32 @@ -84,19 +84,17 @@ MODULE_DEVICE_TABLE(of, exynos_clkout_ids); static int exynos_clkout_match_parent_dev(struct device *dev, u32 *mux_mask) { const struct exynos_clkout_variant *variant; - const struct of_device_id *match; if (!dev->parent) { dev_err(dev, "not instantiated from MFD\n"); return -EINVAL; } - match = of_match_device(exynos_clkout_ids, dev->parent); - if (!match) { + variant = device_get_match_data(dev->parent); + if (!variant) { dev_err(dev, "cannot match parent device\n"); return -EINVAL; } - variant = match->data; *mux_mask = variant->mux_mask; diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c index ff42ea75cb43..6121020b4b38 100644 --- a/drivers/clk/ti/adpll.c +++ b/drivers/clk/ti/adpll.c @@ -8,7 +8,9 @@ #include #include #include -#include +#include +#include +#include #include #define ADPLL_PLLSS_MMR_LOCK_OFFSET 0x00 /* Managed by MPPULL */ @@ -860,24 +862,16 @@ static int ti_adpll_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct device *dev = &pdev->dev; - const struct of_device_id *match; - const struct ti_adpll_platform_data *pdata; struct ti_adpll_data *d; struct resource *res; int err; - match = of_match_device(ti_adpll_match, dev); - if (match) - pdata = match->data; - else - return -ENODEV; - d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); if (!d) return -ENOMEM; d->dev = dev; d->np = node; - d->c = pdata; + d->c = device_get_match_data(dev); dev_set_drvdata(d->dev, d); spin_lock_init(&d->lock); From dcce5cc7826e9c6b3a2443e5e6b7f8d02a103c35 Mon Sep 17 00:00:00 2001 From: Vishal Badole Date: Sun, 27 Nov 2022 22:53:19 +0530 Subject: [PATCH 306/396] clk: Show active consumers of clocks in debugfs This feature lists the clock consumer's name and respective connection id. Using this feature user can easily check that which user has acquired and enabled a particular clock. Usage: >> cat /sys/kernel/debug/clk/clk_summary enable prepare protect duty hardware Connection clock count count count rate accuracy phase cycle enable consumer Id ------------------------------------------------------------------------------------------------------------------------------ clk_mcasp0_fixed 0 0 0 24576000 0 0 50000 Y deviceless of_clk_get_from_provider deviceless no_connection_id clk_mcasp0 0 0 0 24576000 0 0 50000 N simple-audio-card,cpu no_connection_id deviceless no_connection_id Co-developed-by: Chinmoy Ghosh Signed-off-by: Chinmoy Ghosh Co-developed-by: Mintu Patel Signed-off-by: Mintu Patel Co-developed-by: Vimal Kumar Signed-off-by: Vimal Kumar Signed-off-by: Vishal Badole Link: https://lore.kernel.org/r/1669569799-8526-1-git-send-email-badolevishal1116@gmail.com Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index c249f9791ae8..0544615d2a1d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3188,28 +3188,41 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c, int level) { int phase; + struct clk *clk_user; + int multi_node = 0; - seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu ", + seq_printf(s, "%*s%-*s %-7d %-8d %-8d %-11lu %-10lu ", level * 3 + 1, "", - 30 - level * 3, c->name, + 35 - level * 3, c->name, c->enable_count, c->prepare_count, c->protect_count, clk_core_get_rate_recalc(c), clk_core_get_accuracy_recalc(c)); phase = clk_core_get_phase(c); if (phase >= 0) - seq_printf(s, "%5d", phase); + seq_printf(s, "%-5d", phase); else seq_puts(s, "-----"); - seq_printf(s, " %6d", clk_core_get_scaled_duty_cycle(c, 100000)); + seq_printf(s, " %-6d", clk_core_get_scaled_duty_cycle(c, 100000)); if (c->ops->is_enabled) - seq_printf(s, " %9c\n", clk_core_is_enabled(c) ? 'Y' : 'N'); + seq_printf(s, " %5c ", clk_core_is_enabled(c) ? 'Y' : 'N'); else if (!c->ops->enable) - seq_printf(s, " %9c\n", 'Y'); + seq_printf(s, " %5c ", 'Y'); else - seq_printf(s, " %9c\n", '?'); + seq_printf(s, " %5c ", '?'); + + hlist_for_each_entry(clk_user, &c->clks, clks_node) { + seq_printf(s, "%*s%-*s %-25s\n", + level * 3 + 2 + 105 * multi_node, "", + 30, + clk_user->dev_id ? clk_user->dev_id : "deviceless", + clk_user->con_id ? clk_user->con_id : "no_connection_id"); + + multi_node = 1; + } + } static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c, @@ -3230,9 +3243,10 @@ static int clk_summary_show(struct seq_file *s, void *data) struct clk_core *c; struct hlist_head **lists = s->private; - seq_puts(s, " enable prepare protect duty hardware\n"); - seq_puts(s, " clock count count count rate accuracy phase cycle enable\n"); - seq_puts(s, "-------------------------------------------------------------------------------------------------------\n"); + seq_puts(s, " enable prepare protect duty hardware connection\n"); + seq_puts(s, " clock count count count rate accuracy phase cycle enable consumer id\n"); + seq_puts(s, "---------------------------------------------------------------------------------------------------------------------------------------------\n"); + clk_prepare_lock(); From e43d31915cc4fca4e04daeca6c0ff25cc57cf956 Mon Sep 17 00:00:00 2001 From: John Keeping Date: Thu, 20 Apr 2023 11:38:04 +0100 Subject: [PATCH 307/396] clk: Allow phase adjustment from debugfs For testing it may be useful to manually adjust a clock's phase. Add support for writing to the existing clk_phase debugfs file, with the written value clamped to [0, 360) to match the behaviour of the clk_set_phase() function. This is a dangerous feature, so use the existing define CLOCK_ALLOW_WRITE_DEBUGFS to allow it only if the source is modified. Signed-off-by: John Keeping Link: https://lore.kernel.org/r/20230420103805.125246-1-john@metanate.com Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0544615d2a1d..2f0885e4f6bf 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3343,6 +3343,21 @@ static int clk_rate_set(void *data, u64 val) #define clk_rate_mode 0644 +static int clk_phase_set(void *data, u64 val) +{ + struct clk_core *core = data; + int degrees = do_div(val, 360); + int ret; + + clk_prepare_lock(); + ret = clk_core_set_phase_nolock(core, degrees); + clk_prepare_unlock(); + + return ret; +} + +#define clk_phase_mode 0644 + static int clk_prepare_enable_set(void *data, u64 val) { struct clk_core *core = data; @@ -3370,6 +3385,9 @@ DEFINE_DEBUGFS_ATTRIBUTE(clk_prepare_enable_fops, clk_prepare_enable_get, #else #define clk_rate_set NULL #define clk_rate_mode 0444 + +#define clk_phase_set NULL +#define clk_phase_mode 0644 #endif static int clk_rate_get(void *data, u64 *val) @@ -3385,6 +3403,16 @@ static int clk_rate_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(clk_rate_fops, clk_rate_get, clk_rate_set, "%llu\n"); +static int clk_phase_get(void *data, u64 *val) +{ + struct clk_core *core = data; + + *val = core->phase; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(clk_phase_fops, clk_phase_get, clk_phase_set, "%llu\n"); + static const struct { unsigned long flag; const char *name; @@ -3575,7 +3603,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) debugfs_create_file("clk_min_rate", 0444, root, core, &clk_min_rate_fops); debugfs_create_file("clk_max_rate", 0444, root, core, &clk_max_rate_fops); debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy); - debugfs_create_u32("clk_phase", 0444, root, &core->phase); + debugfs_create_file("clk_phase", clk_phase_mode, root, core, + &clk_phase_fops); debugfs_create_file("clk_flags", 0444, root, core, &clk_flags_fops); debugfs_create_u32("clk_prepare_count", 0444, root, &core->prepare_count); debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count); From 48a8748fd0d18b07741f311cd6929982490c5903 Mon Sep 17 00:00:00 2001 From: Zhifeng Tang Date: Wed, 13 Sep 2023 19:52:11 +0800 Subject: [PATCH 308/396] clk: sprd: Composite driver support offset config The composite interface support the offset configuration, which is used to support mux and div in different registers. Because some sprd projects, the divider has different addresses from mux for one composite clk. Signed-off-by: Zhifeng Tang Reviewed-by: Chunyan Zhang Link: https://lore.kernel.org/r/20230913115211.11512-1-zhifeng.tang@unisoc.com Signed-off-by: Stephen Boyd --- drivers/clk/sprd/composite.h | 36 +++++++++++++++++++++++++++--------- drivers/clk/sprd/div.c | 6 +++--- drivers/clk/sprd/div.h | 17 ++++++++++++----- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/drivers/clk/sprd/composite.h b/drivers/clk/sprd/composite.h index adbabbe596b7..15cec97d2aa7 100644 --- a/drivers/clk/sprd/composite.h +++ b/drivers/clk/sprd/composite.h @@ -19,24 +19,24 @@ struct sprd_comp { }; #define SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \ - _mshift, _mwidth, _dshift, _dwidth, \ - _flags, _fn) \ + _mshift, _mwidth, _doffset, _dshift, \ + _dwidth, _flags, _fn) \ struct sprd_comp _struct = { \ .mux = _SPRD_MUX_CLK(_mshift, _mwidth, _table), \ - .div = _SPRD_DIV_CLK(_dshift, _dwidth), \ + .div = _SPRD_DIV_CLK(_doffset, _dshift, _dwidth), \ .common = { \ .regmap = NULL, \ .reg = _reg, \ .hw.init = _fn(_name, _parent, \ &sprd_comp_ops, _flags), \ - } \ + } \ } #define SPRD_COMP_CLK_TABLE(_struct, _name, _parent, _reg, _table, \ _mshift, _mwidth, _dshift, _dwidth, _flags) \ SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \ - _mshift, _mwidth, _dshift, _dwidth, \ - _flags, CLK_HW_INIT_PARENTS) + _mshift, _mwidth, 0x0, _dshift, \ + _dwidth, _flags, CLK_HW_INIT_PARENTS) #define SPRD_COMP_CLK(_struct, _name, _parent, _reg, _mshift, \ _mwidth, _dshift, _dwidth, _flags) \ @@ -47,15 +47,33 @@ struct sprd_comp { _mshift, _mwidth, _dshift, \ _dwidth, _flags) \ SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \ - _mshift, _mwidth, _dshift, _dwidth, \ - _flags, CLK_HW_INIT_PARENTS_DATA) + _mshift, _mwidth, 0x0, _dshift, \ + _dwidth, _flags, \ + CLK_HW_INIT_PARENTS_DATA) #define SPRD_COMP_CLK_DATA(_struct, _name, _parent, _reg, _mshift, \ _mwidth, _dshift, _dwidth, _flags) \ - SPRD_COMP_CLK_DATA_TABLE(_struct, _name, _parent, _reg, NULL, \ + SPRD_COMP_CLK_DATA_TABLE(_struct, _name, _parent, _reg, NULL, \ _mshift, _mwidth, _dshift, _dwidth, \ _flags) +#define SPRD_COMP_CLK_DATA_TABLE_OFFSET(_struct, _name, _parent, _reg, \ + _table, _mshift, _mwidth, \ + _doffset, _dshift, _dwidth, \ + _flags) \ + SPRD_COMP_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _table, \ + _mshift, _mwidth, _doffset, _dshift, \ + _dwidth, _flags, \ + CLK_HW_INIT_PARENTS_DATA) + +#define SPRD_COMP_CLK_DATA_OFFSET(_struct, _name, _parent, _reg, \ + _mshift, _mwidth, _doffset, _dshift, \ + _dwidth, _flags) \ + SPRD_COMP_CLK_DATA_TABLE_OFFSET(_struct, _name, _parent, _reg, \ + NULL, _mshift, _mwidth, \ + _doffset, _dshift, _dwidth, \ + _flags) + static inline struct sprd_comp *hw_to_sprd_comp(const struct clk_hw *hw) { struct sprd_clk_common *common = hw_to_sprd_clk_common(hw); diff --git a/drivers/clk/sprd/div.c b/drivers/clk/sprd/div.c index c7261630cab4..936782c24127 100644 --- a/drivers/clk/sprd/div.c +++ b/drivers/clk/sprd/div.c @@ -25,7 +25,7 @@ unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common, unsigned long val; unsigned int reg; - regmap_read(common->regmap, common->reg, ®); + regmap_read(common->regmap, common->reg + div->offset, ®); val = reg >> div->shift; val &= (1 << div->width) - 1; @@ -53,10 +53,10 @@ int sprd_div_helper_set_rate(const struct sprd_clk_common *common, val = divider_get_val(rate, parent_rate, NULL, div->width, 0); - regmap_read(common->regmap, common->reg, ®); + regmap_read(common->regmap, common->reg + div->offset, ®); reg &= ~GENMASK(div->width + div->shift - 1, div->shift); - regmap_write(common->regmap, common->reg, + regmap_write(common->regmap, common->reg + div->offset, reg | (val << div->shift)); return 0; diff --git a/drivers/clk/sprd/div.h b/drivers/clk/sprd/div.h index f5d614b3dcf1..a0bcad80498f 100644 --- a/drivers/clk/sprd/div.h +++ b/drivers/clk/sprd/div.h @@ -20,12 +20,14 @@ * classes. */ struct sprd_div_internal { + s32 offset; u8 shift; u8 width; }; -#define _SPRD_DIV_CLK(_shift, _width) \ +#define _SPRD_DIV_CLK(_offset, _shift, _width) \ { \ + .offset = _offset, \ .shift = _shift, \ .width = _width, \ } @@ -35,10 +37,10 @@ struct sprd_div { struct sprd_clk_common common; }; -#define SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ +#define SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, _offset, \ _shift, _width, _flags, _fn) \ struct sprd_div _struct = { \ - .div = _SPRD_DIV_CLK(_shift, _width), \ + .div = _SPRD_DIV_CLK(_offset, _shift, _width), \ .common = { \ .regmap = NULL, \ .reg = _reg, \ @@ -49,12 +51,17 @@ struct sprd_div { #define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \ _shift, _width, _flags) \ - SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ + SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, 0x0, \ _shift, _width, _flags, CLK_HW_INIT) +#define SPRD_DIV_CLK_FW_NAME(_struct, _name, _parent, _reg, \ + _shift, _width, _flags) \ + SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, 0x0, \ + _shift, _width, _flags, CLK_HW_INIT_FW_NAME) + #define SPRD_DIV_CLK_HW(_struct, _name, _parent, _reg, \ _shift, _width, _flags) \ - SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \ + SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, 0x0, \ _shift, _width, _flags, CLK_HW_INIT_HW) static inline struct sprd_div *hw_to_sprd_div(const struct clk_hw *hw) From ee58d6a115cefd7e8065eb469788dafa00b999d1 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 24 Jul 2023 17:42:47 -0700 Subject: [PATCH 309/396] clk: analogbits: Allow building the library as a module This library is only used by the SiFive PRCI driver. When that driver is built as a module, it makes sense to build this library as a module too. Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20230725004248.381868-1-samuel.holland@sifive.com Signed-off-by: Stephen Boyd --- drivers/clk/analogbits/Kconfig | 2 +- drivers/clk/analogbits/wrpll-cln28hpc.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/clk/analogbits/Kconfig b/drivers/clk/analogbits/Kconfig index 1e291b185438..7d73db0fcd49 100644 --- a/drivers/clk/analogbits/Kconfig +++ b/drivers/clk/analogbits/Kconfig @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only config CLK_ANALOGBITS_WRPLL_CLN28HPC - bool + tristate diff --git a/drivers/clk/analogbits/wrpll-cln28hpc.c b/drivers/clk/analogbits/wrpll-cln28hpc.c index 09ca82356399..65d422a588e1 100644 --- a/drivers/clk/analogbits/wrpll-cln28hpc.c +++ b/drivers/clk/analogbits/wrpll-cln28hpc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -312,6 +313,7 @@ int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate, return 0; } +EXPORT_SYMBOL_GPL(wrpll_configure_for_rate); /** * wrpll_calc_output_rate() - calculate the PLL's target output rate @@ -349,6 +351,7 @@ unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c, return n; } +EXPORT_SYMBOL_GPL(wrpll_calc_output_rate); /** * wrpll_calc_max_lock_us() - return the time for the PLL to lock @@ -366,3 +369,8 @@ unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c) { return MAX_LOCK_US; } +EXPORT_SYMBOL_GPL(wrpll_calc_max_lock_us); + +MODULE_AUTHOR("Paul Walmsley "); +MODULE_DESCRIPTION("Analog Bits Wide-Range PLL library"); +MODULE_LICENSE("GPL"); From c8e1d8ae6aba7521d96d5cde21384edde1f06d3d Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Mon, 24 Jul 2023 17:42:48 -0700 Subject: [PATCH 310/396] clk: sifive: Allow building the driver as a module This can reduce the kernel image size in multiplatform configurations. Signed-off-by: Samuel Holland Link: https://lore.kernel.org/r/20230725004248.381868-2-samuel.holland@sifive.com Signed-off-by: Stephen Boyd --- drivers/clk/sifive/Kconfig | 2 +- drivers/clk/sifive/sifive-prci.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig index 2322f634a910..49597d95602e 100644 --- a/drivers/clk/sifive/Kconfig +++ b/drivers/clk/sifive/Kconfig @@ -10,7 +10,7 @@ menuconfig CLK_SIFIVE if CLK_SIFIVE config CLK_SIFIVE_PRCI - bool "PRCI driver for SiFive SoCs" + tristate "PRCI driver for SiFive SoCs" default ARCH_SIFIVE select RESET_CONTROLLER select RESET_SIMPLE diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c index af81eb835bc2..25b8e1a80ddc 100644 --- a/drivers/clk/sifive/sifive-prci.c +++ b/drivers/clk/sifive/sifive-prci.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "sifive-prci.h" #include "fu540-prci.h" @@ -618,9 +619,8 @@ static struct platform_driver sifive_prci_driver = { }, .probe = sifive_prci_probe, }; +module_platform_driver(sifive_prci_driver); -static int __init sifive_prci_init(void) -{ - return platform_driver_register(&sifive_prci_driver); -} -core_initcall(sifive_prci_init); +MODULE_AUTHOR("Paul Walmsley "); +MODULE_DESCRIPTION("SiFive Power Reset Clock Interface (PRCI) driver"); +MODULE_LICENSE("GPL"); From d761bb01c85b22d5b44abe283eb89019693f6595 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 23 Oct 2023 21:30:52 -0600 Subject: [PATCH 311/396] clk: socfpga: Fix undefined behavior bug in struct stratix10_clock_data `struct clk_hw_onecell_data` is a flexible structure, which means that it contains flexible-array member at the bottom, in this case array `hws`: include/linux/clk-provider.h: 1380 struct clk_hw_onecell_data { 1381 unsigned int num; 1382 struct clk_hw *hws[] __counted_by(num); 1383 }; This could potentially lead to an overwrite of the objects following `clk_data` in `struct stratix10_clock_data`, in this case `void __iomem *base;` at run-time: drivers/clk/socfpga/stratix10-clk.h: 9 struct stratix10_clock_data { 10 struct clk_hw_onecell_data clk_data; 11 void __iomem *base; 12 }; There are currently three different places where memory is allocated for `struct stratix10_clock_data`, including the flex-array `hws` in `struct clk_hw_onecell_data`: drivers/clk/socfpga/clk-agilex.c: 469 clk_data = devm_kzalloc(dev, struct_size(clk_data, clk_data.hws, 470 num_clks), GFP_KERNEL); drivers/clk/socfpga/clk-agilex.c: 509 clk_data = devm_kzalloc(dev, struct_size(clk_data, clk_data.hws, 510 num_clks), GFP_KERNEL); drivers/clk/socfpga/clk-s10.c: 400 clk_data = devm_kzalloc(dev, struct_size(clk_data, clk_data.hws, 401 num_clks), GFP_KERNEL); I'll use just one of them to describe the issue. See below. Notice that a total of 440 bytes are allocated for flexible-array member `hws` at line 469: include/dt-bindings/clock/agilex-clock.h: 70 #define AGILEX_NUM_CLKS 55 drivers/clk/socfpga/clk-agilex.c: 459 struct stratix10_clock_data *clk_data; 460 void __iomem *base; ... 466 467 num_clks = AGILEX_NUM_CLKS; 468 469 clk_data = devm_kzalloc(dev, struct_size(clk_data, clk_data.hws, 470 num_clks), GFP_KERNEL); `struct_size(clk_data, clk_data.hws, num_clks)` above translates to sizeof(struct stratix10_clock_data) + sizeof(struct clk_hw *) * 55 == 16 + 8 * 55 == 16 + 440 ^^^ | allocated bytes for flex-array `hws` 474 for (i = 0; i < num_clks; i++) 475 clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT); 476 477 clk_data->base = base; and then some data is written into both `hws` and `base` objects. Fix this by placing the declaration of object `clk_data` at the end of `struct stratix10_clock_data`. Also, add a comment to make it clear that this object must always be last in the structure. -Wflex-array-member-not-at-end is coming in GCC-14, and we are getting ready to enable it globally. Fixes: ba7e258425ac ("clk: socfpga: Convert to s10/agilex/n5x to use clk_hw") Cc: stable@vger.kernel.org Reviewed-by: Kees Cook Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/1da736106d8e0806aeafa6e471a13ced490eae22.1698117815.git.gustavoars@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/stratix10-clk.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/socfpga/stratix10-clk.h b/drivers/clk/socfpga/stratix10-clk.h index 75234e0783e1..83fe4eb3133c 100644 --- a/drivers/clk/socfpga/stratix10-clk.h +++ b/drivers/clk/socfpga/stratix10-clk.h @@ -7,8 +7,10 @@ #define __STRATIX10_CLK_H struct stratix10_clock_data { - struct clk_hw_onecell_data clk_data; void __iomem *base; + + /* Must be last */ + struct clk_hw_onecell_data clk_data; }; struct stratix10_pll_clock { From 65f9e1becb5592c120c9f11adce97f5ca31dce9b Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 23 Oct 2023 21:31:42 -0600 Subject: [PATCH 312/396] clk: socfpga: agilex: Add bounds-checking coverage for struct stratix10_clock_data In order to gain the bounds-checking coverage that __counted_by provides to flexible-array members at run-time via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions), we must make sure that the counter member, in this case `num`, is updated before the first access to the flex-array member, in this case array `hws`. commit f316cdff8d67 ("clk: Annotate struct clk_hw_onecell_data with __counted_by") introduced `__counted_by` for `struct clk_hw_onecell_data` together with changes to relocate some of assignments of counter `num` before `hws` is accessed: include/linux/clk-provider.h: 1380 struct clk_hw_onecell_data { 1381 unsigned int num; 1382 struct clk_hw *hws[] __counted_by(num); 1383 }; However, this structure is used as a member in other structs, in this case in `struct sstratix10_clock_data`: drivers/clk/socfpga/stratix10-clk.h: 9 struct stratix10_clock_data { 10 void __iomem *base; 11 12 /* Must be last */ 13 struct clk_hw_onecell_data clk_data; 14 }; Hence, we need to move the assignments to `clk_data->clk_data.num` after allocations for `struct stratix10_clock_data` and before accessing the flexible array `clk_data->clk_data.hws`. And, as assignments for both `clk_data->clk_data.num` and `clk_data->base` are originally adjacent to each other, relocate both assignments together. Reviewed-by: Kees Cook Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/385c516c498e07eb9a521107e16a7efd26e86ea5.1698117815.git.gustavoars@kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-agilex.c | 12 ++++++------ drivers/clk/socfpga/clk-s10.c | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/clk/socfpga/clk-agilex.c b/drivers/clk/socfpga/clk-agilex.c index 6b65a74aefa6..8dd94f64756b 100644 --- a/drivers/clk/socfpga/clk-agilex.c +++ b/drivers/clk/socfpga/clk-agilex.c @@ -471,12 +471,12 @@ static int agilex_clkmgr_init(struct platform_device *pdev) if (!clk_data) return -ENOMEM; + clk_data->clk_data.num = num_clks; + clk_data->base = base; + for (i = 0; i < num_clks; i++) clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT); - clk_data->base = base; - clk_data->clk_data.num = num_clks; - agilex_clk_register_pll(agilex_pll_clks, ARRAY_SIZE(agilex_pll_clks), clk_data); agilex_clk_register_c_perip(agilex_main_perip_c_clks, @@ -511,12 +511,12 @@ static int n5x_clkmgr_init(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - for (i = 0; i < num_clks; i++) - clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT); - clk_data->base = base; clk_data->clk_data.num = num_clks; + for (i = 0; i < num_clks; i++) + clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT); + n5x_clk_register_pll(agilex_pll_clks, ARRAY_SIZE(agilex_pll_clks), clk_data); n5x_clk_register_c_perip(n5x_main_perip_c_clks, diff --git a/drivers/clk/socfpga/clk-s10.c b/drivers/clk/socfpga/clk-s10.c index 3752bd9c103c..b4bf4e2d38e1 100644 --- a/drivers/clk/socfpga/clk-s10.c +++ b/drivers/clk/socfpga/clk-s10.c @@ -402,12 +402,12 @@ static int s10_clkmgr_init(struct platform_device *pdev) if (!clk_data) return -ENOMEM; - for (i = 0; i < num_clks; i++) - clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT); - clk_data->base = base; clk_data->clk_data.num = num_clks; + for (i = 0; i < num_clks; i++) + clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT); + s10_clk_register_pll(s10_pll_clks, ARRAY_SIZE(s10_pll_clks), clk_data); s10_clk_register_c_perip(s10_main_perip_c_clks, From bd54ccc0f147019dac38e7841876a7415459b875 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 24 Oct 2023 08:00:53 +0300 Subject: [PATCH 313/396] clk: mediatek: fix double free in mtk_clk_register_pllfh() The mtk_clk_register_pll_ops() currently frees the "pll" parameter. The function has two callers, mtk_clk_register_pll() and mtk_clk_register_pllfh(). The first one, the _pll() function relies on the free, but for the second _pllfh() function it causes a double free bug. Really the frees should be done in the caller because that's where the allocation is. Fixes: d7964de8a8ea ("clk: mediatek: Add new clock driver to handle FHCTL hardware") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/cd7fa365-28cc-4c34-ac64-6da57c98baa6@moroto.mountain Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-pll.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index a4eca5fd539c..513ab6b1b322 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -321,10 +321,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll, ret = clk_hw_register(NULL, &pll->hw); - if (ret) { - kfree(pll); + if (ret) return ERR_PTR(ret); - } return &pll->hw; } @@ -340,6 +338,8 @@ struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data, return ERR_PTR(-ENOMEM); hw = mtk_clk_register_pll_ops(pll, data, base, &mtk_pll_ops); + if (IS_ERR(hw)) + kfree(pll); return hw; } From 858bd78c9d324781217bb42a87766ca9194809ca Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 21 Oct 2023 11:48:41 +0200 Subject: [PATCH 314/396] platform/x86: asus-wmi: Do not report brightness up/down keys when also reported by acpi_video MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a long time now the acpi_video driver reports evdev brightness up/down key events for the brightness hotkeys on most (non ancient) laptops. asus-wmi also reports evdev brightness up/down key events for these keys leading to each press being reported twice and e.g. GNOME increasing the brightness by 2 steps instead of 1 step. Use the acpi_video_handles_brightness_key_presses() helper to detect if acpi_video is reporting brightness key-presses and if it is then don't report the same events also from the asus-wmi driver. Note there is a chance that this may lead to regressions where the brightness hotkeys stop working because they are not actually reported by the acpi_video driver. Unfortunately the only way to find out if this is a problem is to try. To at least avoid regressions on old hw using the eeepc-wmi driver, implement this as a key filter in asus-nb-wmi so that the eeepc-wmi driver is not affected. Reported-by: James John Closes: https://lore.kernel.org/platform-driver-x86/a2c441fe-457e-44cf-a146-0ecd86b037cf@donjajo.com/ Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20231021094841.7419-1-hdegoede@redhat.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-nb-wmi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index d85d895fee89..67e4111716ca 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -16,6 +16,8 @@ #include #include +#include + #include "asus-wmi.h" #define ASUS_NB_WMI_FILE "asus-nb-wmi" @@ -603,6 +605,19 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_END, 0}, }; +static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, + unsigned int *value, bool *autorelease) +{ + switch (*code) { + case ASUS_WMI_BRN_DOWN: + case ASUS_WMI_BRN_UP: + if (acpi_video_handles_brightness_key_presses()) + *code = ASUS_WMI_KEY_IGNORE; + + break; + } +} + static struct asus_wmi_driver asus_nb_wmi_driver = { .name = ASUS_NB_WMI_FILE, .owner = THIS_MODULE, @@ -611,6 +626,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = { .input_name = "Asus WMI hotkeys", .input_phys = ASUS_NB_WMI_FILE "/input0", .detect_quirks = asus_nb_wmi_quirks, + .key_filter = asus_nb_wmi_key_filter, }; From 02a258ac3ebf8a530d340ec24a694c13ac9d25c0 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 19 Oct 2023 15:51:22 +0200 Subject: [PATCH 315/396] platform/x86/amd/hsmp: Fix iomem handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the metrics table is marked as io memory, use memcpy_fromio() when copying its contents. Compile-tested only. Fixes: 5150542b8ec5 ("platform/x86/amd/hsmp: add support for metrics tbl") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20231019135122.21774-1-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/amd/hsmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd/hsmp.c b/drivers/platform/x86/amd/hsmp.c index b056a5c8654a..b55d80e29139 100644 --- a/drivers/platform/x86/amd/hsmp.c +++ b/drivers/platform/x86/amd/hsmp.c @@ -362,7 +362,7 @@ static ssize_t hsmp_metric_tbl_read(struct file *filp, struct kobject *kobj, ret = hsmp_send_message(&msg); if (ret) return ret; - memcpy(buf, sock->metric_tbl_addr, bin_attr->size); + memcpy_fromio(buf, sock->metric_tbl_addr, bin_attr->size); return bin_attr->size; } From 4186a47dbfbce2f97b0c025a7eac32bb5130df05 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Fri, 20 Oct 2023 23:10:01 +0200 Subject: [PATCH 316/396] platform/x86: wmi: Decouple probe deferring from wmi_block_list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many aggregate WMI drivers do not use -EPROBE_DEFER when they cannot find a WMI device during probe, instead they require all WMI devices associated with an platform device to become available at once. This is currently achieved by adding those WMI devices to the wmi_block_list before they are registered, which is then used by the deprecated GUID-based functions to search for WMI devices. Replace this approach with a device link which defers probing of the WMI device until the associated platform device has finished probing (and has registered all WMI devices). New aggregate WMI drivers should not rely on this behaviour. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20231020211005.38216-2-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/wmi.c | 39 +++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index a78ddd83cda0..1dbef16acdeb 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1221,6 +1221,26 @@ static int wmi_create_device(struct device *wmi_bus_dev, return 0; } +static int wmi_add_device(struct platform_device *pdev, struct wmi_device *wdev) +{ + struct device_link *link; + + /* + * Many aggregate WMI drivers do not use -EPROBE_DEFER when they + * are unable to find a WMI device during probe, instead they require + * all WMI devices associated with an platform device to become available + * at once. This device link thus prevents WMI drivers from probing until + * the associated platform device has finished probing (and has registered + * all discovered WMI devices). + */ + + link = device_link_add(&wdev->dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER); + if (!link) + return -EINVAL; + + return device_add(&wdev->dev); +} + static void wmi_free_devices(struct acpi_device *device) { struct wmi_block *wblock, *next; @@ -1263,11 +1283,12 @@ static bool guid_already_parsed_for_legacy(struct acpi_device *device, const gui /* * Parse the _WDG method for the GUID data blocks */ -static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) +static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; const struct guid_block *gblock; - struct wmi_block *wblock, *next; + struct wmi_block *wblock; union acpi_object *obj; acpi_status status; int retval = 0; @@ -1317,22 +1338,14 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device) wblock->handler = wmi_notify_debug; wmi_method_enable(wblock, true); } - } - /* - * Now that all of the devices are created, add them to the - * device tree and probe subdrivers. - */ - list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { - if (wblock->acpi_device != device) - continue; - - retval = device_add(&wblock->dev.dev); + retval = wmi_add_device(pdev, &wblock->dev); if (retval) { dev_err(wmi_bus_dev, "failed to register %pUL\n", &wblock->gblock.guid); if (debug_event) wmi_method_enable(wblock, false); + list_del(&wblock->list); put_device(&wblock->dev.dev); } @@ -1487,7 +1500,7 @@ static int acpi_wmi_probe(struct platform_device *device) } dev_set_drvdata(&device->dev, wmi_bus_dev); - error = parse_wdg(wmi_bus_dev, acpi_device); + error = parse_wdg(wmi_bus_dev, device); if (error) { pr_err("Failed to parse WDG method\n"); goto err_remove_busdev; From 7444f8347487df8d898fbc022249942806c80fc9 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Fri, 20 Oct 2023 23:10:02 +0200 Subject: [PATCH 317/396] platform/x86: wmi: Fix refcounting of WMI devices in legacy functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now, legacy GUID-based functions where using find_guid() when searching for WMI devices, which did no refcounting on the returned WMI device. This meant that the WMI device could disappear at any moment, potentially leading to various errors. Fix this by using bus_find_device() which returns an actual reference to the found WMI device. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20231020211005.38216-3-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/wmi.c | 167 ++++++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 60 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 1dbef16acdeb..e3984801883a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -109,33 +109,13 @@ static const char * const allow_duplicates[] = { NULL }; +#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev) +#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev) + /* * GUID parsing functions */ -static acpi_status find_guid(const char *guid_string, struct wmi_block **out) -{ - guid_t guid_input; - struct wmi_block *wblock; - - if (!guid_string) - return AE_BAD_PARAMETER; - - if (guid_parse(guid_string, &guid_input)) - return AE_BAD_PARAMETER; - - list_for_each_entry(wblock, &wmi_block_list, list) { - if (guid_equal(&wblock->gblock.guid, &guid_input)) { - if (out) - *out = wblock; - - return AE_OK; - } - } - - return AE_NOT_FOUND; -} - static bool guid_parse_and_compare(const char *string, const guid_t *guid) { guid_t guid_input; @@ -245,6 +225,41 @@ static acpi_status get_event_data(const struct wmi_block *wblock, struct acpi_bu return acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, out); } +static int wmidev_match_guid(struct device *dev, const void *data) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + const guid_t *guid = data; + + if (guid_equal(guid, &wblock->gblock.guid)) + return 1; + + return 0; +} + +static struct bus_type wmi_bus_type; + +static struct wmi_device *wmi_find_device_by_guid(const char *guid_string) +{ + struct device *dev; + guid_t guid; + int ret; + + ret = guid_parse(guid_string, &guid); + if (ret < 0) + return ERR_PTR(ret); + + dev = bus_find_device(&wmi_bus_type, NULL, &guid, wmidev_match_guid); + if (!dev) + return ERR_PTR(-ENODEV); + + return dev_to_wdev(dev); +} + +static void wmi_device_put(struct wmi_device *wdev) +{ + put_device(&wdev->dev); +} + /* * Exported WMI functions */ @@ -279,18 +294,17 @@ EXPORT_SYMBOL_GPL(set_required_buffer_size); */ int wmi_instance_count(const char *guid_string) { - struct wmi_block *wblock; - acpi_status status; + struct wmi_device *wdev; + int ret; - status = find_guid(guid_string, &wblock); - if (ACPI_FAILURE(status)) { - if (status == AE_BAD_PARAMETER) - return -EINVAL; + wdev = wmi_find_device_by_guid(guid_string); + if (IS_ERR(wdev)) + return PTR_ERR(wdev); - return -ENODEV; - } + ret = wmidev_instance_count(wdev); + wmi_device_put(wdev); - return wmidev_instance_count(&wblock->dev); + return ret; } EXPORT_SYMBOL_GPL(wmi_instance_count); @@ -325,15 +339,18 @@ EXPORT_SYMBOL_GPL(wmidev_instance_count); acpi_status wmi_evaluate_method(const char *guid_string, u8 instance, u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) { - struct wmi_block *wblock = NULL; + struct wmi_device *wdev; acpi_status status; - status = find_guid(guid_string, &wblock); - if (ACPI_FAILURE(status)) - return status; + wdev = wmi_find_device_by_guid(guid_string); + if (IS_ERR(wdev)) + return AE_ERROR; - return wmidev_evaluate_method(&wblock->dev, instance, method_id, - in, out); + status = wmidev_evaluate_method(wdev, instance, method_id, in, out); + + wmi_device_put(wdev); + + return status; } EXPORT_SYMBOL_GPL(wmi_evaluate_method); @@ -472,13 +489,19 @@ acpi_status wmi_query_block(const char *guid_string, u8 instance, struct acpi_buffer *out) { struct wmi_block *wblock; + struct wmi_device *wdev; acpi_status status; - status = find_guid(guid_string, &wblock); - if (ACPI_FAILURE(status)) - return status; + wdev = wmi_find_device_by_guid(guid_string); + if (IS_ERR(wdev)) + return AE_ERROR; - return __query_block(wblock, instance, out); + wblock = container_of(wdev, struct wmi_block, dev); + status = __query_block(wblock, instance, out); + + wmi_device_put(wdev); + + return status; } EXPORT_SYMBOL_GPL(wmi_query_block); @@ -516,8 +539,9 @@ EXPORT_SYMBOL_GPL(wmidev_block_query); acpi_status wmi_set_block(const char *guid_string, u8 instance, const struct acpi_buffer *in) { - struct wmi_block *wblock = NULL; + struct wmi_block *wblock; struct guid_block *block; + struct wmi_device *wdev; acpi_handle handle; struct acpi_object_list input; union acpi_object params[2]; @@ -527,19 +551,26 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, if (!in) return AE_BAD_DATA; - status = find_guid(guid_string, &wblock); - if (ACPI_FAILURE(status)) - return status; + wdev = wmi_find_device_by_guid(guid_string); + if (IS_ERR(wdev)) + return AE_ERROR; + wblock = container_of(wdev, struct wmi_block, dev); block = &wblock->gblock; handle = wblock->acpi_device->handle; - if (block->instance_count <= instance) - return AE_BAD_PARAMETER; + if (block->instance_count <= instance) { + status = AE_BAD_PARAMETER; + + goto err_wdev_put; + } /* Check GUID is a data block */ - if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) - return AE_ERROR; + if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD)) { + status = AE_ERROR; + + goto err_wdev_put; + } input.count = 2; input.pointer = params; @@ -551,7 +582,12 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, get_acpi_method_name(wblock, 'S', method); - return acpi_evaluate_object(handle, method, &input, NULL); + status = acpi_evaluate_object(handle, method, &input, NULL); + +err_wdev_put: + wmi_device_put(wdev); + + return status; } EXPORT_SYMBOL_GPL(wmi_set_block); @@ -742,7 +778,15 @@ EXPORT_SYMBOL_GPL(wmi_get_event_data); */ bool wmi_has_guid(const char *guid_string) { - return ACPI_SUCCESS(find_guid(guid_string, NULL)); + struct wmi_device *wdev; + + wdev = wmi_find_device_by_guid(guid_string); + if (IS_ERR(wdev)) + return false; + + wmi_device_put(wdev); + + return true; } EXPORT_SYMBOL_GPL(wmi_has_guid); @@ -756,20 +800,23 @@ EXPORT_SYMBOL_GPL(wmi_has_guid); */ char *wmi_get_acpi_device_uid(const char *guid_string) { - struct wmi_block *wblock = NULL; - acpi_status status; + struct wmi_block *wblock; + struct wmi_device *wdev; + char *uid; - status = find_guid(guid_string, &wblock); - if (ACPI_FAILURE(status)) + wdev = wmi_find_device_by_guid(guid_string); + if (IS_ERR(wdev)) return NULL; - return acpi_device_uid(wblock->acpi_device); + wblock = container_of(wdev, struct wmi_block, dev); + uid = acpi_device_uid(wblock->acpi_device); + + wmi_device_put(wdev); + + return uid; } EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid); -#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev) -#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev) - static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv) { return container_of(drv, struct wmi_driver, driver); From ed85891a276edaf7a867de0e9acd0837bc3008f2 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Fri, 20 Oct 2023 23:10:03 +0200 Subject: [PATCH 318/396] platform/x86: wmi: Fix probe failure when failing to register WMI devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a WMI device besides the first one somehow fails to register, retval is returned while still containing a negative error code. This causes the ACPI device fail to probe, leaving behind zombie WMI devices leading to various errors later. Handle the single error path separately and return 0 unconditionally after trying to register all WMI devices to solve the issue. Also continue to register WMI devices even if some fail to allocate memory. Fixes: 6ee50aaa9a20 ("platform/x86: wmi: Instantiate all devices before adding them") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20231020211005.38216-4-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/wmi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index e3984801883a..ab24ea9ffc9a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1338,8 +1338,8 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev) struct wmi_block *wblock; union acpi_object *obj; acpi_status status; - int retval = 0; u32 i, total; + int retval; status = acpi_evaluate_object(device->handle, "_WDG", NULL, &out); if (ACPI_FAILURE(status)) @@ -1350,8 +1350,8 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev) return -ENXIO; if (obj->type != ACPI_TYPE_BUFFER) { - retval = -ENXIO; - goto out_free_pointer; + kfree(obj); + return -ENXIO; } gblock = (const struct guid_block *)obj->buffer.pointer; @@ -1366,8 +1366,8 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev) wblock = kzalloc(sizeof(*wblock), GFP_KERNEL); if (!wblock) { - retval = -ENOMEM; - break; + dev_err(wmi_bus_dev, "Failed to allocate %pUL\n", &gblock[i].guid); + continue; } wblock->acpi_device = device; @@ -1398,9 +1398,9 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev) } } -out_free_pointer: - kfree(out.pointer); - return retval; + kfree(obj); + + return 0; } /* From eba9ac7abab91c8f6d351460239108bef5e7a0b6 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Fri, 20 Oct 2023 23:10:04 +0200 Subject: [PATCH 319/396] platform/x86: wmi: Fix opening of char device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit fa1f68db6ca7 ("drivers: misc: pass miscdevice pointer via file private data"), the miscdevice stores a pointer to itself inside filp->private_data, which means that private_data will not be NULL when wmi_char_open() is called. This might cause memory corruption should wmi_char_open() be unable to find its driver, something which can happen when the associated WMI device is deleted in wmi_free_devices(). Fix the problem by using the miscdevice pointer to retrieve the WMI device data associated with a char device using container_of(). This also avoids wmi_char_open() picking a wrong WMI device bound to a driver with the same name as the original driver. Fixes: 44b6b7661132 ("platform/x86: wmi: create userspace interface for drivers") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20231020211005.38216-5-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/wmi.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index ab24ea9ffc9a..6b3b2fe464d2 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -958,21 +958,13 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver) } static int wmi_char_open(struct inode *inode, struct file *filp) { - const char *driver_name = filp->f_path.dentry->d_iname; - struct wmi_block *wblock; - struct wmi_block *next; + /* + * The miscdevice already stores a pointer to itself + * inside filp->private_data + */ + struct wmi_block *wblock = container_of(filp->private_data, struct wmi_block, char_dev); - list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { - if (!wblock->dev.dev.driver) - continue; - if (strcmp(driver_name, wblock->dev.dev.driver->name) == 0) { - filp->private_data = wblock; - break; - } - } - - if (!filp->private_data) - return -ENODEV; + filp->private_data = wblock; return nonseekable_open(inode, filp); } From ac9bc85c49ffcfca8c1b117e1a9e94dd32680c68 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Fri, 20 Oct 2023 23:10:05 +0200 Subject: [PATCH 320/396] platform/x86: wmi: Decouple WMI device removal from wmi_block_list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use device_for_each_child_reverse() to find and unregister WMI devices belonging to a WMI bus device instead of iterating thru the entire wmi_block_list. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20231020211005.38216-6-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/wmi.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 6b3b2fe464d2..5c27b4aa9690 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -1280,19 +1280,6 @@ static int wmi_add_device(struct platform_device *pdev, struct wmi_device *wdev) return device_add(&wdev->dev); } -static void wmi_free_devices(struct acpi_device *device) -{ - struct wmi_block *wblock, *next; - - /* Delete devices for all the GUIDs */ - list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { - if (wblock->acpi_device == device) { - list_del(&wblock->list); - device_unregister(&wblock->dev.dev); - } - } -} - static bool guid_already_parsed_for_legacy(struct acpi_device *device, const guid_t *guid) { struct wmi_block *wblock; @@ -1487,16 +1474,28 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, event, 0); } +static int wmi_remove_device(struct device *dev, void *data) +{ + struct wmi_block *wblock = dev_to_wblock(dev); + + list_del(&wblock->list); + device_unregister(dev); + + return 0; +} + static void acpi_wmi_remove(struct platform_device *device) { struct acpi_device *acpi_device = ACPI_COMPANION(&device->dev); + struct device *wmi_bus_device = dev_get_drvdata(&device->dev); acpi_remove_notify_handler(acpi_device->handle, ACPI_ALL_NOTIFY, acpi_wmi_notify_handler); acpi_remove_address_space_handler(acpi_device->handle, ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); - wmi_free_devices(acpi_device); - device_unregister(dev_get_drvdata(&device->dev)); + + device_for_each_child_reverse(wmi_bus_device, NULL, wmi_remove_device); + device_unregister(wmi_bus_device); } static int acpi_wmi_probe(struct platform_device *device) From 2a5b3370a1d9750eca325292e291c8c7cb8cf2e0 Mon Sep 17 00:00:00 2001 From: Dragos Bogdan Date: Wed, 25 Oct 2023 15:21:00 +0200 Subject: [PATCH 321/396] hwmon: (axi-fan-control) Fix possible NULL pointer dereference axi_fan_control_irq_handler(), dependent on the private axi_fan_control_data structure, might be called before the hwmon device is registered. That will cause an "Unable to handle kernel NULL pointer dereference" error. Fixes: 8412b410fa5e ("hwmon: Support ADI Fan Control IP") Signed-off-by: Dragos Bogdan Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20231025132100.649499-1-nuno.sa@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/axi-fan-control.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c index 5fd136baf1cd..19b9bf3d75ef 100644 --- a/drivers/hwmon/axi-fan-control.c +++ b/drivers/hwmon/axi-fan-control.c @@ -496,6 +496,21 @@ static int axi_fan_control_probe(struct platform_device *pdev) return -ENODEV; } + ret = axi_fan_control_init(ctl, pdev->dev.of_node); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize device\n"); + return ret; + } + + ctl->hdev = devm_hwmon_device_register_with_info(&pdev->dev, + name, + ctl, + &axi_chip_info, + axi_fan_control_groups); + + if (IS_ERR(ctl->hdev)) + return PTR_ERR(ctl->hdev); + ctl->irq = platform_get_irq(pdev, 0); if (ctl->irq < 0) return ctl->irq; @@ -509,19 +524,7 @@ static int axi_fan_control_probe(struct platform_device *pdev) return ret; } - ret = axi_fan_control_init(ctl, pdev->dev.of_node); - if (ret) { - dev_err(&pdev->dev, "Failed to initialize device\n"); - return ret; - } - - ctl->hdev = devm_hwmon_device_register_with_info(&pdev->dev, - name, - ctl, - &axi_chip_info, - axi_fan_control_groups); - - return PTR_ERR_OR_ZERO(ctl->hdev); + return 0; } static struct platform_driver axi_fan_control_driver = { From bbfff736d30e5283ad09e748caff979d75ddef7f Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 25 Oct 2023 20:23:16 +0800 Subject: [PATCH 322/396] hwmon: (coretemp) Fix potentially truncated sysfs attribute name When build with W=1 and "-Werror=format-truncation", below error is observed in coretemp driver, drivers/hwmon/coretemp.c: In function 'create_core_data': >> drivers/hwmon/coretemp.c:393:34: error: '%s' directive output may be truncated writing likely 5 or more bytes into a region of size between 3 and 13 [-Werror=format-truncation=] 393 | "temp%d_%s", attr_no, suffixes[i]); | ^~ drivers/hwmon/coretemp.c:393:26: note: assuming directive output of 5 bytes 393 | "temp%d_%s", attr_no, suffixes[i]); | ^~~~~~~~~~~ drivers/hwmon/coretemp.c:392:17: note: 'snprintf' output 7 or more bytes (assuming 22) into a destination of size 19 392 | snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 393 | "temp%d_%s", attr_no, suffixes[i]); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors Given that 1. '%d' could take 10 charactors, 2. '%s' could take 10 charactors ("crit_alarm"), 3. "temp", "_" and the NULL terminator take 6 charactors, fix the problem by increasing CORETEMP_NAME_LENGTH to 28. Signed-off-by: Zhang Rui Fixes: 7108b80a542b ("hwmon/coretemp: Handle large core ID value") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310200443.iD3tUbbK-lkp@intel.com/ Link: https://lore.kernel.org/r/20231025122316.836400-1-rui.zhang@intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index eba94f68585a..ba82d1e79c13 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -42,7 +42,7 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); #define PKG_SYSFS_ATTR_NO 1 /* Sysfs attribute for package temp */ #define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */ #define NUM_REAL_CORES 128 /* Number of Real cores per cpu */ -#define CORETEMP_NAME_LENGTH 19 /* String Length of attrs */ +#define CORETEMP_NAME_LENGTH 28 /* String Length of attrs */ #define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */ #define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) From 920057ad521dc8669e534736c2a12c14ec9fb2d7 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Fri, 29 Sep 2023 13:08:23 -0700 Subject: [PATCH 323/396] hwmon: (nct6775) Fix incorrect variable reuse in fan_div calculation In the regmap conversion in commit 4ef2774511dc ("hwmon: (nct6775) Convert register access to regmap API") I reused the 'reg' variable for all three register reads in the fan speed calculation loop in nct6775_update_device(), but failed to notice that the value from the first one (data->REG_FAN[i]) is actually used in the call to nct6775_select_fan_div() at the end of the loop body. Since that patch the register value passed to nct6775_select_fan_div() has been (conditionally) incorrectly clobbered with the value of a different register than intended, which has in at least some cases resulted in fan speeds being adjusted down to zero. Fix this by using dedicated temporaries for the two intermediate register reads instead of 'reg'. Signed-off-by: Zev Weiss Fixes: 4ef2774511dc ("hwmon: (nct6775) Convert register access to regmap API") Reported-by: Thomas Zajic Tested-by: Thomas Zajic Cc: stable@vger.kernel.org # v5.19+ Link: https://lore.kernel.org/r/20230929200822.964-2-zev@bewilderbeest.net Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775-core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index b5b81bd83bb1..d928eb8ae5a3 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -1614,17 +1614,21 @@ struct nct6775_data *nct6775_update_device(struct device *dev) data->fan_div[i]); if (data->has_fan_min & BIT(i)) { - err = nct6775_read_value(data, data->REG_FAN_MIN[i], ®); + u16 tmp; + + err = nct6775_read_value(data, data->REG_FAN_MIN[i], &tmp); if (err) goto out; - data->fan_min[i] = reg; + data->fan_min[i] = tmp; } if (data->REG_FAN_PULSES[i]) { - err = nct6775_read_value(data, data->REG_FAN_PULSES[i], ®); + u16 tmp; + + err = nct6775_read_value(data, data->REG_FAN_PULSES[i], &tmp); if (err) goto out; - data->fan_pulses[i] = (reg >> data->FAN_PULSE_SHIFT[i]) & 0x03; + data->fan_pulses[i] = (tmp >> data->FAN_PULSE_SHIFT[i]) & 0x03; } err = nct6775_select_fan_div(dev, data, i, reg); From 28da9dee3594423534f3ea1e1f61e6bb2d2fa651 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 25 Oct 2023 14:28:49 -0700 Subject: [PATCH 324/396] Revert "hwmon: (sch56xx-common) Add DMI override table" This reverts commit fd2d53c367ae9983c2100ac733a834e0c79d7537. As reported by Ian Nartowicz, this and the preceding patch result in a failure to load the driver on Celsius W280. While the alternative would be to add the board to the DMI override table, it is quite likely that other systems are also affected. Revert the offending patches to avoid future problems. Fixes: fd2d53c367ae ("hwmon: (sch56xx-common) Add DMI override table") Reported-by: Ian Nartowicz Closes: https://lore.kernel.org/linux-hwmon/20231025192239.3c5389ae@debian.org/T/#t Cc: Armin Wolf Signed-off-by: Guenter Roeck --- drivers/hwmon/sch56xx-common.c | 44 ++++++++-------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index de3a0886c2f7..3ece53adabd6 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -523,28 +523,6 @@ static int __init sch56xx_device_add(int address, const char *name) return PTR_ERR_OR_ZERO(sch56xx_pdev); } -static const struct dmi_system_id sch56xx_dmi_override_table[] __initconst = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS W380"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO P710"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO E9900"), - }, - }, - { } -}; - /* For autoloading only */ static const struct dmi_system_id sch56xx_dmi_table[] __initconst = { { @@ -565,18 +543,16 @@ static int __init sch56xx_init(void) if (!dmi_check_system(sch56xx_dmi_table)) return -ENODEV; - if (!dmi_check_system(sch56xx_dmi_override_table)) { - /* - * Some machines like the Esprimo P720 and Esprimo C700 have - * onboard devices named " Antiope"/" Theseus" instead of - * "Antiope"/"Theseus", so we need to check for both. - */ - if (!dmi_find_device(DMI_DEV_TYPE_OTHER, "Antiope", NULL) && - !dmi_find_device(DMI_DEV_TYPE_OTHER, " Antiope", NULL) && - !dmi_find_device(DMI_DEV_TYPE_OTHER, "Theseus", NULL) && - !dmi_find_device(DMI_DEV_TYPE_OTHER, " Theseus", NULL)) - return -ENODEV; - } + /* + * Some machines like the Esprimo P720 and Esprimo C700 have + * onboard devices named " Antiope"/" Theseus" instead of + * "Antiope"/"Theseus", so we need to check for both. + */ + if (!dmi_find_device(DMI_DEV_TYPE_OTHER, "Antiope", NULL) && + !dmi_find_device(DMI_DEV_TYPE_OTHER, " Antiope", NULL) && + !dmi_find_device(DMI_DEV_TYPE_OTHER, "Theseus", NULL) && + !dmi_find_device(DMI_DEV_TYPE_OTHER, " Theseus", NULL)) + return -ENODEV; } /* From d621a46d05107f4e510383d6a38f2160c62d28f7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 25 Oct 2023 14:32:40 -0700 Subject: [PATCH 325/396] Revert "hwmon: (sch56xx-common) Add automatic module loading on supported devices" This reverts commit 393935baa45e5ccb9603cf7f9f020ed1bc0915f7. As reported by Ian Nartowicz, this and the next patch result in a failure to load the driver on Celsius W280. While the alternative would be to add the board to the DMI override table, it is quite likely that other systems are also affected. Revert the offending patches to avoid future problems. Fixes: 393935baa45e ("hwmon: (sch56xx-common) Add automatic module loading on supported devices") Reported-by: Ian Nartowicz Closes: https://lore.kernel.org/linux-hwmon/20231025192239.3c5389ae@debian.org/T/#t Cc: Armin Wolf Signed-off-by: Guenter Roeck --- drivers/hwmon/sch56xx-common.c | 40 ++-------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index 3ece53adabd6..ac1f72580715 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -7,10 +7,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include -#include #include #include #include @@ -21,10 +19,7 @@ #include #include "sch56xx-common.h" -static bool ignore_dmi; -module_param(ignore_dmi, bool, 0); -MODULE_PARM_DESC(ignore_dmi, "Omit DMI check for supported devices (default=0)"); - +/* Insmod parameters */ static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" @@ -523,42 +518,11 @@ static int __init sch56xx_device_add(int address, const char *name) return PTR_ERR_OR_ZERO(sch56xx_pdev); } -/* For autoloading only */ -static const struct dmi_system_id sch56xx_dmi_table[] __initconst = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), - }, - }, - { } -}; -MODULE_DEVICE_TABLE(dmi, sch56xx_dmi_table); - static int __init sch56xx_init(void) { - const char *name = NULL; int address; + const char *name = NULL; - if (!ignore_dmi) { - if (!dmi_check_system(sch56xx_dmi_table)) - return -ENODEV; - - /* - * Some machines like the Esprimo P720 and Esprimo C700 have - * onboard devices named " Antiope"/" Theseus" instead of - * "Antiope"/"Theseus", so we need to check for both. - */ - if (!dmi_find_device(DMI_DEV_TYPE_OTHER, "Antiope", NULL) && - !dmi_find_device(DMI_DEV_TYPE_OTHER, " Antiope", NULL) && - !dmi_find_device(DMI_DEV_TYPE_OTHER, "Theseus", NULL) && - !dmi_find_device(DMI_DEV_TYPE_OTHER, " Theseus", NULL)) - return -ENODEV; - } - - /* - * Some devices like the Esprimo C700 have both onboard devices, - * so we still have to check manually - */ address = sch56xx_find(0x4e, &name); if (address < 0) address = sch56xx_find(0x2e, &name); From 916646758aea81a143ce89103910f715ed923346 Mon Sep 17 00:00:00 2001 From: Olli Asikainen Date: Tue, 24 Oct 2023 22:09:21 +0300 Subject: [PATCH 326/396] platform/x86: thinkpad_acpi: Add battery quirk for Thinkpad X120e MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thinkpad X120e also needs this battery quirk. Signed-off-by: Olli Asikainen Link: https://lore.kernel.org/r/20231024190922.2742-1-olli.asikainen@gmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index c3499bf60582..fce16b016e88 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9814,6 +9814,7 @@ static const struct tpacpi_quirk battery_quirk_table[] __initconst = { * Individual addressing is broken on models that expose the * primary battery as BAT1. */ + TPACPI_Q_LNV('8', 'F', true), /* Thinkpad X120e */ TPACPI_Q_LNV('J', '7', true), /* B5400 */ TPACPI_Q_LNV('J', 'I', true), /* Thinkpad 11e */ TPACPI_Q_LNV3('R', '0', 'B', true), /* Thinkpad 11e gen 3 */ From 94ace9eda88229c73698b8dd8d3c06dd0831319c Mon Sep 17 00:00:00 2001 From: Ai Chao Date: Fri, 20 Oct 2023 10:40:07 +0800 Subject: [PATCH 327/396] platform/x86: inspur-platform-profile: Add platform profile support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Inspur platforms to used the platform profile feature. This will allow users to determine and control the platform modes between low-power, balanced and performance modes. Signed-off-by: Ai Chao Reviewed-by: Thomas Weißschuh Reviewed-by: Armin Wolf Link: https://lore.kernel.org/r/20231020024007.1677962-1-aichao@kylinos.cn [ij: Removed kerneldoc markers from non-kerneldoc comments.] Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/Kconfig | 11 + drivers/platform/x86/Makefile | 3 + .../platform/x86/inspur_platform_profile.c | 216 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 drivers/platform/x86/inspur_platform_profile.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 2a1070543391..7e69fdaccdd5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -988,6 +988,17 @@ config TOUCHSCREEN_DMI the OS-image for the device. This option supplies the missing info. Enable this for x86 tablets with Silead or Chipone touchscreens. +config INSPUR_PLATFORM_PROFILE + tristate "Inspur WMI platform profile driver" + depends on ACPI_WMI + select ACPI_PLATFORM_PROFILE + help + This will allow users to determine and control the platform modes + between low-power, balanced and performance modes. + + To compile this driver as a module, choose M here: the module + will be called inspur-platform-profile. + source "drivers/platform/x86/x86-android-tablets/Kconfig" config FW_ATTR_CLASS diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index b457de5abf7d..c7a18e95ad8c 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -98,6 +98,9 @@ obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o # before toshiba_acpi initializes obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o +# Inspur +obj-$(CONFIG_INSPUR_PLATFORM_PROFILE) += inspur_platform_profile.o + # Laptop drivers obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o diff --git a/drivers/platform/x86/inspur_platform_profile.c b/drivers/platform/x86/inspur_platform_profile.c new file mode 100644 index 000000000000..743705bddda3 --- /dev/null +++ b/drivers/platform/x86/inspur_platform_profile.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Inspur WMI Platform Profile + * + * Copyright (C) 2018 Ai Chao + */ + +#include +#include +#include +#include +#include + +#define WMI_INSPUR_POWERMODE_BIOS_GUID "596C31E3-332D-43C9-AEE9-585493284F5D" + +enum inspur_wmi_method_ids { + INSPUR_WMI_GET_POWERMODE = 0x02, + INSPUR_WMI_SET_POWERMODE = 0x03, +}; + +/* + * Power Mode: + * 0x0: Balance Mode + * 0x1: Performance Mode + * 0x2: Power Saver Mode + */ +enum inspur_tmp_profile { + INSPUR_TMP_PROFILE_BALANCE = 0, + INSPUR_TMP_PROFILE_PERFORMANCE = 1, + INSPUR_TMP_PROFILE_POWERSAVE = 2, +}; + +struct inspur_wmi_priv { + struct wmi_device *wdev; + struct platform_profile_handler handler; +}; + +static int inspur_wmi_perform_query(struct wmi_device *wdev, + enum inspur_wmi_method_ids query_id, + void *buffer, size_t insize, + size_t outsize) +{ + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer input = { insize, buffer}; + union acpi_object *obj; + acpi_status status; + int ret = 0; + + status = wmidev_evaluate_method(wdev, 0, query_id, &input, &output); + if (ACPI_FAILURE(status)) { + dev_err(&wdev->dev, "EC Powermode control failed: %s\n", + acpi_format_exception(status)); + return -EIO; + } + + obj = output.pointer; + if (!obj) + return -EINVAL; + + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length != outsize) { + ret = -EINVAL; + goto out_free; + } + + memcpy(buffer, obj->buffer.pointer, obj->buffer.length); + +out_free: + kfree(obj); + return ret; +} + +/* + * Set Power Mode to EC RAM. If Power Mode value greater than 0x3, + * return error + * Method ID: 0x3 + * Arg: 4 Bytes + * Byte [0]: Power Mode: + * 0x0: Balance Mode + * 0x1: Performance Mode + * 0x2: Power Saver Mode + * Return Value: 4 Bytes + * Byte [0]: Return Code + * 0x0: No Error + * 0x1: Error + */ +static int inspur_platform_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) +{ + struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv, + handler); + u8 ret_code[4] = {0, 0, 0, 0}; + int ret; + + switch (profile) { + case PLATFORM_PROFILE_BALANCED: + ret_code[0] = INSPUR_TMP_PROFILE_BALANCE; + break; + case PLATFORM_PROFILE_PERFORMANCE: + ret_code[0] = INSPUR_TMP_PROFILE_PERFORMANCE; + break; + case PLATFORM_PROFILE_LOW_POWER: + ret_code[0] = INSPUR_TMP_PROFILE_POWERSAVE; + break; + default: + return -EOPNOTSUPP; + } + + ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_SET_POWERMODE, + ret_code, sizeof(ret_code), + sizeof(ret_code)); + + if (ret < 0) + return ret; + + if (ret_code[0]) + return -EBADRQC; + + return 0; +} + +/* + * Get Power Mode from EC RAM, If Power Mode value greater than 0x3, + * return error + * Method ID: 0x2 + * Return Value: 4 Bytes + * Byte [0]: Return Code + * 0x0: No Error + * 0x1: Error + * Byte [1]: Power Mode + * 0x0: Balance Mode + * 0x1: Performance Mode + * 0x2: Power Saver Mode + */ +static int inspur_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) +{ + struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv, + handler); + u8 ret_code[4] = {0, 0, 0, 0}; + int ret; + + ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_GET_POWERMODE, + &ret_code, sizeof(ret_code), + sizeof(ret_code)); + if (ret < 0) + return ret; + + if (ret_code[0]) + return -EBADRQC; + + switch (ret_code[1]) { + case INSPUR_TMP_PROFILE_BALANCE: + *profile = PLATFORM_PROFILE_BALANCED; + break; + case INSPUR_TMP_PROFILE_PERFORMANCE: + *profile = PLATFORM_PROFILE_PERFORMANCE; + break; + case INSPUR_TMP_PROFILE_POWERSAVE: + *profile = PLATFORM_PROFILE_LOW_POWER; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int inspur_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct inspur_wmi_priv *priv; + + priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->wdev = wdev; + dev_set_drvdata(&wdev->dev, priv); + + priv->handler.profile_get = inspur_platform_profile_get; + priv->handler.profile_set = inspur_platform_profile_set; + + set_bit(PLATFORM_PROFILE_LOW_POWER, priv->handler.choices); + set_bit(PLATFORM_PROFILE_BALANCED, priv->handler.choices); + set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->handler.choices); + + return platform_profile_register(&priv->handler); +} + +static void inspur_wmi_remove(struct wmi_device *wdev) +{ + platform_profile_remove(); +} + +static const struct wmi_device_id inspur_wmi_id_table[] = { + { .guid_string = WMI_INSPUR_POWERMODE_BIOS_GUID }, + { } +}; + +MODULE_DEVICE_TABLE(wmi, inspur_wmi_id_table); + +static struct wmi_driver inspur_wmi_driver = { + .driver = { + .name = "inspur-wmi-platform-profile", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .id_table = inspur_wmi_id_table, + .probe = inspur_wmi_probe, + .remove = inspur_wmi_remove, +}; + +module_wmi_driver(inspur_wmi_driver); + +MODULE_AUTHOR("Ai Chao "); +MODULE_DESCRIPTION("Platform Profile Support for Inspur"); +MODULE_LICENSE("GPL"); From 9da2901c47332b030ea4d2a2302bc7c0b83fc67c Mon Sep 17 00:00:00 2001 From: Naresh Solanki Date: Fri, 27 Oct 2023 10:33:52 +0000 Subject: [PATCH 328/396] hwmon: (pmbus/mp2975) Move PGOOD fix The PGOOD fix was intended for MP2973 & MP2971 & not for MP2975. Fixes: acda945afb46 ("hwmon: (pmbus/mp2975) Fix PGOOD in READ_STATUS_WORD") Signed-off-by: Naresh Solanki Link: https://lore.kernel.org/r/20231027103352.918895-1-naresh.solanki@9elements.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/mp2975.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c index 26ba50633100..b9bb469e2d8f 100644 --- a/drivers/hwmon/pmbus/mp2975.c +++ b/drivers/hwmon/pmbus/mp2975.c @@ -297,6 +297,11 @@ static int mp2973_read_word_data(struct i2c_client *client, int page, int ret; switch (reg) { + case PMBUS_STATUS_WORD: + /* MP2973 & MP2971 return PGOOD instead of PB_STATUS_POWER_GOOD_N. */ + ret = pmbus_read_word_data(client, page, phase, reg); + ret ^= PB_STATUS_POWER_GOOD_N; + break; case PMBUS_OT_FAULT_LIMIT: ret = mp2975_read_word_helper(client, page, phase, reg, GENMASK(7, 0)); @@ -380,11 +385,6 @@ static int mp2975_read_word_data(struct i2c_client *client, int page, int ret; switch (reg) { - case PMBUS_STATUS_WORD: - /* MP2973 & MP2971 return PGOOD instead of PB_STATUS_POWER_GOOD_N. */ - ret = pmbus_read_word_data(client, page, phase, reg); - ret ^= PB_STATUS_POWER_GOOD_N; - break; case PMBUS_OT_FAULT_LIMIT: ret = mp2975_read_word_helper(client, page, phase, reg, GENMASK(7, 0)); From 4381a36abdf1c5c0323c1c51f869dc000115eb20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sat, 2 Sep 2023 09:47:01 +0200 Subject: [PATCH 329/396] hwmon: add POWER-Z driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POWER-Z is a series of devices to monitor power characteristics of USB-C connections and display those on a on-device display. Some of the devices, notably KM002C and KM003C, contain an additional port which exposes the measurements via USB. This is a driver for this monitor port. It was developed and tested with the KM003C. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20230902-powerz-v4-1-7ec2c1440687@weissschuh.net [groeck: Release urb after hwmon registration error; Move priv->status initialization to correct place before reinit_completion ] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/powerz.rst | 30 ++++ MAINTAINERS | 7 + drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/powerz.c | 274 +++++++++++++++++++++++++++++++++ 6 files changed, 323 insertions(+) create mode 100644 Documentation/hwmon/powerz.rst create mode 100644 drivers/hwmon/powerz.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 88dadea85cfc..10a54644557d 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -178,6 +178,7 @@ Hardware Monitoring Kernel Drivers peci-cputemp peci-dimmtemp pmbus + powerz powr1220 pxe1610 pwm-fan diff --git a/Documentation/hwmon/powerz.rst b/Documentation/hwmon/powerz.rst new file mode 100644 index 000000000000..317084e0b76b --- /dev/null +++ b/Documentation/hwmon/powerz.rst @@ -0,0 +1,30 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver POWERZ +==================== + +Supported chips: + + * ChargerLAB POWER-Z KM003C + + Prefix: 'powerz' + + Addresses scanned: - + +Author: + + - Thomas Weißschuh + +Description +----------- + +This driver implements support for the ChargerLAB POWER-Z USB-C power testing +family. + +The device communicates with the custom protocol over USB. + +The channel labels exposed via hwmon match the labels used by the on-device +display and the official POWER-Z PC software. + +As current can flow in both directions through the tester the sign of the +channel "curr1_input" (label "IBUS") indicates the direction. diff --git a/MAINTAINERS b/MAINTAINERS index b19995690904..44d394dc97c7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4794,6 +4794,13 @@ X: drivers/char/ipmi/ X: drivers/char/random.c X: drivers/char/tpm/ +CHARGERLAB POWER-Z HARDWARE MONITOR DRIVER +M: Thomas Weißschuh +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/powerz.rst +F: drivers/hwmon/powerz.c + CHECKPATCH M: Andy Whitcroft M: Joe Perches diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ec38c8892158..12af9f9cfd9f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -839,6 +839,16 @@ config SENSORS_JC42 This driver can also be built as a module. If so, the module will be called jc42. +config SENSORS_POWERZ + tristate "ChargerLAB POWER-Z USB-C tester" + depends on USB + help + If you say yes here you get support for ChargerLAB POWER-Z series of + USB-C charging testers. + + This driver can also be built as a module. If so, the module + will be called powerz. + config SENSORS_POWR1220 tristate "Lattice POWR1220 Power Monitoring" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 4ac9452b5430..019189500e5d 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -176,6 +176,7 @@ obj-$(CONFIG_SENSORS_OXP) += oxp-sensors.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o +obj-$(CONFIG_SENSORS_POWERZ) += powerz.o obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o diff --git a/drivers/hwmon/powerz.c b/drivers/hwmon/powerz.c new file mode 100644 index 000000000000..2b9693aee6f6 --- /dev/null +++ b/drivers/hwmon/powerz.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 Thomas Weißschuh + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "powerz" +#define POWERZ_EP_CMD_OUT 0x01 +#define POWERZ_EP_DATA_IN 0x81 + +struct powerz_sensor_data { + u8 _unknown_1[8]; + __le32 V_bus; + __le32 I_bus; + __le32 V_bus_avg; + __le32 I_bus_avg; + u8 _unknown_2[8]; + u8 temp[2]; + __le16 V_cc1; + __le16 V_cc2; + __le16 V_dp; + __le16 V_dm; + __le16 V_dd; + u8 _unknown_3[4]; +} __packed; + +struct powerz_priv { + char transfer_buffer[64]; /* first member to satisfy DMA alignment */ + struct mutex mutex; + struct completion completion; + struct urb *urb; + int status; +}; + +static const struct hwmon_channel_info *const powerz_info[] = { + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_AVERAGE, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_AVERAGE), + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL), + NULL +}; + +static umode_t powerz_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + return 0444; +} + +static int powerz_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + if (type == hwmon_curr && attr == hwmon_curr_label) { + *str = "IBUS"; + } else if (type == hwmon_in && attr == hwmon_in_label) { + if (channel == 0) + *str = "VBUS"; + else if (channel == 1) + *str = "VCC1"; + else if (channel == 2) + *str = "VCC2"; + else if (channel == 3) + *str = "VDP"; + else if (channel == 4) + *str = "VDM"; + else if (channel == 5) + *str = "VDD"; + else + return -EOPNOTSUPP; + } else if (type == hwmon_temp && attr == hwmon_temp_label) { + *str = "TEMP"; + } else { + return -EOPNOTSUPP; + } + + return 0; +} + +static void powerz_usb_data_complete(struct urb *urb) +{ + struct powerz_priv *priv = urb->context; + + complete(&priv->completion); +} + +static void powerz_usb_cmd_complete(struct urb *urb) +{ + struct powerz_priv *priv = urb->context; + + usb_fill_bulk_urb(urb, urb->dev, + usb_rcvbulkpipe(urb->dev, POWERZ_EP_DATA_IN), + priv->transfer_buffer, sizeof(priv->transfer_buffer), + powerz_usb_data_complete, priv); + + priv->status = usb_submit_urb(urb, GFP_ATOMIC); + if (priv->status) + complete(&priv->completion); +} + +static int powerz_read_data(struct usb_device *udev, struct powerz_priv *priv) +{ + int ret; + + priv->status = -ETIMEDOUT; + reinit_completion(&priv->completion); + + priv->transfer_buffer[0] = 0x0c; + priv->transfer_buffer[1] = 0x00; + priv->transfer_buffer[2] = 0x02; + priv->transfer_buffer[3] = 0x00; + + usb_fill_bulk_urb(priv->urb, udev, + usb_sndbulkpipe(udev, POWERZ_EP_CMD_OUT), + priv->transfer_buffer, 4, powerz_usb_cmd_complete, + priv); + ret = usb_submit_urb(priv->urb, GFP_KERNEL); + if (ret) + return ret; + + if (!wait_for_completion_interruptible_timeout + (&priv->completion, msecs_to_jiffies(5))) { + usb_kill_urb(priv->urb); + return -EIO; + } + + if (priv->urb->actual_length < sizeof(struct powerz_sensor_data)) + return -EIO; + + return priv->status; +} + +static int powerz_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct usb_interface *intf = to_usb_interface(dev->parent); + struct usb_device *udev = interface_to_usbdev(intf); + struct powerz_priv *priv = usb_get_intfdata(intf); + struct powerz_sensor_data *data; + int ret; + + if (!priv) + return -EIO; /* disconnected */ + + mutex_lock(&priv->mutex); + ret = powerz_read_data(udev, priv); + if (ret) + goto out; + + data = (struct powerz_sensor_data *)priv->transfer_buffer; + + if (type == hwmon_curr) { + if (attr == hwmon_curr_input) + *val = ((s32)le32_to_cpu(data->I_bus)) / 1000; + else if (attr == hwmon_curr_average) + *val = ((s32)le32_to_cpu(data->I_bus_avg)) / 1000; + else + ret = -EOPNOTSUPP; + } else if (type == hwmon_in) { + if (attr == hwmon_in_input) { + if (channel == 0) + *val = le32_to_cpu(data->V_bus) / 1000; + else if (channel == 1) + *val = le16_to_cpu(data->V_cc1) / 10; + else if (channel == 2) + *val = le16_to_cpu(data->V_cc2) / 10; + else if (channel == 3) + *val = le16_to_cpu(data->V_dp) / 10; + else if (channel == 4) + *val = le16_to_cpu(data->V_dm) / 10; + else if (channel == 5) + *val = le16_to_cpu(data->V_dd) / 10; + else + ret = -EOPNOTSUPP; + } else if (attr == hwmon_in_average && channel == 0) { + *val = le32_to_cpu(data->V_bus_avg) / 1000; + } else { + ret = -EOPNOTSUPP; + } + } else if (type == hwmon_temp && attr == hwmon_temp_input) { + *val = data->temp[1] * 2000 + data->temp[0] * 1000 / 128; + } else { + ret = -EOPNOTSUPP; + } + +out: + mutex_unlock(&priv->mutex); + return ret; +} + +static const struct hwmon_ops powerz_hwmon_ops = { + .is_visible = powerz_is_visible, + .read = powerz_read, + .read_string = powerz_read_string, +}; + +static const struct hwmon_chip_info powerz_chip_info = { + .ops = &powerz_hwmon_ops, + .info = powerz_info, +}; + +static int powerz_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct powerz_priv *priv; + struct device *hwmon_dev; + struct device *parent; + + parent = &intf->dev; + + priv = devm_kzalloc(parent, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!priv->urb) + return -ENOMEM; + mutex_init(&priv->mutex); + init_completion(&priv->completion); + + hwmon_dev = + devm_hwmon_device_register_with_info(parent, DRIVER_NAME, priv, + &powerz_chip_info, NULL); + if (IS_ERR(hwmon_dev)) { + usb_free_urb(priv->urb); + return PTR_ERR(hwmon_dev); + } + + usb_set_intfdata(intf, priv); + + return 0; +} + +static void powerz_disconnect(struct usb_interface *intf) +{ + struct powerz_priv *priv = usb_get_intfdata(intf); + + mutex_lock(&priv->mutex); + usb_kill_urb(priv->urb); + usb_free_urb(priv->urb); + mutex_unlock(&priv->mutex); +} + +static const struct usb_device_id powerz_id_table[] = { + { USB_DEVICE_INTERFACE_NUMBER(0x5FC9, 0x0063, 0x00) }, /* ChargerLAB POWER-Z KM003C */ + { } +}; + +MODULE_DEVICE_TABLE(usb, powerz_id_table); + +static struct usb_driver powerz_driver = { + .name = DRIVER_NAME, + .id_table = powerz_id_table, + .probe = powerz_probe, + .disconnect = powerz_disconnect, +}; + +module_usb_driver(powerz_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Weißschuh "); +MODULE_DESCRIPTION("ChargerLAB POWER-Z USB-C tester"); From 30eea19c67d546bde1fbbc61e434b3a446a313dc Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Thu, 31 Aug 2023 21:07:27 +0200 Subject: [PATCH 330/396] dt-bindings: hwmon: Add Infineon TDA38640 Add the DT property 'infineon,en-pin-fixed-level' to indicated that the chip EN pin is at fixed level or left unconnected(has internal pull-down). Signed-off-by: Patrick Rudolph Signed-off-by: Naresh Solanki Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230831190731.265099-1-Naresh.Solanki@9elements.com [groeck: Dropped empty line at end] Signed-off-by: Guenter Roeck --- .../hwmon/pmbus/infineon,tda38640.yaml | 49 +++++++++++++++++++ .../devicetree/bindings/trivial-devices.yaml | 2 - 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/hwmon/pmbus/infineon,tda38640.yaml diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/infineon,tda38640.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/infineon,tda38640.yaml new file mode 100644 index 000000000000..ded1c115764b --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/infineon,tda38640.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/pmbus/infineon,tda38640.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Infineon TDA38640 Synchronous Buck Regulator with SVID and I2C + +maintainers: + - Naresh Solanki + +description: | + The Infineon TDA38640 is a 40A Single-voltage Synchronous Buck + Regulator with SVID and I2C designed for Industrial use. + + Datasheet: https://www.infineon.com/dgdl/Infineon-TDA38640-0000-DataSheet-v02_04-EN.pdf?fileId=8ac78c8c80027ecd018042f2337f00c9 + +properties: + compatible: + enum: + - infineon,tda38640 + + reg: + maxItems: 1 + + infineon,en-pin-fixed-level: + description: + Indicates that the chip EN pin is at fixed level or left + unconnected(has internal pull-down). + type: boolean + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + tda38640@40 { + compatible = "infineon,tda38640"; + reg = <0x40>; + }; + }; diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index cd58179ae337..d12a3fe98c9f 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -151,8 +151,6 @@ properties: - infineon,slb9645tt # Infineon SLB9673 I2C TPM 2.0 - infineon,slb9673 - # Infineon TDA38640 Voltage Regulator - - infineon,tda38640 # Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor - infineon,tlv493d-a1b6 # Infineon Multi-phase Digital VR Controller xdpe11280 From 05010fcf58e818cf71e2b4df338d84916644b749 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Thu, 31 Aug 2023 21:07:28 +0200 Subject: [PATCH 331/396] hwmon: (pmbus) Add ON_OFF_CONFIG register bits Add bits found in the ON_OFF_CONFIG register. Signed-off-by: Patrick Rudolph Signed-off-by: Naresh Solanki Link: https://lore.kernel.org/r/20230831190731.265099-2-Naresh.Solanki@9elements.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index b0832a4c690d..7a28bac7f171 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -243,6 +243,15 @@ enum pmbus_regs { */ #define PB_OPERATION_CONTROL_ON BIT(7) +/* + * ON_OFF_CONFIG + */ +#define PB_ON_OFF_CONFIG_POWERUP_CONTROL BIT(4) +#define PB_ON_OFF_CONFIG_OPERATION_REQ BIT(3) +#define PB_ON_OFF_CONFIG_EN_PIN_REQ BIT(2) +#define PB_ON_OFF_CONFIG_POLARITY_HIGH BIT(1) +#define PB_ON_OFF_CONFIG_TURN_OFF_FAST BIT(0) + /* * WRITE_PROTECT */ From 923774d759c9f83d13b900bda9d146a918f65a45 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Thu, 31 Aug 2023 21:07:29 +0200 Subject: [PATCH 332/396] hwmon: (pmbus/tda38640) Add workaround for SVID mode TDA38640 can operate in either PMBus mode or SVID mode. In SVID mode, by design ENABLE pin is the only option for controlling the output rail i.e., ENABLE pin is chained to power good of another reglator & FPGA. In cases where the chip is configured for SVID mode, and the ENABLE pin is set at a fixed level or is left unconnected (with an internal pull-down), while requiring software control, the following workaround is necessary. The workaround utilizes ENABLE pin polarity flipping to control output rail. If property 'infineon,en-pin-fixed-level' is specified then determine if chip is in SVID mode by checking BIT15 of MTP memory offset 0x44 as described in the datasheet. If chip is in SVID mode then apply the workaround by 1. Determine EN pin level 2. Maps BIT7 of OPERATION(01h) to EN_PIN_POLARITY(BIT1) of PB_ON_OFF_CONFIG. Signed-off-by: Patrick Rudolph Signed-off-by: Naresh Solanki Link: https://lore.kernel.org/r/20230831190731.265099-3-Naresh.Solanki@9elements.com [groeck: Dropped unnecessary line continuation] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/tda38640.c | 154 ++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/pmbus/tda38640.c b/drivers/hwmon/pmbus/tda38640.c index 450b0273fb59..09cd114b1736 100644 --- a/drivers/hwmon/pmbus/tda38640.c +++ b/drivers/hwmon/pmbus/tda38640.c @@ -18,6 +18,127 @@ static const struct regulator_desc __maybe_unused tda38640_reg_desc[] = { PMBUS_REGULATOR("vout", 0), }; +struct tda38640_data { + struct pmbus_driver_info info; + u32 en_pin_lvl; +}; + +#define to_tda38640_data(x) container_of(x, struct tda38640_data, info) + +/* + * Map PB_ON_OFF_CONFIG_POLARITY_HIGH to PB_OPERATION_CONTROL_ON. + */ +static int tda38640_read_byte_data(struct i2c_client *client, int page, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct tda38640_data *data = to_tda38640_data(info); + int ret, on_off_config, enabled; + + if (reg != PMBUS_OPERATION) + return -ENODATA; + + ret = pmbus_read_byte_data(client, page, reg); + if (ret < 0) + return ret; + + on_off_config = pmbus_read_byte_data(client, page, + PMBUS_ON_OFF_CONFIG); + if (on_off_config < 0) + return on_off_config; + + enabled = !!(on_off_config & PB_ON_OFF_CONFIG_POLARITY_HIGH); + + enabled ^= data->en_pin_lvl; + if (enabled) + ret &= ~PB_OPERATION_CONTROL_ON; + else + ret |= PB_OPERATION_CONTROL_ON; + + return ret; +} + +/* + * Map PB_OPERATION_CONTROL_ON to PB_ON_OFF_CONFIG_POLARITY_HIGH. + */ +static int tda38640_write_byte_data(struct i2c_client *client, int page, + int reg, u8 byte) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct tda38640_data *data = to_tda38640_data(info); + int enable, ret; + + if (reg != PMBUS_OPERATION) + return -ENODATA; + + enable = !!(byte & PB_OPERATION_CONTROL_ON); + + byte &= ~PB_OPERATION_CONTROL_ON; + ret = pmbus_write_byte_data(client, page, reg, byte); + if (ret < 0) + return ret; + + enable ^= data->en_pin_lvl; + + return pmbus_update_byte_data(client, page, PMBUS_ON_OFF_CONFIG, + PB_ON_OFF_CONFIG_POLARITY_HIGH, + enable ? 0 : PB_ON_OFF_CONFIG_POLARITY_HIGH); +} + +static int svid_mode(struct i2c_client *client, struct tda38640_data *data) +{ + /* PMBUS_MFR_READ(0xD0) + MTP Address offset */ + u8 write_buf[] = {0xd0, 0x44, 0x00}; + u8 read_buf[2]; + int ret, svid; + bool off, reg_en_pin_pol; + + struct i2c_msg msgs[2] = { + { + .addr = client->addr, + .flags = 0, + .buf = write_buf, + .len = sizeof(write_buf), + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = read_buf, + .len = sizeof(read_buf), + } + }; + + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0) { + dev_err(&client->dev, "i2c_transfer failed. %d", ret); + return ret; + } + + /* + * 0x44[15] determines PMBus Operating Mode + * If bit is set then it is SVID mode. + */ + svid = !!(read_buf[1] & BIT(7)); + + /* + * Determine EN pin level for use in SVID mode. + * This is done with help of STATUS_BYTE bit 6(OFF) & ON_OFF_CONFIG bit 2(EN pin polarity). + */ + if (svid) { + ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE); + if (ret < 0) + return ret; + off = !!(ret & PB_STATUS_OFF); + + ret = i2c_smbus_read_byte_data(client, PMBUS_ON_OFF_CONFIG); + if (ret < 0) + return ret; + reg_en_pin_pol = !!(ret & PB_ON_OFF_CONFIG_POLARITY_HIGH); + data->en_pin_lvl = off ^ reg_en_pin_pol; + } + + return svid; +} + static struct pmbus_driver_info tda38640_info = { .pages = 1, .format[PSC_VOLTAGE_IN] = linear, @@ -26,7 +147,6 @@ static struct pmbus_driver_info tda38640_info = { .format[PSC_CURRENT_IN] = linear, .format[PSC_POWER] = linear, .format[PSC_TEMPERATURE] = linear, - .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_IIN @@ -41,7 +161,37 @@ static struct pmbus_driver_info tda38640_info = { static int tda38640_probe(struct i2c_client *client) { - return pmbus_do_probe(client, &tda38640_info); + struct tda38640_data *data; + int svid; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + memcpy(&data->info, &tda38640_info, sizeof(tda38640_info)); + + if (IS_ENABLED(CONFIG_SENSORS_TDA38640_REGULATOR) && + of_property_read_bool(client->dev.of_node, "infineon,en-pin-fixed-level")) { + svid = svid_mode(client, data); + if (svid < 0) { + dev_err_probe(&client->dev, svid, "Could not determine operating mode."); + return svid; + } + + /* + * Apply ON_OFF_CONFIG workaround as enabling the regulator using the + * OPERATION register doesn't work in SVID mode. + * + * One should configure PMBUS_ON_OFF_CONFIG here, but + * PB_ON_OFF_CONFIG_POWERUP_CONTROL and PB_ON_OFF_CONFIG_EN_PIN_REQ + * are ignored by the device. + * Only PB_ON_OFF_CONFIG_POLARITY_HIGH has an effect. + */ + if (svid) { + data->info.read_byte_data = tda38640_read_byte_data; + data->info.write_byte_data = tda38640_write_byte_data; + } + } + return pmbus_do_probe(client, &data->info); } static const struct i2c_device_id tda38640_id[] = { From fb99e07a9e396402f643a138c2aef4699671b44a Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 7 Sep 2023 08:14:03 +0100 Subject: [PATCH 333/396] hwmon: tmp513: Add max_channels variable to struct tmp51x_data The tmp512 chip has 3 channels whereas tmp513 has 4 channels. Avoid using tmp51x_ids for this HW difference by replacing OF/ID table data with maximum channels supported by the device. Replace id->max_channels variable from struct tmp51x_data and drop the macros TMP51{2,3}_TEMP_CONFIG_DEFAULT as it can be derived from the macro TMP51X_TEMP_CONFIG_DEFAULT and update the logic in tmp51x_is_visible(), tmp51x_read_properties() and tmp51x_init() using max_channels. While at it, drop enum tmp51x_ids as there is no user and remove trailing comma in the terminator entry for OF table. Signed-off-by: Biju Das Link: https://lore.kernel.org/r/20230907071404.24334-2-biju.das.jz@bp.renesas.com Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp513.c | 49 ++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index 9a180b1030c9..b336b95298ab 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -73,9 +73,6 @@ #define TMP51X_PGA_DEFAULT 8 #define TMP51X_MAX_REGISTER_ADDR 0xFF -#define TMP512_TEMP_CONFIG_DEFAULT 0xBF80 -#define TMP513_TEMP_CONFIG_DEFAULT 0xFF80 - // Mask and shift #define CURRENT_SENSE_VOLTAGE_320_MASK 0x1800 #define CURRENT_SENSE_VOLTAGE_160_MASK 0x1000 @@ -113,6 +110,17 @@ #define MAX_TEMP_HYST 127500 +#define TMP512_MAX_CHANNELS 3 +#define TMP513_MAX_CHANNELS 4 + +#define TMP51X_TEMP_CONFIG_CONV_RATE GENMASK(9, 7) +#define TMP51X_TEMP_CONFIG_RC BIT(10) +#define TMP51X_TEMP_CHANNEL_MASK(n) (GENMASK((n) - 1, 0) << 11) +#define TMP51X_TEMP_CONFIG_CONT BIT(15) +#define TMP51X_TEMP_CONFIG_DEFAULT(n) \ + (TMP51X_TEMP_CHANNEL_MASK(n) | TMP51X_TEMP_CONFIG_CONT | \ + TMP51X_TEMP_CONFIG_CONV_RATE | TMP51X_TEMP_CONFIG_RC) + static const u8 TMP51X_TEMP_INPUT[4] = { TMP51X_LOCAL_TEMP_RESULT, TMP51X_REMOTE_TEMP_RESULT_1, @@ -152,10 +160,6 @@ static struct regmap_config tmp51x_regmap_config = { .max_register = TMP51X_MAX_REGISTER_ADDR, }; -enum tmp51x_ids { - tmp512, tmp513 -}; - struct tmp51x_data { u16 shunt_config; u16 pga_gain; @@ -169,7 +173,7 @@ struct tmp51x_data { u32 curr_lsb_ua; u32 pwr_lsb_uw; - enum tmp51x_ids id; + u8 max_channels; struct regmap *regmap; }; @@ -434,7 +438,7 @@ static umode_t tmp51x_is_visible(const void *_data, switch (type) { case hwmon_temp: - if (data->id == tmp512 && channel == 3) + if (channel >= data->max_channels) return 0; switch (attr) { case hwmon_temp_input: @@ -585,7 +589,7 @@ static int tmp51x_init(struct tmp51x_data *data) if (ret < 0) return ret; - if (data->id == tmp513) { + if (data->max_channels == TMP513_MAX_CHANNELS) { ret = regmap_write(data->regmap, TMP513_N_FACTOR_3, data->nfactor[2] << 8); if (ret < 0) @@ -601,22 +605,16 @@ static int tmp51x_init(struct tmp51x_data *data) } static const struct i2c_device_id tmp51x_id[] = { - { "tmp512", tmp512 }, - { "tmp513", tmp513 }, + { "tmp512", TMP512_MAX_CHANNELS }, + { "tmp513", TMP513_MAX_CHANNELS }, { } }; MODULE_DEVICE_TABLE(i2c, tmp51x_id); static const struct of_device_id tmp51x_of_match[] = { - { - .compatible = "ti,tmp512", - .data = (void *)tmp512 - }, - { - .compatible = "ti,tmp513", - .data = (void *)tmp513 - }, - { }, + { .compatible = "ti,tmp512", .data = (void *)TMP512_MAX_CHANNELS }, + { .compatible = "ti,tmp513", .data = (void *)TMP513_MAX_CHANNELS }, + { } }; MODULE_DEVICE_TABLE(of, tmp51x_of_match); @@ -674,9 +672,9 @@ static int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data) return ret; ret = device_property_read_u32_array(dev, "ti,nfactor", nfactor, - (data->id == tmp513) ? 3 : 2); + data->max_channels - 1); if (ret >= 0) - memcpy(data->nfactor, nfactor, (data->id == tmp513) ? 3 : 2); + memcpy(data->nfactor, nfactor, data->max_channels - 1); // Check if shunt value is compatible with pga-gain if (data->shunt_uohms > data->pga_gain * 40 * 1000 * 1000) { @@ -698,8 +696,7 @@ static void tmp51x_use_default(struct tmp51x_data *data) static int tmp51x_configure(struct device *dev, struct tmp51x_data *data) { data->shunt_config = TMP51X_SHUNT_CONFIG_DEFAULT; - data->temp_config = (data->id == tmp513) ? - TMP513_TEMP_CONFIG_DEFAULT : TMP512_TEMP_CONFIG_DEFAULT; + data->temp_config = TMP51X_TEMP_CONFIG_DEFAULT(data->max_channels); if (dev->of_node) return tmp51x_read_properties(dev, data); @@ -720,7 +717,7 @@ static int tmp51x_probe(struct i2c_client *client) if (!data) return -ENOMEM; - data->id = (uintptr_t)i2c_get_match_data(client); + data->max_channels = (uintptr_t)i2c_get_match_data(client); ret = tmp51x_configure(dev, data); if (ret < 0) { From 27887b06597bbfef8924985d1ed21db3ab01c417 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 7 Sep 2023 08:14:04 +0100 Subject: [PATCH 334/396] hwmon: tmp513: Simplify tmp51x_read_properties() Simplify tmp51x_read_properties() by replacing 'nfactor' ->'data->nfactor' in device_property_read_u32_array() and drop the local variable as it is unused. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230907071404.24334-3-biju.das.jz@bp.renesas.com Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp513.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index b336b95298ab..8a7cf08733c6 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -653,7 +653,6 @@ static int tmp51x_pga_gain_to_reg(struct device *dev, struct tmp51x_data *data) static int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data) { int ret; - u32 nfactor[3]; u32 val; ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val); @@ -671,10 +670,8 @@ static int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data) if (ret < 0) return ret; - ret = device_property_read_u32_array(dev, "ti,nfactor", nfactor, - data->max_channels - 1); - if (ret >= 0) - memcpy(data->nfactor, nfactor, data->max_channels - 1); + device_property_read_u32_array(dev, "ti,nfactor", data->nfactor, + data->max_channels - 1); // Check if shunt value is compatible with pga-gain if (data->shunt_uohms > data->pga_gain * 40 * 1000 * 1000) { From 7f0b28e0653f36b51542d25dd54ed312c397ecfc Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 7 Sep 2023 07:26:35 +0200 Subject: [PATCH 335/396] hwmon: (sch5627) Use bit macros when accessing the control register Use bit macros then accessing SCH5627_REG_CTRL, so that people do not need to look at the datasheet to find out what each bit does. Tested on a Fujitsu Esprimo P720. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230907052639.16491-2-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/sch5627.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 1bbda3b05532..0eefb8c0aef2 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -32,6 +33,9 @@ #define SCH5627_REG_PRIMARY_ID 0x3f #define SCH5627_REG_CTRL 0x40 +#define SCH5627_CTRL_START BIT(0) +#define SCH5627_CTRL_VBAT BIT(4) + #define SCH5627_NO_TEMPS 8 #define SCH5627_NO_FANS 4 #define SCH5627_NO_IN 5 @@ -147,7 +151,8 @@ static int sch5627_update_in(struct sch5627_data *data) /* Trigger a Vbat voltage measurement every 5 minutes */ if (time_after(jiffies, data->last_battery + 300 * HZ)) { - sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | 0x10); + sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, + data->control | SCH5627_CTRL_VBAT); data->last_battery = jiffies; } @@ -483,14 +488,13 @@ static int sch5627_probe(struct platform_device *pdev) return val; data->control = val; - if (!(data->control & 0x01)) { + if (!(data->control & SCH5627_CTRL_START)) { pr_err("hardware monitoring not enabled\n"); return -ENODEV; } /* Trigger a Vbat voltage measurement, so that we get a valid reading the first time we read Vbat */ - sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, - data->control | 0x10); + sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | SCH5627_CTRL_VBAT); data->last_battery = jiffies; /* From 7da8a635436029957c5350da3acf51d78ed64071 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 7 Sep 2023 07:26:36 +0200 Subject: [PATCH 336/396] hwmon: (sch5627) Disallow write access if virtual registers are locked When the lock bit inside SCH5627_REG_CTRL is set, then the virtual registers become read-only until the next power cycle. Disallow write access to those registers in such a case. Tested on a Fujitsu Esprimo P720. Fixes: aa9f833dfc12 ("hwmon: (sch5627) Add pwmX_auto_channels_temp support") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230907052639.16491-3-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/sch5627.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 0eefb8c0aef2..bf408e35e2c3 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -34,6 +34,7 @@ #define SCH5627_REG_CTRL 0x40 #define SCH5627_CTRL_START BIT(0) +#define SCH5627_CTRL_LOCK BIT(1) #define SCH5627_CTRL_VBAT BIT(4) #define SCH5627_NO_TEMPS 8 @@ -231,6 +232,14 @@ static int reg_to_rpm(u16 reg) static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) { + const struct sch5627_data *data = drvdata; + + /* Once the lock bit is set, the virtual registers become read-only + * until the next power cycle. + */ + if (data->control & SCH5627_CTRL_LOCK) + return 0444; + if (type == hwmon_pwm && attr == hwmon_pwm_auto_channels_temp) return 0644; From a54fe61639d9f3b6765fee32edda7cfceb6d705a Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 7 Sep 2023 07:26:37 +0200 Subject: [PATCH 337/396] hwmon: (sch5627) Use regmap for pwm map register caching Accessing virtual registers is very inefficient, so pwm map values should be cached when possible, else userspace could effectively do a DOS attack by reading pwm map values in a while loop. Use the regmap cache to cache those values. Tested on a Fujitsu Esprimo P720. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230907052639.16491-4-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 1 + drivers/hwmon/sch5627.c | 72 +++++++++++++++++++++++++------- drivers/hwmon/sch56xx-common.c | 76 ++++++++++++++++++++++++++++++++++ drivers/hwmon/sch56xx-common.h | 3 ++ 4 files changed, 138 insertions(+), 14 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 12af9f9cfd9f..ea390da7bc75 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1919,6 +1919,7 @@ config SENSORS_SMSC47B397 config SENSORS_SCH56XX_COMMON tristate + select REGMAP config SENSORS_SCH5627 tristate "SMSC SCH5627" diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index bf408e35e2c3..85f8352cb3cf 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -72,6 +74,7 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = { "VCC", "VTT", "VBAT", "VTR", "V_IN" }; struct sch5627_data { + struct regmap *regmap; unsigned short addr; u8 control; u8 temp_max[SCH5627_NO_TEMPS]; @@ -91,6 +94,26 @@ struct sch5627_data { u16 in[SCH5627_NO_IN]; }; +static const struct regmap_range sch5627_tunables_ranges[] = { + regmap_reg_range(0xA0, 0xA3), +}; + +static const struct regmap_access_table sch5627_tunables_table = { + .yes_ranges = sch5627_tunables_ranges, + .n_yes_ranges = ARRAY_SIZE(sch5627_tunables_ranges), +}; + +static const struct regmap_config sch5627_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .wr_table = &sch5627_tunables_table, + .rd_table = &sch5627_tunables_table, + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, + .can_sleep = true, +}; + static int sch5627_update_temp(struct sch5627_data *data) { int ret = 0; @@ -250,7 +273,7 @@ static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 at long *val) { struct sch5627_data *data = dev_get_drvdata(dev); - int ret; + int ret, value; switch (type) { case hwmon_temp: @@ -301,15 +324,11 @@ static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 at case hwmon_pwm: switch (attr) { case hwmon_pwm_auto_channels_temp: - mutex_lock(&data->update_lock); - ret = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel]); - mutex_unlock(&data->update_lock); - + ret = regmap_read(data->regmap, SCH5627_REG_PWM_MAP[channel], &value); if (ret < 0) return ret; - *val = ret; - + *val = value; return 0; default: break; @@ -359,7 +378,6 @@ static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 a long val) { struct sch5627_data *data = dev_get_drvdata(dev); - int ret; switch (type) { case hwmon_pwm: @@ -369,12 +387,7 @@ static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 a if (val > U8_MAX || val < 0) return -EINVAL; - mutex_lock(&data->update_lock); - ret = sch56xx_write_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel], - val); - mutex_unlock(&data->update_lock); - - return ret; + return regmap_write(data->regmap, SCH5627_REG_PWM_MAP[channel], val); default: break; } @@ -501,6 +514,12 @@ static int sch5627_probe(struct platform_device *pdev) pr_err("hardware monitoring not enabled\n"); return -ENODEV; } + + data->regmap = devm_regmap_init_sch56xx(&pdev->dev, &data->update_lock, data->addr, + &sch5627_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + /* Trigger a Vbat voltage measurement, so that we get a valid reading the first time we read Vbat */ sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | SCH5627_CTRL_VBAT); @@ -531,6 +550,30 @@ static int sch5627_probe(struct platform_device *pdev) return 0; } +static int sch5627_suspend(struct device *dev) +{ + struct sch5627_data *data = dev_get_drvdata(dev); + + regcache_cache_only(data->regmap, true); + regcache_mark_dirty(data->regmap); + + return 0; +} + +static int sch5627_resume(struct device *dev) +{ + struct sch5627_data *data = dev_get_drvdata(dev); + + regcache_cache_only(data->regmap, false); + /* We must not access the virtual registers when the lock bit is set */ + if (data->control & SCH5627_CTRL_LOCK) + return regcache_drop_region(data->regmap, 0, U16_MAX); + + return regcache_sync(data->regmap); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(sch5627_dev_pm_ops, sch5627_suspend, sch5627_resume); + static const struct platform_device_id sch5627_device_id[] = { { .name = "sch5627", @@ -542,6 +585,7 @@ MODULE_DEVICE_TABLE(platform, sch5627_device_id); static struct platform_driver sch5627_driver = { .driver = { .name = DRVNAME, + .pm = pm_sleep_ptr(&sch5627_dev_pm_ops), }, .probe = sch5627_probe, .id_table = sch5627_device_id, diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index ac1f72580715..ebdeb3a20b87 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,11 @@ struct sch56xx_watchdog_data { u8 watchdog_output_enable; }; +struct sch56xx_bus_context { + struct mutex *lock; /* Used to serialize access to the mailbox registers */ + u16 addr; +}; + static struct platform_device *sch56xx_pdev; /* Super I/O functions */ @@ -238,6 +244,76 @@ int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg, } EXPORT_SYMBOL(sch56xx_read_virtual_reg12); +/* + * Regmap support + */ + +static int sch56xx_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct sch56xx_bus_context *bus = context; + int ret; + + mutex_lock(bus->lock); + ret = sch56xx_write_virtual_reg(bus->addr, (u16)reg, (u8)val); + mutex_unlock(bus->lock); + + return ret; +} + +static int sch56xx_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct sch56xx_bus_context *bus = context; + int ret; + + mutex_lock(bus->lock); + ret = sch56xx_read_virtual_reg(bus->addr, (u16)reg); + mutex_unlock(bus->lock); + + if (ret < 0) + return ret; + + *val = ret; + + return 0; +} + +static void sch56xx_free_context(void *context) +{ + kfree(context); +} + +static const struct regmap_bus sch56xx_bus = { + .reg_write = sch56xx_reg_write, + .reg_read = sch56xx_reg_read, + .free_context = sch56xx_free_context, + .reg_format_endian_default = REGMAP_ENDIAN_LITTLE, + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, +}; + +struct regmap *devm_regmap_init_sch56xx(struct device *dev, struct mutex *lock, u16 addr, + const struct regmap_config *config) +{ + struct sch56xx_bus_context *context; + struct regmap *map; + + if (config->reg_bits != 16 && config->val_bits != 8) + return ERR_PTR(-EOPNOTSUPP); + + context = kzalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return ERR_PTR(-ENOMEM); + + context->lock = lock; + context->addr = addr; + + map = devm_regmap_init(dev, &sch56xx_bus, context, config); + if (IS_ERR(map)) + kfree(context); + + return map; +} +EXPORT_SYMBOL(devm_regmap_init_sch56xx); + /* * Watchdog routines */ diff --git a/drivers/hwmon/sch56xx-common.h b/drivers/hwmon/sch56xx-common.h index e907d9da0dd5..3fb1cddbf977 100644 --- a/drivers/hwmon/sch56xx-common.h +++ b/drivers/hwmon/sch56xx-common.h @@ -5,9 +5,12 @@ ***************************************************************************/ #include +#include struct sch56xx_watchdog_data; +struct regmap *devm_regmap_init_sch56xx(struct device *dev, struct mutex *lock, u16 addr, + const struct regmap_config *config); int sch56xx_read_virtual_reg(u16 addr, u16 reg); int sch56xx_write_virtual_reg(u16 addr, u16 reg, u8 val); int sch56xx_read_virtual_reg16(u16 addr, u16 reg); From 10655bb6df25514e0ae8406637c3b4acbc812fe5 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 7 Sep 2023 07:26:38 +0200 Subject: [PATCH 338/396] hwmon: (sch5627) Add support for writing limit registers After some testing on a Fujitsu Esprimo P720, it turned out that the limit registers are indeed writable and affect the fan control algorithm. This is supported by the datasheet, which says that the fan control functions are based on the limit and parameter registers. Since accessing those registers is very inefficient, the existing regmap cache is used to cache those registers values. Tested on a Fujitsu Esprimo P720. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230907052639.16491-5-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/sch5627.c | 174 ++++++++++++++++++++++----------- drivers/hwmon/sch56xx-common.c | 31 ++++++ drivers/hwmon/sch56xx-common.h | 3 + 3 files changed, 153 insertions(+), 55 deletions(-) diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 85f8352cb3cf..1891d4d75aa9 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -77,9 +78,6 @@ struct sch5627_data { struct regmap *regmap; unsigned short addr; u8 control; - u8 temp_max[SCH5627_NO_TEMPS]; - u8 temp_crit[SCH5627_NO_TEMPS]; - u16 fan_min[SCH5627_NO_FANS]; struct mutex update_lock; unsigned long last_battery; /* In jiffies */ @@ -95,7 +93,17 @@ struct sch5627_data { }; static const struct regmap_range sch5627_tunables_ranges[] = { + regmap_reg_range(0x57, 0x57), + regmap_reg_range(0x59, 0x59), + regmap_reg_range(0x5B, 0x5B), + regmap_reg_range(0x5D, 0x5D), + regmap_reg_range(0x5F, 0x5F), + regmap_reg_range(0x61, 0x69), + regmap_reg_range(0x96, 0x9B), regmap_reg_range(0xA0, 0xA3), + regmap_reg_range(0x184, 0x184), + regmap_reg_range(0x186, 0x186), + regmap_reg_range(0x1A8, 0x1A9), }; static const struct regmap_access_table sch5627_tunables_table = { @@ -200,38 +208,6 @@ abort: return ret; } -static int sch5627_read_limits(struct sch5627_data *data) -{ - int i, val; - - for (i = 0; i < SCH5627_NO_TEMPS; i++) { - /* - * Note what SMSC calls ABS, is what lm_sensors calls max - * (aka high), and HIGH is what lm_sensors calls crit. - */ - val = sch56xx_read_virtual_reg(data->addr, - SCH5627_REG_TEMP_ABS[i]); - if (val < 0) - return val; - data->temp_max[i] = val; - - val = sch56xx_read_virtual_reg(data->addr, - SCH5627_REG_TEMP_HIGH[i]); - if (val < 0) - return val; - data->temp_crit[i] = val; - } - for (i = 0; i < SCH5627_NO_FANS; i++) { - val = sch56xx_read_virtual_reg16(data->addr, - SCH5627_REG_FAN_MIN[i]); - if (val < 0) - return val; - data->fan_min[i] = val; - } - - return 0; -} - static int reg_to_temp(u16 reg) { return (reg * 625) / 10 - 64000; @@ -252,6 +228,25 @@ static int reg_to_rpm(u16 reg) return 5400540 / reg; } +static u8 sch5627_temp_limit_to_reg(long value) +{ + long limit = (value / 1000) + 64; + + return clamp_val(limit, 0, U8_MAX); +} + +static u16 sch5627_rpm_to_reg(long value) +{ + long pulses; + + if (value <= 0) + return U16_MAX - 1; + + pulses = 5400540 / value; + + return clamp_val(pulses, 1, U16_MAX - 1); +} + static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) { @@ -263,8 +258,35 @@ static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types t if (data->control & SCH5627_CTRL_LOCK) return 0444; - if (type == hwmon_pwm && attr == hwmon_pwm_auto_channels_temp) - return 0644; + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_max: + case hwmon_temp_crit: + return 0644; + default: + break; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_min: + return 0644; + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_auto_channels_temp: + return 0644; + default: + break; + } + break; + default: + break; + } return 0444; } @@ -277,20 +299,33 @@ static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 at switch (type) { case hwmon_temp: - ret = sch5627_update_temp(data); - if (ret < 0) - return ret; switch (attr) { case hwmon_temp_input: + ret = sch5627_update_temp(data); + if (ret < 0) + return ret; + *val = reg_to_temp(data->temp[channel]); return 0; case hwmon_temp_max: - *val = reg_to_temp_limit(data->temp_max[channel]); + ret = regmap_read(data->regmap, SCH5627_REG_TEMP_ABS[channel], &value); + if (ret < 0) + return ret; + + *val = reg_to_temp_limit((u8)value); return 0; case hwmon_temp_crit: - *val = reg_to_temp_limit(data->temp_crit[channel]); + ret = regmap_read(data->regmap, SCH5627_REG_TEMP_HIGH[channel], &value); + if (ret < 0) + return ret; + + *val = reg_to_temp_limit((u8)value); return 0; case hwmon_temp_fault: + ret = sch5627_update_temp(data); + if (ret < 0) + return ret; + *val = (data->temp[channel] == 0); return 0; default: @@ -298,23 +333,35 @@ static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 at } break; case hwmon_fan: - ret = sch5627_update_fan(data); - if (ret < 0) - return ret; switch (attr) { case hwmon_fan_input: + ret = sch5627_update_fan(data); + if (ret < 0) + return ret; + ret = reg_to_rpm(data->fan[channel]); if (ret < 0) return ret; + *val = ret; return 0; case hwmon_fan_min: - ret = reg_to_rpm(data->fan_min[channel]); + ret = sch56xx_regmap_read16(data->regmap, SCH5627_REG_FAN_MIN[channel], + &value); if (ret < 0) return ret; + + ret = reg_to_rpm((u16)value); + if (ret < 0) + return ret; + *val = ret; return 0; case hwmon_fan_fault: + ret = sch5627_update_fan(data); + if (ret < 0) + return ret; + *val = (data->fan[channel] == 0xffff); return 0; default: @@ -378,8 +425,33 @@ static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 a long val) { struct sch5627_data *data = dev_get_drvdata(dev); + u16 fan; + u8 temp; switch (type) { + case hwmon_temp: + temp = sch5627_temp_limit_to_reg(val); + + switch (attr) { + case hwmon_temp_max: + return regmap_write(data->regmap, SCH5627_REG_TEMP_ABS[channel], temp); + case hwmon_temp_crit: + return regmap_write(data->regmap, SCH5627_REG_TEMP_HIGH[channel], temp); + default: + break; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_min: + fan = sch5627_rpm_to_reg(val); + + return sch56xx_regmap_write16(data->regmap, SCH5627_REG_FAN_MIN[channel], + fan); + default: + break; + } + break; case hwmon_pwm: switch (attr) { case hwmon_pwm_auto_channels_temp: @@ -449,7 +521,7 @@ static int sch5627_probe(struct platform_device *pdev) { struct sch5627_data *data; struct device *hwmon_dev; - int err, build_code, build_id, hwmon_rev, val; + int build_code, build_id, hwmon_rev, val; data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data), GFP_KERNEL); @@ -525,14 +597,6 @@ static int sch5627_probe(struct platform_device *pdev) sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | SCH5627_CTRL_VBAT); data->last_battery = jiffies; - /* - * Read limits, we do this only once as reading a register on - * the sch5627 is quite expensive (and they don't change). - */ - err = sch5627_read_limits(data); - if (err) - return err; - pr_info("found %s chip at %#hx\n", DEVNAME, data->addr); pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n", build_code, build_id, hwmon_rev); diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index ebdeb3a20b87..71941b1bb573 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -248,6 +248,37 @@ EXPORT_SYMBOL(sch56xx_read_virtual_reg12); * Regmap support */ +int sch56xx_regmap_read16(struct regmap *map, unsigned int reg, unsigned int *val) +{ + int lsb, msb, ret; + + /* See sch56xx_read_virtual_reg16() */ + ret = regmap_read(map, reg, &lsb); + if (ret < 0) + return ret; + + ret = regmap_read(map, reg + 1, &msb); + if (ret < 0) + return ret; + + *val = lsb | (msb << 8); + + return 0; +} +EXPORT_SYMBOL(sch56xx_regmap_read16); + +int sch56xx_regmap_write16(struct regmap *map, unsigned int reg, unsigned int val) +{ + int ret; + + ret = regmap_write(map, reg, val & 0xff); + if (ret < 0) + return ret; + + return regmap_write(map, reg + 1, (val >> 8) & 0xff); +} +EXPORT_SYMBOL(sch56xx_regmap_write16); + static int sch56xx_reg_write(void *context, unsigned int reg, unsigned int val) { struct sch56xx_bus_context *bus = context; diff --git a/drivers/hwmon/sch56xx-common.h b/drivers/hwmon/sch56xx-common.h index 3fb1cddbf977..7479a549a026 100644 --- a/drivers/hwmon/sch56xx-common.h +++ b/drivers/hwmon/sch56xx-common.h @@ -11,6 +11,9 @@ struct sch56xx_watchdog_data; struct regmap *devm_regmap_init_sch56xx(struct device *dev, struct mutex *lock, u16 addr, const struct regmap_config *config); +int sch56xx_regmap_read16(struct regmap *map, unsigned int reg, unsigned int *val); +int sch56xx_regmap_write16(struct regmap *map, unsigned int reg, unsigned int val); + int sch56xx_read_virtual_reg(u16 addr, u16 reg); int sch56xx_write_virtual_reg(u16 addr, u16 reg, u8 val); int sch56xx_read_virtual_reg16(u16 addr, u16 reg); From e09b750526210775287c52d57b5ee2494847f5ed Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 7 Sep 2023 07:26:39 +0200 Subject: [PATCH 339/396] hwmon: (sch5627) Document behaviour of limit registers The values of the limit registers affect the fan speed in a particular way. Document this behaviour so that future users can exploit it if required. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230907052639.16491-6-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- Documentation/hwmon/sch5627.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/hwmon/sch5627.rst b/Documentation/hwmon/sch5627.rst index ecb4fc84d045..8639dff234fc 100644 --- a/Documentation/hwmon/sch5627.rst +++ b/Documentation/hwmon/sch5627.rst @@ -33,3 +33,13 @@ The hardware monitoring part of the SMSC SCH5627 is accessed by talking through an embedded microcontroller. An application note describing the protocol for communicating with the microcontroller is available upon request. Please mail me if you want a copy. + + +Controlling fan speed +--------------------- + +The SCH5627 allows for partially controlling the fan speed. If a temperature +channel excedes tempX_max, all fans are forced to maximum speed. The same is not +true for tempX_crit, presumably some other measures to cool down the system are +take in this case. +In which way the value of fanX_min affects the fan speed is currently unknown. From a7dee82af86c190570b04f202b1ef04d29249a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:28 +0200 Subject: [PATCH 340/396] hwmon: (abitguru{,3}) Enable build testing on !X86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two drivers compile fine on arm64, powerpc, m68k and s390. So make it possible to enable the drivers in the presence of COMPILE_TEST. Signed-off-by: Uwe Kleine-König Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20230918085951.1234172-2-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ea390da7bc75..e36f58b01f2d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -40,7 +40,7 @@ comment "Native drivers" config SENSORS_ABITUGURU tristate "Abit uGuru (rev 1 & 2)" - depends on X86 && DMI + depends on (X86 && DMI) || COMPILE_TEST help If you say yes here you get support for the sensor part of the first and second revision of the Abit uGuru chip. The voltage and frequency @@ -55,7 +55,7 @@ config SENSORS_ABITUGURU config SENSORS_ABITUGURU3 tristate "Abit uGuru (rev 3)" - depends on X86 && DMI + depends on (X86 && DMI) || COMPILE_TEST help If you say yes here you get support for the sensor part of the third revision of the Abit uGuru chip. Only reading the sensors From 68d66551eb5ead02a826cd0c235f0f94f384ac09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:29 +0200 Subject: [PATCH 341/396] hwmon: (abituguru) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20230918085951.1234172-3-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/abituguru.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index a7cae6568155..93653ea05430 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1428,7 +1428,7 @@ abituguru_probe_error: return res; } -static int abituguru_remove(struct platform_device *pdev) +static void abituguru_remove(struct platform_device *pdev) { int i; struct abituguru_data *data = platform_get_drvdata(pdev); @@ -1439,8 +1439,6 @@ static int abituguru_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) device_remove_file(&pdev->dev, &abituguru_sysfs_attr[i].dev_attr); - - return 0; } static struct abituguru_data *abituguru_update_device(struct device *dev) @@ -1533,7 +1531,7 @@ static struct platform_driver abituguru_driver = { .pm = pm_sleep_ptr(&abituguru_pm), }, .probe = abituguru_probe, - .remove = abituguru_remove, + .remove_new = abituguru_remove, }; static int __init abituguru_detect(void) From f23e759737e643255e04ce5d52dfda0a466c8c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:30 +0200 Subject: [PATCH 342/396] hwmon: (abituguru3) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-4-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/abituguru3.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index afb21f73032d..4501f0e49efb 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -1061,7 +1061,7 @@ abituguru3_probe_error: return res; } -static int abituguru3_remove(struct platform_device *pdev) +static void abituguru3_remove(struct platform_device *pdev) { int i; struct abituguru3_data *data = platform_get_drvdata(pdev); @@ -1072,7 +1072,6 @@ static int abituguru3_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++) device_remove_file(&pdev->dev, &abituguru3_sysfs_attr[i].dev_attr); - return 0; } static struct abituguru3_data *abituguru3_update_device(struct device *dev) @@ -1153,7 +1152,7 @@ static struct platform_driver abituguru3_driver = { .pm = pm_sleep_ptr(&abituguru3_pm), }, .probe = abituguru3_probe, - .remove = abituguru3_remove, + .remove_new = abituguru3_remove, }; static int __init abituguru3_dmi_detect(void) From f5681a839c03a71c485228eb28430d58e7a5d3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:31 +0200 Subject: [PATCH 343/396] hwmon: (da9052-hwmon) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-5-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/da9052-hwmon.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c index ed6c5df94fdf..2bd7ae8100d7 100644 --- a/drivers/hwmon/da9052-hwmon.c +++ b/drivers/hwmon/da9052-hwmon.c @@ -479,7 +479,7 @@ exit_regulator: return err; } -static int da9052_hwmon_remove(struct platform_device *pdev) +static void da9052_hwmon_remove(struct platform_device *pdev) { struct da9052_hwmon *hwmon = platform_get_drvdata(pdev); @@ -487,13 +487,11 @@ static int da9052_hwmon_remove(struct platform_device *pdev) da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon); regulator_disable(hwmon->tsiref); } - - return 0; } static struct platform_driver da9052_hwmon_driver = { .probe = da9052_hwmon_probe, - .remove = da9052_hwmon_remove, + .remove_new = da9052_hwmon_remove, .driver = { .name = "da9052-hwmon", }, From 63d35e96e0c01cbdc5ecd76cb231b0678f5602fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:32 +0200 Subject: [PATCH 344/396] hwmon: (dme1737) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-6-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/dme1737.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index cdbf3dff9172..3dcef221041d 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -2710,14 +2710,12 @@ exit_remove_files: return err; } -static int dme1737_isa_remove(struct platform_device *pdev) +static void dme1737_isa_remove(struct platform_device *pdev) { struct dme1737_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); dme1737_remove_files(&pdev->dev); - - return 0; } static struct platform_driver dme1737_isa_driver = { @@ -2725,7 +2723,7 @@ static struct platform_driver dme1737_isa_driver = { .name = "dme1737", }, .probe = dme1737_isa_probe, - .remove = dme1737_isa_remove, + .remove_new = dme1737_isa_remove, }; /* --------------------------------------------------------------------- From f79fe155cb7c326cf9ba58b5c4c289a994bd3e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:33 +0200 Subject: [PATCH 345/396] hwmon: (f71805f) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-7-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/f71805f.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 7f20edb0677c..243c570dee4c 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1480,7 +1480,7 @@ exit_remove_files: return err; } -static int f71805f_remove(struct platform_device *pdev) +static void f71805f_remove(struct platform_device *pdev) { struct f71805f_data *data = platform_get_drvdata(pdev); int i; @@ -1490,8 +1490,6 @@ static int f71805f_remove(struct platform_device *pdev) for (i = 0; i < 4; i++) sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); - - return 0; } static struct platform_driver f71805f_driver = { @@ -1499,7 +1497,7 @@ static struct platform_driver f71805f_driver = { .name = DRVNAME, }, .probe = f71805f_probe, - .remove = f71805f_remove, + .remove_new = f71805f_remove, }; static int __init f71805f_device_add(unsigned short address, From a8f208d2a4c8fc20109d217d05490d23fcd1109f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:34 +0200 Subject: [PATCH 346/396] hwmon: (f71882fg) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-8-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 27207ec6f7fe..7c941d320a18 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -2223,7 +2223,7 @@ static int f71882fg_create_fan_sysfs_files( return err; } -static int f71882fg_remove(struct platform_device *pdev) +static void f71882fg_remove(struct platform_device *pdev) { struct f71882fg_data *data = platform_get_drvdata(pdev); int nr_fans = f71882fg_nr_fans[data->type]; @@ -2333,7 +2333,6 @@ static int f71882fg_remove(struct platform_device *pdev) ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); } } - return 0; } static int f71882fg_probe(struct platform_device *pdev) @@ -2659,7 +2658,7 @@ static struct platform_driver f71882fg_driver = { .name = DRVNAME, }, .probe = f71882fg_probe, - .remove = f71882fg_remove, + .remove_new = f71882fg_remove, }; static int __init f71882fg_init(void) From 62f5e95d409c20a946942f65455e17c9c59b75fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:35 +0200 Subject: [PATCH 347/396] hwmon: (i5k_amb) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-9-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/i5k_amb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 783fa936e4d1..ff48913fe6bf 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -555,7 +555,7 @@ err: return res; } -static int i5k_amb_remove(struct platform_device *pdev) +static void i5k_amb_remove(struct platform_device *pdev) { int i; struct i5k_amb_data *data = platform_get_drvdata(pdev); @@ -568,7 +568,6 @@ static int i5k_amb_remove(struct platform_device *pdev) iounmap(data->amb_mmio); release_mem_region(data->amb_base, data->amb_len); kfree(data); - return 0; } static struct platform_driver i5k_amb_driver = { @@ -576,7 +575,7 @@ static struct platform_driver i5k_amb_driver = { .name = DRVNAME, }, .probe = i5k_amb_probe, - .remove = i5k_amb_remove, + .remove_new = i5k_amb_remove, }; static int __init i5k_amb_init(void) From 19eae13a8980eb71e789e676ce94869b3b76ed50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:36 +0200 Subject: [PATCH 348/396] hwmon: (max197) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-10-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/max197.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index 56add579e32f..bb30403f81ca 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -312,14 +312,12 @@ error: return ret; } -static int max197_remove(struct platform_device *pdev) +static void max197_remove(struct platform_device *pdev) { struct max197_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group); - - return 0; } static const struct platform_device_id max197_device_ids[] = { @@ -334,7 +332,7 @@ static struct platform_driver max197_driver = { .name = "max197", }, .probe = max197_probe, - .remove = max197_remove, + .remove_new = max197_remove, .id_table = max197_device_ids, }; module_platform_driver(max197_driver); From 13af7eeeb6be5895c3ca9752c6ff8d719b2228c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:37 +0200 Subject: [PATCH 349/396] hwmon: (mc13783-adc) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-11-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/mc13783-adc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index ff147e5e1b8c..67471c9cd4d4 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -285,7 +285,7 @@ out_err_create_16chans: return ret; } -static int mc13783_adc_remove(struct platform_device *pdev) +static void mc13783_adc_remove(struct platform_device *pdev) { struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; @@ -299,8 +299,6 @@ static int mc13783_adc_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans); sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base); - - return 0; } static const struct platform_device_id mc13783_adc_idtable[] = { @@ -317,7 +315,7 @@ static const struct platform_device_id mc13783_adc_idtable[] = { MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); static struct platform_driver mc13783_adc_driver = { - .remove = mc13783_adc_remove, + .remove_new = mc13783_adc_remove, .driver = { .name = DRIVER_NAME, }, From ade539199bdade09382a1fa2a8a5a68474507f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:38 +0200 Subject: [PATCH 350/396] hwmon: (occ/p9_sbe) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-12-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/occ/p9_sbe.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c index 96521363b696..b5993c79c09e 100644 --- a/drivers/hwmon/occ/p9_sbe.c +++ b/drivers/hwmon/occ/p9_sbe.c @@ -167,7 +167,7 @@ static int p9_sbe_occ_probe(struct platform_device *pdev) return rc; } -static int p9_sbe_occ_remove(struct platform_device *pdev) +static void p9_sbe_occ_remove(struct platform_device *pdev) { struct occ *occ = platform_get_drvdata(pdev); struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ); @@ -178,8 +178,6 @@ static int p9_sbe_occ_remove(struct platform_device *pdev) occ_shutdown(occ); kvfree(ctx->ffdc); - - return 0; } static const struct of_device_id p9_sbe_occ_of_match[] = { @@ -195,7 +193,7 @@ static struct platform_driver p9_sbe_occ_driver = { .of_match_table = p9_sbe_occ_of_match, }, .probe = p9_sbe_occ_probe, - .remove = p9_sbe_occ_remove, + .remove_new = p9_sbe_occ_remove, }; module_platform_driver(p9_sbe_occ_driver); From c45af5d2f3161910d86819741e64b9d801ae99ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:39 +0200 Subject: [PATCH 351/396] hwmon: (pc87360) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-13-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/pc87360.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index a4adc8bd531f..926ea1fe133c 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -1586,14 +1586,12 @@ error: return err; } -static int pc87360_remove(struct platform_device *pdev) +static void pc87360_remove(struct platform_device *pdev) { struct pc87360_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); pc87360_remove_files(&pdev->dev); - - return 0; } /* @@ -1604,7 +1602,7 @@ static struct platform_driver pc87360_driver = { .name = DRIVER_NAME, }, .probe = pc87360_probe, - .remove = pc87360_remove, + .remove_new = pc87360_remove, }; /* From d29041681aa69c15dc0ac4688cb6e6f5b1a7d7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:40 +0200 Subject: [PATCH 352/396] hwmon: (pc87427) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-14-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/pc87427.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index eaab83d879fb..7bca04eb4ee4 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -1115,14 +1115,12 @@ exit_remove_files: return err; } -static int pc87427_remove(struct platform_device *pdev) +static void pc87427_remove(struct platform_device *pdev) { struct pc87427_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); pc87427_remove_files(&pdev->dev); - - return 0; } @@ -1131,7 +1129,7 @@ static struct platform_driver pc87427_driver = { .name = DRVNAME, }, .probe = pc87427_probe, - .remove = pc87427_remove, + .remove_new = pc87427_remove, }; static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) From e44e19945ca10d9a260916b414d3345dfb671735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:41 +0200 Subject: [PATCH 353/396] hwmon: (sch5636) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-15-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/sch5636.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index 269757bc3a9e..6e6d54158474 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -367,7 +367,7 @@ static struct sensor_device_attribute sch5636_fan_attr[] = { SENSOR_ATTR_RO(fan8_alarm, fan_alarm, 7), }; -static int sch5636_remove(struct platform_device *pdev) +static void sch5636_remove(struct platform_device *pdev) { struct sch5636_data *data = platform_get_drvdata(pdev); int i; @@ -385,8 +385,6 @@ static int sch5636_remove(struct platform_device *pdev) for (i = 0; i < SCH5636_NO_FANS * 3; i++) device_remove_file(&pdev->dev, &sch5636_fan_attr[i].dev_attr); - - return 0; } static int sch5636_probe(struct platform_device *pdev) @@ -515,7 +513,7 @@ static struct platform_driver sch5636_driver = { .name = DRVNAME, }, .probe = sch5636_probe, - .remove = sch5636_remove, + .remove_new = sch5636_remove, .id_table = sch5636_device_id, }; From a93a2c415486fbe9304543a943de789f0a89727a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:42 +0200 Subject: [PATCH 354/396] hwmon: (sht15) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-16-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/sht15.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 32a41fc56fc9..494f9655f44f 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -1017,7 +1017,7 @@ err_release_reg: return ret; } -static int sht15_remove(struct platform_device *pdev) +static void sht15_remove(struct platform_device *pdev) { struct sht15_data *data = platform_get_drvdata(pdev); int ret; @@ -1033,8 +1033,6 @@ static int sht15_remove(struct platform_device *pdev) regulator_unregister_notifier(data->reg, &data->nb); regulator_disable(data->reg); } - - return 0; } static const struct platform_device_id sht15_device_ids[] = { @@ -1053,7 +1051,7 @@ static struct platform_driver sht15_driver = { .of_match_table = of_match_ptr(sht15_dt_match), }, .probe = sht15_probe, - .remove = sht15_remove, + .remove_new = sht15_remove, .id_table = sht15_device_ids, }; module_platform_driver(sht15_driver); From 39797753fdc208ea5771acbcf338a1649086afa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:43 +0200 Subject: [PATCH 355/396] hwmon: (sis5595) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-17-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/sis5595.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 0a0479501e11..641be1f7f9cd 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -709,7 +709,7 @@ exit_remove_files: return err; } -static int sis5595_remove(struct platform_device *pdev) +static void sis5595_remove(struct platform_device *pdev) { struct sis5595_data *data = platform_get_drvdata(pdev); @@ -717,8 +717,6 @@ static int sis5595_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &sis5595_group); sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4); sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1); - - return 0; } static const struct pci_device_id sis5595_pci_ids[] = { @@ -790,7 +788,7 @@ static struct platform_driver sis5595_driver = { .name = DRIVER_NAME, }, .probe = sis5595_probe, - .remove = sis5595_remove, + .remove_new = sis5595_remove, }; static int sis5595_pci_probe(struct pci_dev *dev, From b875359995fad1ca20ed198e7969e2d1d308c202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:44 +0200 Subject: [PATCH 356/396] hwmon: (ultra45_env) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-18-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/ultra45_env.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 3b580f229887..9823afb0675a 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -291,7 +291,7 @@ out_iounmap: goto out; } -static int env_remove(struct platform_device *op) +static void env_remove(struct platform_device *op) { struct env *p = platform_get_drvdata(op); @@ -300,8 +300,6 @@ static int env_remove(struct platform_device *op) hwmon_device_unregister(p->hwmon_dev); of_iounmap(&op->resource[0], p->regs, REG_SIZE); } - - return 0; } static const struct of_device_id env_match[] = { @@ -319,7 +317,7 @@ static struct platform_driver env_driver = { .of_match_table = env_match, }, .probe = env_probe, - .remove = env_remove, + .remove_new = env_remove, }; module_platform_driver(env_driver); From 88ac8226a34fa82f82d8a12a8d99b2436a35e2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:45 +0200 Subject: [PATCH 357/396] hwmon: (via-cputemp) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-19-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/via-cputemp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index e5d18dac8ee7..5abe95b683c0 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -182,7 +182,7 @@ exit_remove: return err; } -static int via_cputemp_remove(struct platform_device *pdev) +static void via_cputemp_remove(struct platform_device *pdev) { struct via_cputemp_data *data = platform_get_drvdata(pdev); @@ -190,7 +190,6 @@ static int via_cputemp_remove(struct platform_device *pdev) if (data->vrm) device_remove_file(&pdev->dev, &dev_attr_cpu0_vid); sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group); - return 0; } static struct platform_driver via_cputemp_driver = { @@ -198,7 +197,7 @@ static struct platform_driver via_cputemp_driver = { .name = DRVNAME, }, .probe = via_cputemp_probe, - .remove = via_cputemp_remove, + .remove_new = via_cputemp_remove, }; struct pdev_entry { From 680a1b08096c97727819d5b257c85e5a8b46be04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:46 +0200 Subject: [PATCH 358/396] hwmon: (via686a) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-20-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/via686a.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 407933d6e425..3a002ad3c005 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -786,14 +786,12 @@ exit_remove_files: return err; } -static int via686a_remove(struct platform_device *pdev) +static void via686a_remove(struct platform_device *pdev) { struct via686a_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &via686a_group); - - return 0; } static struct platform_driver via686a_driver = { @@ -801,7 +799,7 @@ static struct platform_driver via686a_driver = { .name = DRIVER_NAME, }, .probe = via686a_probe, - .remove = via686a_remove, + .remove_new = via686a_remove, }; static const struct pci_device_id via686a_pci_ids[] = { From 6e4c7bafcd0cc7e221a6d06605f645616529fb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:47 +0200 Subject: [PATCH 359/396] hwmon: (vt1211) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-21-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/vt1211.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index fcd4be7a5a85..2f3890463e18 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -1208,14 +1208,12 @@ EXIT_DEV_REMOVE_SILENT: return err; } -static int vt1211_remove(struct platform_device *pdev) +static void vt1211_remove(struct platform_device *pdev) { struct vt1211_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); vt1211_remove_sysfs(pdev); - - return 0; } static struct platform_driver vt1211_driver = { @@ -1223,7 +1221,7 @@ static struct platform_driver vt1211_driver = { .name = DRVNAME, }, .probe = vt1211_probe, - .remove = vt1211_remove, + .remove_new = vt1211_remove, }; static int __init vt1211_device_add(unsigned short address) From 5b4000065cde815dbe3475f24a1a7fe527a68d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:48 +0200 Subject: [PATCH 360/396] hwmon: (vt8231) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-22-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/vt8231.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 16bc16d33cd1..dcdd14ccd115 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -892,7 +892,7 @@ exit_remove_files: return err; } -static int vt8231_remove(struct platform_device *pdev) +static void vt8231_remove(struct platform_device *pdev) { struct vt8231_data *data = platform_get_drvdata(pdev); int i; @@ -906,8 +906,6 @@ static int vt8231_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]); sysfs_remove_group(&pdev->dev.kobj, &vt8231_group); - - return 0; } @@ -916,7 +914,7 @@ static struct platform_driver vt8231_driver = { .name = DRIVER_NAME, }, .probe = vt8231_probe, - .remove = vt8231_remove, + .remove_new = vt8231_remove, }; static const struct pci_device_id vt8231_pci_ids[] = { From eaac830a7e736bf493e9096453d620d29f39c695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:49 +0200 Subject: [PATCH 361/396] hwmon: (w83627hf) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-23-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/w83627hf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index b638d672ac45..2fc9b718e2ab 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -1828,7 +1828,7 @@ static int w83627hf_probe(struct platform_device *pdev) return err; } -static int w83627hf_remove(struct platform_device *pdev) +static void w83627hf_remove(struct platform_device *pdev) { struct w83627hf_data *data = platform_get_drvdata(pdev); @@ -1836,8 +1836,6 @@ static int w83627hf_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group); sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt); - - return 0; } static struct platform_driver w83627hf_driver = { @@ -1846,7 +1844,7 @@ static struct platform_driver w83627hf_driver = { .pm = W83627HF_DEV_PM_OPS, }, .probe = w83627hf_probe, - .remove = w83627hf_remove, + .remove_new = w83627hf_remove, }; static int __init w83627hf_find(int sioaddr, unsigned short *addr, From bc70de33250e1b9b8ae6909140943fe251b81571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:50 +0200 Subject: [PATCH 362/396] hwmon: (w83781d) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-24-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/w83781d.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index b33f382f238d..cba5ec432e6d 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1816,16 +1816,13 @@ w83781d_isa_probe(struct platform_device *pdev) return err; } -static int -w83781d_isa_remove(struct platform_device *pdev) +static void w83781d_isa_remove(struct platform_device *pdev) { struct w83781d_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); w83781d_remove_files(&pdev->dev); device_remove_file(&pdev->dev, &dev_attr_name); - - return 0; } static struct platform_driver w83781d_isa_driver = { @@ -1833,7 +1830,7 @@ static struct platform_driver w83781d_isa_driver = { .name = "w83781d", }, .probe = w83781d_isa_probe, - .remove = w83781d_isa_remove, + .remove_new = w83781d_isa_remove, }; /* return 1 if a supported chip is found, 0 otherwise */ From 9ab6fe910b1a00b51e6f9396950092e658211474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 18 Sep 2023 10:59:51 +0200 Subject: [PATCH 363/396] hwmon: (xgene-hwmon) Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230918085951.1234172-25-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/xgene-hwmon.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c index 78d9f52e2a71..bf5b3880ce5b 100644 --- a/drivers/hwmon/xgene-hwmon.c +++ b/drivers/hwmon/xgene-hwmon.c @@ -757,7 +757,7 @@ out_mbox_free: return rc; } -static int xgene_hwmon_remove(struct platform_device *pdev) +static void xgene_hwmon_remove(struct platform_device *pdev) { struct xgene_hwmon_dev *ctx = platform_get_drvdata(pdev); @@ -768,8 +768,6 @@ static int xgene_hwmon_remove(struct platform_device *pdev) mbox_free_channel(ctx->mbox_chan); else pcc_mbox_free_channel(ctx->pcc_chan); - - return 0; } static const struct of_device_id xgene_hwmon_of_match[] = { @@ -780,7 +778,7 @@ MODULE_DEVICE_TABLE(of, xgene_hwmon_of_match); static struct platform_driver xgene_hwmon_driver = { .probe = xgene_hwmon_probe, - .remove = xgene_hwmon_remove, + .remove_new = xgene_hwmon_remove, .driver = { .name = "xgene-slimpro-hwmon", .of_match_table = xgene_hwmon_of_match, From 2232f10d714f2198d037b8047f482c09f7ad3b9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 11 Sep 2023 07:44:42 +0200 Subject: [PATCH 364/396] hwmon: (powerz) add support for ChargerLAB KM002C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KM002C is similar to the KM003C and seems to use the same protocol and firmware. Reported-by: Douglas Gilbert Closes: https://lore.kernel.org/lkml/290ebce4-54f0-8ac1-2a13-cbc806d80d64@interlog.com/ Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20230911-powerz-km002c-v1-1-898bd79b9bae@weissschuh.net Signed-off-by: Guenter Roeck --- drivers/hwmon/powerz.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwmon/powerz.c b/drivers/hwmon/powerz.c index 2b9693aee6f6..cfb635f94d66 100644 --- a/drivers/hwmon/powerz.c +++ b/drivers/hwmon/powerz.c @@ -254,6 +254,7 @@ static void powerz_disconnect(struct usb_interface *intf) } static const struct usb_device_id powerz_id_table[] = { + { USB_DEVICE_INTERFACE_NUMBER(0x5FC9, 0x0061, 0x00) }, /* ChargerLAB POWER-Z KM002C */ { USB_DEVICE_INTERFACE_NUMBER(0x5FC9, 0x0063, 0x00) }, /* ChargerLAB POWER-Z KM003C */ { } }; From 62c11e461c7b669e8d42c0e49c8193a5e14d002a Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Thu, 14 Sep 2023 17:39:47 -0500 Subject: [PATCH 365/396] hwmon: (adt7475) Add support for Imon readout on ADT7490 Add support for the ADT7490's Imon voltage readout. It is handled largely the same way as the existing Vtt readout. Signed-off-by: Timothy Pearson Co-developed-by: Shawn Anastasio Signed-off-by: Shawn Anastasio Link: https://lore.kernel.org/r/20230914223947.829025-1-tpearson@raptorengineering.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/adt7475.rst | 3 +- drivers/hwmon/adt7475.c | 68 ++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Documentation/hwmon/adt7475.rst b/Documentation/hwmon/adt7475.rst index ef3ea1ea9bc1..f90f769d82d6 100644 --- a/Documentation/hwmon/adt7475.rst +++ b/Documentation/hwmon/adt7475.rst @@ -90,7 +90,7 @@ ADT7476: ADT7490: * 6 voltage inputs - * 1 Imon input (not implemented) + * 1 Imon input * PECI support (not implemented) * 2 GPIO pins (not implemented) * system acoustics optimizations (not implemented) @@ -107,6 +107,7 @@ in2 VCC (4) VCC (4) VCC (4) VCC (3) in3 5VIN (20) 5VIN (20) in4 12VIN (21) 12VIN (21) in5 VTT (8) +in6 Imon (19) ==== =========== =========== ========= ========== Special Features diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 03acadc3a6cb..4224ffb30483 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -43,6 +43,7 @@ /* 7475 Common Registers */ #define REG_DEVREV2 0x12 /* ADT7490 only */ +#define REG_IMON 0x1D /* ADT7490 only */ #define REG_VTT 0x1E /* ADT7490 only */ #define REG_EXTEND3 0x1F /* ADT7490 only */ @@ -103,6 +104,9 @@ #define REG_VTT_MIN 0x84 /* ADT7490 only */ #define REG_VTT_MAX 0x86 /* ADT7490 only */ +#define REG_IMON_MIN 0x85 /* ADT7490 only */ +#define REG_IMON_MAX 0x87 /* ADT7490 only */ + #define VID_VIDSEL 0x80 /* ADT7476 only */ #define CONFIG2_ATTN 0x20 @@ -123,7 +127,7 @@ /* ADT7475 Settings */ -#define ADT7475_VOLTAGE_COUNT 5 /* Not counting Vtt */ +#define ADT7475_VOLTAGE_COUNT 5 /* Not counting Vtt or Imon */ #define ADT7475_TEMP_COUNT 3 #define ADT7475_TACH_COUNT 4 #define ADT7475_PWM_COUNT 3 @@ -204,7 +208,7 @@ struct adt7475_data { u8 has_fan4:1; u8 has_vid:1; u32 alarms; - u16 voltage[3][6]; + u16 voltage[3][7]; u16 temp[7][3]; u16 tach[2][4]; u8 pwm[4][3]; @@ -215,7 +219,7 @@ struct adt7475_data { u8 vid; u8 vrm; - const struct attribute_group *groups[9]; + const struct attribute_group *groups[10]; }; static struct i2c_driver adt7475_driver; @@ -273,13 +277,14 @@ static inline u16 rpm2tach(unsigned long rpm) } /* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */ -static const int adt7473_in_scaling[ADT7475_VOLTAGE_COUNT + 1][2] = { +static const int adt7473_in_scaling[ADT7475_VOLTAGE_COUNT + 2][2] = { { 45, 94 }, /* +2.5V */ { 175, 525 }, /* Vccp */ { 68, 71 }, /* Vcc */ { 93, 47 }, /* +5V */ { 120, 20 }, /* +12V */ { 45, 45 }, /* Vtt */ + { 45, 45 }, /* Imon */ }; static inline int reg2volt(int channel, u16 reg, u8 bypass_attn) @@ -369,11 +374,16 @@ static ssize_t voltage_store(struct device *dev, reg = VOLTAGE_MIN_REG(sattr->index); else reg = VOLTAGE_MAX_REG(sattr->index); - } else { + } else if (sattr->index == 5) { if (sattr->nr == MIN) reg = REG_VTT_MIN; else reg = REG_VTT_MAX; + } else { + if (sattr->nr == MIN) + reg = REG_IMON_MIN; + else + reg = REG_IMON_MAX; } i2c_smbus_write_byte_data(client, reg, @@ -1104,6 +1114,10 @@ static SENSOR_DEVICE_ATTR_2_RO(in5_input, voltage, INPUT, 5); static SENSOR_DEVICE_ATTR_2_RW(in5_max, voltage, MAX, 5); static SENSOR_DEVICE_ATTR_2_RW(in5_min, voltage, MIN, 5); static SENSOR_DEVICE_ATTR_2_RO(in5_alarm, voltage, ALARM, 31); +static SENSOR_DEVICE_ATTR_2_RO(in6_input, voltage, INPUT, 6); +static SENSOR_DEVICE_ATTR_2_RW(in6_max, voltage, MAX, 6); +static SENSOR_DEVICE_ATTR_2_RW(in6_min, voltage, MIN, 6); +static SENSOR_DEVICE_ATTR_2_RO(in6_alarm, voltage, ALARM, 30); static SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, INPUT, 0); static SENSOR_DEVICE_ATTR_2_RO(temp1_alarm, temp, ALARM, 0); static SENSOR_DEVICE_ATTR_2_RO(temp1_fault, temp, FAULT, 0); @@ -1294,6 +1308,14 @@ static struct attribute *in5_attrs[] = { NULL }; +static struct attribute *in6_attrs[] = { + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + NULL +}; + static struct attribute *vid_attrs[] = { &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, @@ -1307,6 +1329,7 @@ static const struct attribute_group in0_attr_group = { .attrs = in0_attrs }; static const struct attribute_group in3_attr_group = { .attrs = in3_attrs }; static const struct attribute_group in4_attr_group = { .attrs = in4_attrs }; static const struct attribute_group in5_attr_group = { .attrs = in5_attrs }; +static const struct attribute_group in6_attr_group = { .attrs = in6_attrs }; static const struct attribute_group vid_attr_group = { .attrs = vid_attrs }; static int adt7475_detect(struct i2c_client *client, @@ -1389,6 +1412,18 @@ static int adt7475_update_limits(struct i2c_client *client) data->voltage[MAX][5] = ret << 2; } + if (data->has_voltage & (1 << 6)) { + ret = adt7475_read(REG_IMON_MIN); + if (ret < 0) + return ret; + data->voltage[MIN][6] = ret << 2; + + ret = adt7475_read(REG_IMON_MAX); + if (ret < 0) + return ret; + data->voltage[MAX][6] = ret << 2; + } + for (i = 0; i < ADT7475_TEMP_COUNT; i++) { /* Adjust values so they match the input precision */ ret = adt7475_read(TEMP_MIN_REG(i)); @@ -1663,7 +1698,7 @@ static int adt7475_probe(struct i2c_client *client) revision = adt7475_read(REG_DEVID2) & 0x07; break; case adt7490: - data->has_voltage = 0x3e; /* in1 to in5 */ + data->has_voltage = 0x7e; /* in1 to in6 */ revision = adt7475_read(REG_DEVID2) & 0x03; if (revision == 0x03) revision += adt7475_read(REG_DEVREV2); @@ -1775,6 +1810,9 @@ static int adt7475_probe(struct i2c_client *client) if (data->has_voltage & (1 << 5)) { data->groups[group_num++] = &in5_attr_group; } + if (data->has_voltage & (1 << 6)) { + data->groups[group_num++] = &in6_attr_group; + } if (data->has_vid) { data->vrm = vid_which_vrm(); data->groups[group_num] = &vid_attr_group; @@ -1960,6 +1998,24 @@ static int adt7475_update_measure(struct device *dev) ((ext >> 4) & 3); } + if (data->has_voltage & (1 << 6)) { + ret = adt7475_read(REG_STATUS4); + if (ret < 0) + return ret; + data->alarms |= ret << 24; + + ret = adt7475_read(REG_EXTEND3); + if (ret < 0) + return ret; + ext = ret; + + ret = adt7475_read(REG_IMON); + if (ret < 0) + return ret; + data->voltage[INPUT][6] = ret << 2 | + ((ext >> 6) & 3); + } + for (i = 0; i < ADT7475_TACH_COUNT; i++) { if (i == 3 && !data->has_fan4) continue; From 7e52b1164a474dc7b90f68fbb40e35ccd7f7e2e2 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 27 Oct 2023 10:58:24 +0200 Subject: [PATCH 366/396] clk: si521xx: Increase stack based print buffer size in probe Increase the size of temporary print buffer on stack to fix the following warnings reported by LKP. Since all the input parameters of snprintf() are under control of this driver, it is not possible to trigger and overflow here, but since the print buffer is on stack and discarded once driver probe() finishes, it is not an issue to increase it by 10 bytes and fix the warning in the process. Make it so. " drivers/clk/clk-si521xx.c: In function 'si521xx_probe': >> drivers/clk/clk-si521xx.c:318:26: warning: '%d' directive output may be truncated writing between 1 and 10 bytes into a region of size 2 [-Wformat-truncation=] snprintf(name, 6, "DIFF%d", i); ^~ drivers/clk/clk-si521xx.c:318:21: note: directive argument in the range [0, 2147483647] snprintf(name, 6, "DIFF%d", i); ^~~~~~~~ drivers/clk/clk-si521xx.c:318:3: note: 'snprintf' output between 6 and 15 bytes into a destination of size 6 snprintf(name, 6, "DIFF%d", i); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ " Fixes: edc12763a3a2 ("clk: si521xx: Clock driver for Skyworks Si521xx I2C PCIe clock generators") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310260412.AGASjFN4-lkp@intel.com/ Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20231027085840.30098-1-marex@denx.de Signed-off-by: Stephen Boyd --- drivers/clk/clk-si521xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index 14c8741b9ba0..0f8da64f87bb 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -282,7 +282,7 @@ static int si521xx_probe(struct i2c_client *client) const u16 chip_info = (u16)(uintptr_t)i2c_get_match_data(client); const struct clk_parent_data clk_parent_data = { .index = 0 }; struct si521xx *si; - unsigned char name[6] = "DIFF0"; + unsigned char name[16] = "DIFF0"; struct clk_init_data init = {}; int i, ret; @@ -315,7 +315,7 @@ static int si521xx_probe(struct i2c_client *client) /* Register clock */ for (i = 0; i < hweight16(chip_info); i++) { memset(&init, 0, sizeof(init)); - snprintf(name, 6, "DIFF%d", i); + snprintf(name, sizeof(name), "DIFF%d", i); init.name = name; init.ops = &si521xx_diff_clk_ops; init.parent_data = &clk_parent_data; From b7c3ca3553d1de5e86c85636828e186d30cd0628 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Thu, 26 Oct 2023 00:53:28 -0700 Subject: [PATCH 367/396] hte: tegra: Fix missing error code in tegra_hte_test_probe() The value of 'ret' is zero when of_hte_req_count() fails to get number of entitties to timestamp. And returning success(zero) on this failure path is incorrect. Fixes: 9a75a7cd03c9 ("hte: Add Tegra HTE test driver") Signed-off-by: Harshit Mogalapalli Reviewed-by: Dipen Patel Signed-off-by: Dipen Patel --- drivers/hte/hte-tegra194-test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hte/hte-tegra194-test.c b/drivers/hte/hte-tegra194-test.c index ba37a5efbf82..ab2edff018eb 100644 --- a/drivers/hte/hte-tegra194-test.c +++ b/drivers/hte/hte-tegra194-test.c @@ -153,8 +153,10 @@ static int tegra_hte_test_probe(struct platform_device *pdev) } cnt = of_hte_req_count(hte.pdev); - if (cnt < 0) + if (cnt < 0) { + ret = cnt; goto free_irq; + } dev_info(&pdev->dev, "Total requested lines:%d\n", cnt); From fc62d5e214df2dd64f5d675f01b609d86a422a2b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Oct 2023 17:11:23 +0300 Subject: [PATCH 368/396] hte: Use kasprintf() instead of fixed buffer formatting Improve readability and maintainability by replacing a hardcoded string allocation and formatting by the use of the kasprintf() helper. Signed-off-by: Andy Shevchenko Reviewed-by: Dipen Patel Signed-off-by: Dipen Patel --- drivers/hte/hte.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/hte/hte.c b/drivers/hte/hte.c index 1fd8d2d4528b..23a6eeb8c506 100644 --- a/drivers/hte/hte.c +++ b/drivers/hte/hte.c @@ -17,8 +17,6 @@ #include #include -#define HTE_TS_NAME_LEN 10 - /* Global list of the HTE devices */ static DEFINE_SPINLOCK(hte_lock); static LIST_HEAD(hte_devices); @@ -389,13 +387,10 @@ static int __hte_req_ts(struct hte_ts_desc *desc, hte_ts_cb_t cb, atomic_inc(&gdev->ts_req); - ei->line_name = NULL; - if (!desc->attr.name) { - ei->line_name = kzalloc(HTE_TS_NAME_LEN, GFP_KERNEL); - if (ei->line_name) - scnprintf(ei->line_name, HTE_TS_NAME_LEN, "ts_%u", - desc->attr.line_id); - } + if (desc->attr.name) + ei->line_name = NULL; + else + ei->line_name = kasprintf(GFP_KERNEL, "ts_%u", desc->attr.line_id); hte_ts_dbgfs_init(desc->attr.name == NULL ? ei->line_name : desc->attr.name, ei); From 75357829cc8ef20808f38b6256fa167f36267c9f Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 27 Oct 2023 15:58:21 -0700 Subject: [PATCH 369/396] clk: Fix clk gate kunit test on big-endian CPUs The clk gate kunit test checks that the implementation of the basic clk gate reads and writes the proper bits in an MMIO register. The implementation of the basic clk gate type uses writel() and readl() which operate on little-endian registers. This test fails on big-endian CPUs because the clk gate implementation writes to 'fake_reg' with writel(), which converts the value to be written to little-endian before storing the value in the fake register. When the test checks the bits in the fake register on a big-endian machine it falsely assumes the format of the register is also big-endian, when it is really always little-endian. Suffice to say things don't work very well. Mark 'fake_reg' as __le32 and push through endian accessor fixes wherever the value is inspected to make this test endian agnostic. There's a CLK_GATE_BIG_ENDIAN flag for big-endian MMIO devices, which this test isn't using. A follow-up patch will test with and without that flag. Reported-by: Boqun Feng Closes: https://lore.kernel.org/r/ZTLH5o0GlFBYsAHq@boqun-archlinux Tested-by: Boqun Feng Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20231027225821.95833-1-sboyd@kernel.org --- drivers/clk/clk-gate_test.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/clk/clk-gate_test.c b/drivers/clk/clk-gate_test.c index e136aaad48bf..c96d93b19ddf 100644 --- a/drivers/clk/clk-gate_test.c +++ b/drivers/clk/clk-gate_test.c @@ -131,7 +131,7 @@ struct clk_gate_test_context { void __iomem *fake_mem; struct clk_hw *hw; struct clk_hw *parent; - u32 fake_reg; /* Keep at end, KASAN can detect out of bounds */ + __le32 fake_reg; /* Keep at end, KASAN can detect out of bounds */ }; static struct clk_gate_test_context *clk_gate_test_alloc_ctx(struct kunit *test) @@ -166,7 +166,7 @@ static void clk_gate_test_enable(struct kunit *test) KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); - KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); @@ -183,10 +183,10 @@ static void clk_gate_test_disable(struct kunit *test) u32 disable_val = 0; KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); - KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); clk_disable_unprepare(clk); - KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg); + KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg)); KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); @@ -246,7 +246,7 @@ static void clk_gate_test_invert_enable(struct kunit *test) KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); - KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); @@ -263,10 +263,10 @@ static void clk_gate_test_invert_disable(struct kunit *test) u32 disable_val = BIT(15); KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); - KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); clk_disable_unprepare(clk); - KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg); + KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg)); KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); @@ -290,7 +290,7 @@ static int clk_gate_test_invert_init(struct kunit *test) 2000000); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); - ctx->fake_reg = BIT(15); /* Default to off */ + ctx->fake_reg = cpu_to_le32(BIT(15)); /* Default to off */ hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0, ctx->fake_mem, 15, CLK_GATE_SET_TO_DISABLE, NULL); @@ -319,7 +319,7 @@ static void clk_gate_test_hiword_enable(struct kunit *test) KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); - KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw)); KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw)); KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent)); @@ -336,10 +336,10 @@ static void clk_gate_test_hiword_disable(struct kunit *test) u32 disable_val = BIT(9 + 16); KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0); - KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg); + KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg)); clk_disable_unprepare(clk); - KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg); + KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg)); KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw)); KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw)); KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent)); @@ -387,7 +387,7 @@ static void clk_gate_test_is_enabled(struct kunit *test) struct clk_gate_test_context *ctx; ctx = clk_gate_test_alloc_ctx(test); - ctx->fake_reg = BIT(7); + ctx->fake_reg = cpu_to_le32(BIT(7)); hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7, 0, NULL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); @@ -402,7 +402,7 @@ static void clk_gate_test_is_disabled(struct kunit *test) struct clk_gate_test_context *ctx; ctx = clk_gate_test_alloc_ctx(test); - ctx->fake_reg = BIT(4); + ctx->fake_reg = cpu_to_le32(BIT(4)); hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7, 0, NULL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); @@ -417,7 +417,7 @@ static void clk_gate_test_is_enabled_inverted(struct kunit *test) struct clk_gate_test_context *ctx; ctx = clk_gate_test_alloc_ctx(test); - ctx->fake_reg = BIT(31); + ctx->fake_reg = cpu_to_le32(BIT(31)); hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 2, CLK_GATE_SET_TO_DISABLE, NULL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); @@ -432,7 +432,7 @@ static void clk_gate_test_is_disabled_inverted(struct kunit *test) struct clk_gate_test_context *ctx; ctx = clk_gate_test_alloc_ctx(test); - ctx->fake_reg = BIT(29); + ctx->fake_reg = cpu_to_le32(BIT(29)); hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 29, CLK_GATE_SET_TO_DISABLE, NULL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); From 47ea0ddb1f5604ba3496baa19110aec6a3151f2e Mon Sep 17 00:00:00 2001 From: Lalith Rajendran Date: Fri, 27 Oct 2023 16:02:22 -0500 Subject: [PATCH 370/396] platform/chrome: cros_ec_lpc: Separate host command and irq disable Both cros host command and irq disable were moved to suspend prepare stage from late suspend recently. This is causing EC to report MKBP event timeouts during suspend stress testing. When the MKBP event timeouts happen during suspend, subsequent wakeup of AP by EC using MKBP doesn't happen properly. Move the irq disabling part back to late suspend stage which is a general suggestion from the suspend kernel documentaiton to do irq disable as late as possible. Fixes: 4b9abbc132b8 ("platform/chrome: cros_ec_lpc: Move host command to prepare/complete") Signed-off-by: Lalith Rajendran Link: https://lore.kernel.org/r/20231027160221.v4.1.I1725c3ed27eb7cd9836904e49e8bfa9fb0200a97@changeid Signed-off-by: Tzung-Bi Shih --- drivers/platform/chrome/cros_ec.c | 116 +++++++++++++++++++++----- drivers/platform/chrome/cros_ec.h | 4 + drivers/platform/chrome/cros_ec_lpc.c | 22 ++++- 3 files changed, 116 insertions(+), 26 deletions(-) diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index 5d36fbc75e1b..badc68bbae8c 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -321,17 +321,8 @@ void cros_ec_unregister(struct cros_ec_device *ec_dev) EXPORT_SYMBOL(cros_ec_unregister); #ifdef CONFIG_PM_SLEEP -/** - * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device. - * @ec_dev: Device to suspend. - * - * This can be called by drivers to handle a suspend event. - * - * Return: 0 on success or negative error code. - */ -int cros_ec_suspend(struct cros_ec_device *ec_dev) +static void cros_ec_send_suspend_event(struct cros_ec_device *ec_dev) { - struct device *dev = ec_dev->dev; int ret; u8 sleep_event; @@ -343,7 +334,26 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev) if (ret < 0) dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec\n", ret); +} +/** + * cros_ec_suspend_prepare() - Handle a suspend prepare operation for the ChromeOS EC device. + * @ec_dev: Device to suspend. + * + * This can be called by drivers to handle a suspend prepare stage of suspend. + * + * Return: 0 always. + */ +int cros_ec_suspend_prepare(struct cros_ec_device *ec_dev) +{ + cros_ec_send_suspend_event(ec_dev); + return 0; +} +EXPORT_SYMBOL(cros_ec_suspend_prepare); + +static void cros_ec_disable_irq(struct cros_ec_device *ec_dev) +{ + struct device *dev = ec_dev->dev; if (device_may_wakeup(dev)) ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); else @@ -351,7 +361,35 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev) disable_irq(ec_dev->irq); ec_dev->suspended = true; +} +/** + * cros_ec_suspend_late() - Handle a suspend late operation for the ChromeOS EC device. + * @ec_dev: Device to suspend. + * + * This can be called by drivers to handle a suspend late stage of suspend. + * + * Return: 0 always. + */ +int cros_ec_suspend_late(struct cros_ec_device *ec_dev) +{ + cros_ec_disable_irq(ec_dev); + return 0; +} +EXPORT_SYMBOL(cros_ec_suspend_late); + +/** + * cros_ec_suspend() - Handle a suspend operation for the ChromeOS EC device. + * @ec_dev: Device to suspend. + * + * This can be called by drivers to handle a suspend event. + * + * Return: 0 always. + */ +int cros_ec_suspend(struct cros_ec_device *ec_dev) +{ + cros_ec_send_suspend_event(ec_dev); + cros_ec_disable_irq(ec_dev); return 0; } EXPORT_SYMBOL(cros_ec_suspend); @@ -370,22 +408,11 @@ static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev) } } -/** - * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device. - * @ec_dev: Device to resume. - * - * This can be called by drivers to handle a resume event. - * - * Return: 0 on success or negative error code. - */ -int cros_ec_resume(struct cros_ec_device *ec_dev) +static void cros_ec_send_resume_event(struct cros_ec_device *ec_dev) { int ret; u8 sleep_event; - ec_dev->suspended = false; - enable_irq(ec_dev->irq); - sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ? HOST_SLEEP_EVENT_S3_RESUME : HOST_SLEEP_EVENT_S0IX_RESUME; @@ -394,6 +421,24 @@ int cros_ec_resume(struct cros_ec_device *ec_dev) if (ret < 0) dev_dbg(ec_dev->dev, "Error %d sending resume event to ec\n", ret); +} + +/** + * cros_ec_resume_complete() - Handle a resume complete operation for the ChromeOS EC device. + * @ec_dev: Device to resume. + * + * This can be called by drivers to handle a resume complete stage of resume. + */ +void cros_ec_resume_complete(struct cros_ec_device *ec_dev) +{ + cros_ec_send_resume_event(ec_dev); +} +EXPORT_SYMBOL(cros_ec_resume_complete); + +static void cros_ec_enable_irq(struct cros_ec_device *ec_dev) +{ + ec_dev->suspended = false; + enable_irq(ec_dev->irq); if (ec_dev->wake_enabled) disable_irq_wake(ec_dev->irq); @@ -403,8 +448,35 @@ int cros_ec_resume(struct cros_ec_device *ec_dev) * suspend. This way the clients know what to do with them. */ cros_ec_report_events_during_suspend(ec_dev); +} +/** + * cros_ec_resume_early() - Handle a resume early operation for the ChromeOS EC device. + * @ec_dev: Device to resume. + * + * This can be called by drivers to handle a resume early stage of resume. + * + * Return: 0 always. + */ +int cros_ec_resume_early(struct cros_ec_device *ec_dev) +{ + cros_ec_enable_irq(ec_dev); + return 0; +} +EXPORT_SYMBOL(cros_ec_resume_early); +/** + * cros_ec_resume() - Handle a resume operation for the ChromeOS EC device. + * @ec_dev: Device to resume. + * + * This can be called by drivers to handle a resume event. + * + * Return: 0 always. + */ +int cros_ec_resume(struct cros_ec_device *ec_dev) +{ + cros_ec_enable_irq(ec_dev); + cros_ec_send_resume_event(ec_dev); return 0; } EXPORT_SYMBOL(cros_ec_resume); diff --git a/drivers/platform/chrome/cros_ec.h b/drivers/platform/chrome/cros_ec.h index 2b2574236030..6b95f1e0bace 100644 --- a/drivers/platform/chrome/cros_ec.h +++ b/drivers/platform/chrome/cros_ec.h @@ -16,7 +16,11 @@ int cros_ec_register(struct cros_ec_device *ec_dev); void cros_ec_unregister(struct cros_ec_device *ec_dev); int cros_ec_suspend(struct cros_ec_device *ec_dev); +int cros_ec_suspend_late(struct cros_ec_device *ec_dev); +int cros_ec_suspend_prepare(struct cros_ec_device *ec_dev); int cros_ec_resume(struct cros_ec_device *ec_dev); +int cros_ec_resume_early(struct cros_ec_device *ec_dev); +void cros_ec_resume_complete(struct cros_ec_device *ec_dev); irqreturn_t cros_ec_irq_thread(int irq, void *data); diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 897090f0f26e..f0f3d3d56157 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -547,22 +547,36 @@ MODULE_DEVICE_TABLE(dmi, cros_ec_lpc_dmi_table); static int cros_ec_lpc_prepare(struct device *dev) { struct cros_ec_device *ec_dev = dev_get_drvdata(dev); - - return cros_ec_suspend(ec_dev); + return cros_ec_suspend_prepare(ec_dev); } static void cros_ec_lpc_complete(struct device *dev) { struct cros_ec_device *ec_dev = dev_get_drvdata(dev); - cros_ec_resume(ec_dev); + cros_ec_resume_complete(ec_dev); +} + +static int cros_ec_lpc_suspend_late(struct device *dev) +{ + struct cros_ec_device *ec_dev = dev_get_drvdata(dev); + + return cros_ec_suspend_late(ec_dev); +} + +static int cros_ec_lpc_resume_early(struct device *dev) +{ + struct cros_ec_device *ec_dev = dev_get_drvdata(dev); + + return cros_ec_resume_early(ec_dev); } #endif static const struct dev_pm_ops cros_ec_lpc_pm_ops = { #ifdef CONFIG_PM_SLEEP .prepare = cros_ec_lpc_prepare, - .complete = cros_ec_lpc_complete + .complete = cros_ec_lpc_complete, #endif + SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_lpc_suspend_late, cros_ec_lpc_resume_early) }; static struct platform_driver cros_ec_lpc_driver = { From 1b515cfee17810e74cda9cf020e302747821d46c Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Tue, 24 Oct 2023 11:50:17 +0530 Subject: [PATCH 371/396] hwmon: (nct6775) use acpi_dev_hid_uid_match() for matching _HID and _UID Convert manual _UID references to use the standard ACPI helper. Signed-off-by: Raag Jadav Link: https://lore.kernel.org/r/20231024062018.23839-6-raag.jadav@intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775-platform.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index 81bf03dad6bb..0adeeab7ee03 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -1465,10 +1465,8 @@ static const char * const asus_msi_boards[] = { static int nct6775_asuswmi_device_match(struct device *dev, void *data) { struct acpi_device *adev = to_acpi_device(dev); - const char *uid = acpi_device_uid(adev); - const char *hid = acpi_device_hid(adev); - if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && uid && !strcmp(uid, data)) { + if (acpi_dev_hid_uid_match(adev, ASUSWMI_DEVICE_HID, data)) { asus_acpi_dev = adev; return 1; } From 748465a53eedbc2c440ac07f6b2328de6263dbfd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 23 Oct 2023 14:58:28 +0100 Subject: [PATCH 372/396] hwmon: (hs3001) remove redundant store on division Currently the local variable hum is being divided by a constant and the results is being re-assigned back to hum before the value is being returned to the caller. The assignment to hum is redundant and can be removed. Cleans up clang scan build warning: drivers/hwmon/hs3001.c:65:9: warning: Although the value stored to 'hum' is used in the enclosing expression, the value is never actually read from 'hum' [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20231023135828.667297-1-colin.i.king@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/hs3001.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/hs3001.c b/drivers/hwmon/hs3001.c index ac574e46d069..01ea9a3062bc 100644 --- a/drivers/hwmon/hs3001.c +++ b/drivers/hwmon/hs3001.c @@ -62,7 +62,7 @@ static u32 hs3001_extract_humidity(u16 raw) { u32 hum = (raw & HS3001_MASK_HUMIDITY_0X3FFF) * HS3001_FIXPOINT_ARITH * 100; - return hum /= (1 << 14) - 1; + return hum / (1 << 14) - 1; } static int hs3001_data_fetch_command(struct i2c_client *client, From b92b2984a5b62099ab7731bc3a30a0d7c83a01d4 Mon Sep 17 00:00:00 2001 From: Su Hui Date: Fri, 20 Oct 2023 16:55:19 +0800 Subject: [PATCH 373/396] hwmon: (npcm750-pwm) Add an error code check in npcm7xx_en_pwm_fan npcm7xx_pwm_config_set() can return '-ENODEV' for failed. So check the value of 'ret' after calling npcm7xx_pwm_config_set(). Signed-off-by: Su Hui Link: https://lore.kernel.org/r/20231020085518.198477-1-suhui@nfschina.com Signed-off-by: Guenter Roeck --- drivers/hwmon/npcm750-pwm-fan.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c index 10ed3f4335d4..4702e4edc662 100644 --- a/drivers/hwmon/npcm750-pwm-fan.c +++ b/drivers/hwmon/npcm750-pwm-fan.c @@ -875,6 +875,8 @@ static int npcm7xx_en_pwm_fan(struct device *dev, data->pwm_present[pwm_port] = true; ret = npcm7xx_pwm_config_set(data, pwm_port, NPCM7XX_PWM_CMR_DEFAULT_NUM); + if (ret) + return ret; ret = of_property_count_u8_elems(child, "cooling-levels"); if (ret > 0) { From 10b02902048737f376104bc69e5212466e65a542 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Wed, 11 Oct 2023 16:57:53 +0300 Subject: [PATCH 374/396] hwmon: (ltc2992) Avoid division by zero Do not allow setting shunt resistor to 0. This results in a division by zero when performing current value computations based on input voltages and connected resistor values. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20231011135754.13508-1-antoniu.miclaus@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/ltc2992.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c index 589bcd07ce7f..001799bc28ed 100644 --- a/drivers/hwmon/ltc2992.c +++ b/drivers/hwmon/ltc2992.c @@ -875,8 +875,12 @@ static int ltc2992_parse_dt(struct ltc2992_state *st) } ret = fwnode_property_read_u32(child, "shunt-resistor-micro-ohms", &val); - if (!ret) + if (!ret) { + if (!val) + return dev_err_probe(&st->client->dev, -EINVAL, + "shunt resistor value cannot be zero\n"); st->r_sense_uohm[addr] = val; + } } return 0; From 05b68e18ec64663be11119dd48de52fec927dfde Mon Sep 17 00:00:00 2001 From: Alexander Koskovich Date: Mon, 23 Oct 2023 18:24:59 +0000 Subject: [PATCH 375/396] hwmon: (nct6683) Add another customer ID for ASRock X670E Taichi This value was found on an ASRock X670E Taichi with an NCT6686D chip. Signed-off-by: Alexander Koskovich Link: https://lore.kernel.org/r/20231023182442.21943-1-akoskovich@pm.me Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct6683.rst | 1 + drivers/hwmon/nct6683.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Documentation/hwmon/nct6683.rst b/Documentation/hwmon/nct6683.rst index 2e1408d174bd..3e7f6ee779c2 100644 --- a/Documentation/hwmon/nct6683.rst +++ b/Documentation/hwmon/nct6683.rst @@ -62,5 +62,6 @@ Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13 Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13 Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13 ASRock X570 NCT6683D EC firmware version 1.0 build 06/28/19 +ASRock X670E NCT6686D EC firmware version 1.0 build 05/19/22 MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20 =============== =============================================== diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index f673f7d07941..3f3f7a88413e 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -176,6 +176,7 @@ superio_exit(int ioreg) #define NCT6683_CUSTOMER_ID_MSI2 0x200 #define NCT6683_CUSTOMER_ID_ASROCK 0xe2c #define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b +#define NCT6683_CUSTOMER_ID_ASROCK3 0x1631 #define NCT6683_REG_BUILD_YEAR 0x604 #define NCT6683_REG_BUILD_MONTH 0x605 @@ -1227,6 +1228,8 @@ static int nct6683_probe(struct platform_device *pdev) break; case NCT6683_CUSTOMER_ID_ASROCK2: break; + case NCT6683_CUSTOMER_ID_ASROCK3: + break; default: if (!force) return -ENODEV; From b344041db783c4cb1e1944a1d5eae6651af72483 Mon Sep 17 00:00:00 2001 From: Hal Feng Date: Thu, 28 Sep 2023 15:52:49 +0800 Subject: [PATCH 376/396] MAINTAINERS: Add Hal as one of the maintainers of SFCTEMP HWMON DRIVER As he is the submitter of this driver, add his mail so he can maintain the driver and easily reply in the mailing list. Acked-by: Emil Renner Berthing Signed-off-by: Hal Feng Link: https://lore.kernel.org/r/20230928075249.109459-1-hal.feng@starfivetech.com Signed-off-by: Guenter Roeck --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 44d394dc97c7..d0ce1a122ddf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19409,6 +19409,7 @@ F: drivers/net/ethernet/sfc/ SFCTEMP HWMON DRIVER M: Emil Renner Berthing +M: Hal Feng L: linux-hwmon@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml From 9ca6696718cc3f8ca94172d834567f35500f21bf Mon Sep 17 00:00:00 2001 From: Daniel Matyas Date: Tue, 19 Sep 2023 12:34:49 +0300 Subject: [PATCH 377/396] hwmon: (max31827) Make code cleaner Used enums and while loops to replace switch for selecting and getting update interval from conversion rate bits. Divided the write_alarm_val function into 2 functions. The new function is more generic: it can be used not only for alarm writes, but for any kind of writes which require the device to be in shutdown mode. Signed-off-by: Daniel Matyas Link: https://lore.kernel.org/r/20230919093456.10592-1-daniel.matyas@analog.com [groeck: Reverted error return value change (EOPNOTSUPP -> EINVAL)] Signed-off-by: Guenter Roeck --- drivers/hwmon/max31827.c | 125 +++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 70 deletions(-) diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c index 602f4e4f81ff..6e3e034aae32 100644 --- a/drivers/hwmon/max31827.c +++ b/drivers/hwmon/max31827.c @@ -27,18 +27,30 @@ #define MAX31827_12_BIT_CNV_TIME 141 -#define MAX31827_CNV_1_DIV_64_HZ 0x1 -#define MAX31827_CNV_1_DIV_32_HZ 0x2 -#define MAX31827_CNV_1_DIV_16_HZ 0x3 -#define MAX31827_CNV_1_DIV_4_HZ 0x4 -#define MAX31827_CNV_1_HZ 0x5 -#define MAX31827_CNV_4_HZ 0x6 -#define MAX31827_CNV_8_HZ 0x7 - #define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16) #define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000) #define MAX31827_DEVICE_ENABLE(x) ((x) ? 0xA : 0x0) +enum max31827_cnv { + MAX31827_CNV_1_DIV_64_HZ = 1, + MAX31827_CNV_1_DIV_32_HZ, + MAX31827_CNV_1_DIV_16_HZ, + MAX31827_CNV_1_DIV_4_HZ, + MAX31827_CNV_1_HZ, + MAX31827_CNV_4_HZ, + MAX31827_CNV_8_HZ, +}; + +static const u16 max31827_conversions[] = { + [MAX31827_CNV_1_DIV_64_HZ] = 64000, + [MAX31827_CNV_1_DIV_32_HZ] = 32000, + [MAX31827_CNV_1_DIV_16_HZ] = 16000, + [MAX31827_CNV_1_DIV_4_HZ] = 4000, + [MAX31827_CNV_1_HZ] = 1000, + [MAX31827_CNV_4_HZ] = 250, + [MAX31827_CNV_8_HZ] = 125, +}; + struct max31827_state { /* * Prevent simultaneous access to the i2c client. @@ -54,15 +66,13 @@ static const struct regmap_config max31827_regmap = { .max_register = 0xA, }; -static int write_alarm_val(struct max31827_state *st, unsigned int reg, - long val) +static int shutdown_write(struct max31827_state *st, unsigned int reg, + unsigned int val) { unsigned int cfg; - unsigned int tmp; + unsigned int cnv_rate; int ret; - val = MAX31827_M_DGR_TO_16_BIT(val); - /* * Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold * register values are changed over I2C, the part must be in shutdown @@ -82,9 +92,10 @@ static int write_alarm_val(struct max31827_state *st, unsigned int reg, if (ret) goto unlock; - tmp = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK | + cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg; + cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK | MAX31827_CONFIGURATION_CNV_RATE_MASK); - ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, tmp); + ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg); if (ret) goto unlock; @@ -92,13 +103,23 @@ static int write_alarm_val(struct max31827_state *st, unsigned int reg, if (ret) goto unlock; - ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg); + ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_CNV_RATE_MASK, + cnv_rate); unlock: mutex_unlock(&st->lock); return ret; } +static int write_alarm_val(struct max31827_state *st, unsigned int reg, + long val) +{ + val = MAX31827_M_DGR_TO_16_BIT(val); + + return shutdown_write(st, reg, val); +} + static umode_t max31827_is_visible(const void *state, enum hwmon_sensor_types type, u32 attr, int channel) @@ -243,32 +264,7 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK, uval); - switch (uval) { - case MAX31827_CNV_1_DIV_64_HZ: - *val = 64000; - break; - case MAX31827_CNV_1_DIV_32_HZ: - *val = 32000; - break; - case MAX31827_CNV_1_DIV_16_HZ: - *val = 16000; - break; - case MAX31827_CNV_1_DIV_4_HZ: - *val = 4000; - break; - case MAX31827_CNV_1_HZ: - *val = 1000; - break; - case MAX31827_CNV_4_HZ: - *val = 250; - break; - case MAX31827_CNV_8_HZ: - *val = 125; - break; - default: - *val = 0; - break; - } + *val = max31827_conversions[uval]; } break; @@ -284,6 +280,7 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { struct max31827_state *st = dev_get_drvdata(dev); + int res = 1; int ret; switch (type) { @@ -333,39 +330,27 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, if (!st->enable) return -EINVAL; - switch (val) { - case 125: - val = MAX31827_CNV_8_HZ; - break; - case 250: - val = MAX31827_CNV_4_HZ; - break; - case 1000: - val = MAX31827_CNV_1_HZ; - break; - case 4000: - val = MAX31827_CNV_1_DIV_4_HZ; - break; - case 16000: - val = MAX31827_CNV_1_DIV_16_HZ; - break; - case 32000: - val = MAX31827_CNV_1_DIV_32_HZ; - break; - case 64000: - val = MAX31827_CNV_1_DIV_64_HZ; - break; - default: - return -EINVAL; - } + /* + * Convert the desired conversion rate into register + * bits. res is already initialized with 1. + * + * This was inspired by lm73 driver. + */ + while (res < ARRAY_SIZE(max31827_conversions) && + val < max31827_conversions[res]) + res++; - val = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK, - val); + if (res == ARRAY_SIZE(max31827_conversions) || + val != max31827_conversions[res]) + return -EINVAL; + + res = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK, + res); return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, MAX31827_CONFIGURATION_CNV_RATE_MASK, - val); + res); } break; From 8824557037d50f7819cef07b32ca9974965bd7ba Mon Sep 17 00:00:00 2001 From: Daniel Matyas Date: Tue, 19 Sep 2023 12:34:50 +0300 Subject: [PATCH 378/396] hwmon: (max31827) Modify conversion wait time There is nothing in the datasheet indicating that the 1ms error is needed and I didn't encounter any error during testing with 140ms wait time. Signed-off-by: Daniel Matyas Link: https://lore.kernel.org/r/20230919093456.10592-2-daniel.matyas@analog.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/max31827.rst | 4 ++-- drivers/hwmon/max31827.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst index b0971d05b8a4..9a1055a007cf 100644 --- a/Documentation/hwmon/max31827.rst +++ b/Documentation/hwmon/max31827.rst @@ -73,8 +73,8 @@ the conversion frequency to 1 conv/s. The conversion time varies depending on the resolution. The conversion time doubles with every bit of increased resolution. For 10 bit resolution 35ms are needed, while for 12 bit resolution (default) 140ms. When chip is in shutdown mode and a read operation is -requested, one-shot is triggered, the device waits for 140 (conversion time) + 1 -(error) ms, and only after that is the temperature value register read. +requested, one-shot is triggered, the device waits for 140 (conversion time) ms, +and only after that is the temperature value register read. The LSB of the temperature values is 0.0625 degrees Celsius, but the values of the temperatures are displayed in milli-degrees. This means, that some data is diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c index 6e3e034aae32..614bbf5d25fa 100644 --- a/drivers/hwmon/max31827.c +++ b/drivers/hwmon/max31827.c @@ -25,7 +25,7 @@ #define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK BIT(14) #define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK BIT(15) -#define MAX31827_12_BIT_CNV_TIME 141 +#define MAX31827_12_BIT_CNV_TIME 140 #define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16) #define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000) From 6632b45606bdcf14a9ee576c21f0d8331a99df9f Mon Sep 17 00:00:00 2001 From: Daniel Matyas Date: Tue, 19 Sep 2023 12:34:51 +0300 Subject: [PATCH 379/396] dt-bindings: hwmon: Add possible new properties to max31827 bindings These modify the corresponding bits in the configuration register. adi,comp-int is a hardware property, because it affects the behavior of the interrupt signal and whatever it is connected to. adi,timeout-enable is a hardware property, because it affects i2c bus operation. Signed-off-by: Daniel Matyas Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230919093456.10592-3-daniel.matyas@analog.com Signed-off-by: Guenter Roeck --- .../bindings/hwmon/adi,max31827.yaml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml index 2dc8b07b4d3b..f60e06ab7d0a 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml @@ -32,6 +32,68 @@ properties: Must have values in the interval (1.6V; 3.6V) in order for the device to function correctly. + adi,comp-int: + description: + If present interrupt mode is used. If not present comparator mode is used + (default). + type: boolean + + adi,alarm-pol: + description: + Sets the alarms active state. + - 0 = active low + - 1 = active high + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1] + + adi,fault-q: + description: + Select how many consecutive temperature faults must occur before + overtemperature or undertemperature faults are indicated in the + corresponding status bits. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 4, 8] + + adi,timeout-enable: + description: + Enables timeout. Bus timeout resets the I2C-compatible interface when SCL + is low for more than 30ms (nominal). + type: boolean + +allOf: + - if: + properties: + compatible: + contains: + const: adi,max31829 + + then: + properties: + adi,alarm-pol: + default: 1 + + else: + properties: + adi,alarm-pol: + default: 0 + + - if: + properties: + compatible: + contains: + const: adi,max31827 + + then: + properties: + adi,fault-q: + default: 1 + + else: + properties: + adi,fault-q: + default: 4 + + required: - compatible - reg @@ -49,6 +111,10 @@ examples: compatible = "adi,max31827"; reg = <0x42>; vref-supply = <®_vdd>; + adi,comp-int; + adi,alarm-pol = <0>; + adi,fault-q = <1>; + adi,timeout-enable; }; }; ... From b1a55c0af684fdab2229770a40e708b4138c6389 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Wed, 11 Oct 2023 22:17:51 +0530 Subject: [PATCH 380/396] hwmon: (pmbus/mpq7932) Get page count based on chip info Get page count using compatible match to support the series of chipsets which differs in number of regualator/page. Signed-off-by: Saravanan Sekar Link: https://lore.kernel.org/r/20231011164754.449399-2-saravanan@linumiz.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/mpq7932.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c index 6c62f01da7c6..723c314a57a2 100644 --- a/drivers/hwmon/pmbus/mpq7932.c +++ b/drivers/hwmon/pmbus/mpq7932.c @@ -105,7 +105,7 @@ static int mpq7932_probe(struct i2c_client *client) return -ENOMEM; info = &data->info; - info->pages = MPQ7932_NUM_PAGES; + info->pages = (int)(unsigned long)device_get_match_data(&client->dev); info->format[PSC_VOLTAGE_OUT] = direct; info->m[PSC_VOLTAGE_OUT] = 160; info->b[PSC_VOLTAGE_OUT] = -33; @@ -115,7 +115,7 @@ static int mpq7932_probe(struct i2c_client *client) } #if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR) - info->num_regulators = ARRAY_SIZE(mpq7932_regulators_desc); + info->num_regulators = info->pages; info->reg_desc = mpq7932_regulators_desc; #endif @@ -129,7 +129,7 @@ static int mpq7932_probe(struct i2c_client *client) } static const struct of_device_id mpq7932_of_match[] = { - { .compatible = "mps,mpq7932"}, + { .compatible = "mps,mpq7932", .data = (void *)MPQ7932_NUM_PAGES }, {}, }; MODULE_DEVICE_TABLE(of, mpq7932_of_match); From 90a801d5657a4b28d2c45023ee3a789463db2d64 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Wed, 11 Oct 2023 22:17:52 +0530 Subject: [PATCH 381/396] regulator: dt-bindings: Add mps,mpq2286 power-management IC Document mpq2286 power-management IC. Signed-off-by: Saravanan Sekar Acked-by: Mark Brown Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20231011164754.449399-3-saravanan@linumiz.com Signed-off-by: Guenter Roeck --- .../bindings/regulator/mps,mpq2286.yaml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/mps,mpq2286.yaml diff --git a/Documentation/devicetree/bindings/regulator/mps,mpq2286.yaml b/Documentation/devicetree/bindings/regulator/mps,mpq2286.yaml new file mode 100644 index 000000000000..1296f9b30862 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mps,mpq2286.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/mps,mpq2286.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Monolithic Power System MPQ2286 PMIC + +maintainers: + - Saravanan Sekar + +properties: + compatible: + enum: + - mps,mpq2286 + + reg: + maxItems: 1 + + regulators: + type: object + + properties: + buck: + type: object + $ref: regulator.yaml# + + unevaluatedProperties: false + + additionalProperties: false + +required: + - compatible + - reg + - regulators + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@3 { + compatible = "mps,mpq2286"; + reg = <0x3>; + + regulators { + buck { + regulator-name = "buck"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + }; + }; + }; +... From 88b5970e92d0d3f6df67fb80f441a84b2c36b23f Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Wed, 11 Oct 2023 22:17:53 +0530 Subject: [PATCH 382/396] hwmon: (pmbus/core) Add helper macro to define single pmbus regulator The bindings for single instance regulator should be named with no instance (e.g., buck not buck0). Introduce a new helper macro to define the single pmbus regulator. Signed-off-by: Saravanan Sekar Link: https://lore.kernel.org/r/20231011164754.449399-4-saravanan@linumiz.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 7a28bac7f171..fb442fae7b3e 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -489,6 +489,21 @@ extern const struct regulator_ops pmbus_regulator_ops; #define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0) +#define PMBUS_REGULATOR_STEP_ONE(_name, _voltages, _step, _min_uV) \ + { \ + .name = (_name), \ + .of_match = of_match_ptr(_name), \ + .regulators_node = of_match_ptr("regulators"), \ + .ops = &pmbus_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .n_voltages = _voltages, \ + .uV_step = _step, \ + .min_uV = _min_uV, \ + } + +#define PMBUS_REGULATOR_ONE(_name) PMBUS_REGULATOR_STEP_ONE(_name, 0, 0, 0) + /* Function declarations */ void pmbus_clear_cache(struct i2c_client *client); From fe0eba175e96820ae6b8ff2d6407ca5ab40a1d31 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Wed, 11 Oct 2023 22:17:54 +0530 Subject: [PATCH 383/396] hwmon: (pmbus/mpq7932) Add a support for mpq2286 Power Management IC The MPQ2286 is a programmable, high frequency synchronous buck regulator designed to power a variety of Automotive system peripherals. Single buck converters with hardware monitoring capability is configurable over PMBus interface. Signed-off-by: Saravanan Sekar Link: https://lore.kernel.org/r/20231011164754.449399-5-saravanan@linumiz.com [groeck: Updated subject (mpq2286 -> mpq7932)] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/mpq7932.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c index 723c314a57a2..67487867c70f 100644 --- a/drivers/hwmon/pmbus/mpq7932.c +++ b/drivers/hwmon/pmbus/mpq7932.c @@ -21,6 +21,7 @@ #define MPQ7932_N_VOLTAGES 256 #define MPQ7932_VOUT_MAX 0xFF #define MPQ7932_NUM_PAGES 6 +#define MPQ2286_NUM_PAGES 1 #define MPQ7932_TON_DELAY 0x60 #define MPQ7932_VOUT_STARTUP_SLEW 0xA3 @@ -48,6 +49,11 @@ static struct regulator_desc mpq7932_regulators_desc[] = { PMBUS_REGULATOR_STEP("buck", 5, MPQ7932_N_VOLTAGES, MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), }; + +static const struct regulator_desc mpq7932_regulators_desc_one[] = { + PMBUS_REGULATOR_STEP_ONE("buck", MPQ7932_N_VOLTAGES, + MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), +}; #endif static int mpq7932_write_word_data(struct i2c_client *client, int page, int reg, @@ -116,7 +122,10 @@ static int mpq7932_probe(struct i2c_client *client) #if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR) info->num_regulators = info->pages; - info->reg_desc = mpq7932_regulators_desc; + if (info->num_regulators == 1) + info->reg_desc = mpq7932_regulators_desc_one; + else + info->reg_desc = mpq7932_regulators_desc; #endif info->read_word_data = mpq7932_read_word_data; @@ -129,12 +138,14 @@ static int mpq7932_probe(struct i2c_client *client) } static const struct of_device_id mpq7932_of_match[] = { + { .compatible = "mps,mpq2286", .data = (void *)MPQ2286_NUM_PAGES }, { .compatible = "mps,mpq7932", .data = (void *)MPQ7932_NUM_PAGES }, {}, }; MODULE_DEVICE_TABLE(of, mpq7932_of_match); static const struct i2c_device_id mpq7932_id[] = { + { "mpq2286", }, { "mpq7932", }, { }, }; From 81b75e336c139be9ad4b3dce56d24e722850d2b4 Mon Sep 17 00:00:00 2001 From: Ninad Malwade Date: Fri, 29 Sep 2023 11:36:47 +0100 Subject: [PATCH 384/396] dt-bindings: hwmon: ina3221: Convert to json-schema Convert the TI INA3221 bindings from the free-form text format to json-schema. Note that the INA3221 input channels default to enabled in the chip. Unless channels are explicitly disabled in device-tree, input channels will be enabled. Signed-off-by: Thierry Reding Signed-off-by: Ninad Malwade Signed-off-by: Jon Hunter Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230929103650.86074-2-jonathanh@nvidia.com Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ina3221.txt | 54 ---------- .../devicetree/bindings/hwmon/ti,ina3221.yaml | 102 ++++++++++++++++++ 2 files changed, 102 insertions(+), 54 deletions(-) delete mode 100644 Documentation/devicetree/bindings/hwmon/ina3221.txt create mode 100644 Documentation/devicetree/bindings/hwmon/ti,ina3221.yaml diff --git a/Documentation/devicetree/bindings/hwmon/ina3221.txt b/Documentation/devicetree/bindings/hwmon/ina3221.txt deleted file mode 100644 index fa63b6171407..000000000000 --- a/Documentation/devicetree/bindings/hwmon/ina3221.txt +++ /dev/null @@ -1,54 +0,0 @@ -Texas Instruments INA3221 Device Tree Bindings - -1) ina3221 node - Required properties: - - compatible: Must be "ti,ina3221" - - reg: I2C address - - Optional properties: - - ti,single-shot: This chip has two power modes: single-shot (chip takes one - measurement and then shuts itself down) and continuous ( - chip takes continuous measurements). The continuous mode is - more reliable and suitable for hardware monitor type device, - but the single-shot mode is more power-friendly and useful - for battery-powered device which cares power consumptions - while still needs some measurements occasionally. - If this property is present, the single-shot mode will be - used, instead of the default continuous one for monitoring. - - = The node contains optional child nodes for three channels = - = Each child node describes the information of input source = - - - #address-cells: Required only if a child node is present. Must be 1. - - #size-cells: Required only if a child node is present. Must be 0. - -2) child nodes - Required properties: - - reg: Must be 0, 1 or 2, corresponding to IN1, IN2 or IN3 port of INA3221 - - Optional properties: - - label: Name of the input source - - shunt-resistor-micro-ohms: Shunt resistor value in micro-Ohm - -Example: - -ina3221@40 { - compatible = "ti,ina3221"; - reg = <0x40>; - #address-cells = <1>; - #size-cells = <0>; - - input@0 { - reg = <0x0>; - status = "disabled"; - }; - input@1 { - reg = <0x1>; - shunt-resistor-micro-ohms = <5000>; - }; - input@2 { - reg = <0x2>; - label = "VDD_5V"; - shunt-resistor-micro-ohms = <5000>; - }; -}; diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina3221.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina3221.yaml new file mode 100644 index 000000000000..0fd8ae5f6a22 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/ti,ina3221.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/ti,ina3221.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments INA3221 Current and Voltage Monitor + +maintainers: + - Jean Delvare + - Guenter Roeck + +properties: + compatible: + const: ti,ina3221 + + reg: + maxItems: 1 + + ti,single-shot: + description: | + This chip has two power modes: single-shot (chip takes one measurement + and then shuts itself down) and continuous (chip takes continuous + measurements). The continuous mode is more reliable and suitable for + hardware monitor type device, but the single-shot mode is more power- + friendly and useful for battery-powered device which cares power + consumptions while still needs some measurements occasionally. + + If this property is present, the single-shot mode will be used, instead + of the default continuous one for monitoring. + $ref: /schemas/types.yaml#/definitions/flag + + "#address-cells": + description: Required only if a child node is present. + const: 1 + + "#size-cells": + description: Required only if a child node is present. + const: 0 + +patternProperties: + "^input@[0-2]$": + description: The node contains optional child nodes for three channels. + Each child node describes the information of input source. Input channels + default to enabled in the chip. Unless channels are explicitly disabled + in device-tree, input channels will be enabled. + type: object + additionalProperties: false + properties: + reg: + description: Must be 0, 1 and 2, corresponding to the IN1, IN2 or IN3 + ports of the INA3221, respectively. + enum: [ 0, 1, 2 ] + + label: + description: name of the input source + + shunt-resistor-micro-ohms: + description: shunt resistor value in micro-Ohm + + required: + - reg + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + power-sensor@40 { + compatible = "ti,ina3221"; + reg = <0x40>; + #address-cells = <1>; + #size-cells = <0>; + + input@0 { + reg = <0x0>; + /* + * Input channels are enabled by default in the device and so + * to disable, must be explicitly disabled in device-tree. + */ + status = "disabled"; + }; + + input@1 { + reg = <0x1>; + shunt-resistor-micro-ohms = <5000>; + }; + + input@2 { + reg = <0x2>; + label = "VDD_5V"; + shunt-resistor-micro-ohms = <5000>; + }; + }; + }; From 13ab5fdc2cc60b24016546a8f402acd239280b68 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 29 Sep 2023 11:36:48 +0100 Subject: [PATCH 385/396] dt-bindings: hwmon: ina3221: Add ti,summation-disable The INA3221 has a critical alert pin that can be controlled by the summation control function. This function adds the single shunt-voltage conversions for the desired channels in order to compare the combined sum to the programmed limit. The Shunt-Voltage Sum Limit register contains the programmed value that is compared to the value in the Shunt-Voltage Sum register in order to determine if the total summed limit is exceeded. If the shunt-voltage sum limit value is exceeded, the critical alert pin pulls low. For the summation limit to have a meaningful value, it is necessary to use the same shunt-resistor value on all included channels. Add a new vendor specific property, 'ti,summation-disable', to allow specific channels to be excluded from the summation control function if the shunt resistor is different to other channels or the channel should not be considered for triggering the critical alert pin. Note that the ina3221 has always supported summing the various input channels and summation is enabled by default if the shunt-resistor values are the same. This change simply provides a way to exclude inputs from the summation. If this property is not populated, then the functionality of the driver does not change. Signed-off-by: Jon Hunter Signed-off-by: Ninad Malwade Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230929103650.86074-3-jonathanh@nvidia.com Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/ti,ina3221.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina3221.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina3221.yaml index 0fd8ae5f6a22..5f10f1207d69 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,ina3221.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,ina3221.yaml @@ -58,6 +58,25 @@ patternProperties: shunt-resistor-micro-ohms: description: shunt resistor value in micro-Ohm + ti,summation-disable: + description: | + The INA3221 has a critical alert pin that can be controlled by the + summation control function. This function adds the single + shunt-voltage conversions for the desired channels in order to + compare the combined sum to the programmed limit. The Shunt-Voltage + Sum Limit register contains the programmed value that is compared + to the value in the Shunt-Voltage Sum register in order to + determine if the total summed limit is exceeded. If the + shunt-voltage sum limit value is exceeded, the critical alert pin + is asserted. + + For the summation limit to have a meaningful value, it is necessary + to use the same shunt-resistor value on all enabled channels. If + this is not the case or if a channel should not be used for + triggering the critical alert pin, then this property can be used + exclude specific channels from the summation control function. + type: boolean + required: - reg From 7b64906c98fe503338066b97d3ff2dad65debf2b Mon Sep 17 00:00:00 2001 From: Ninad Malwade Date: Fri, 29 Sep 2023 11:36:49 +0100 Subject: [PATCH 386/396] hwmon: (ina3221) Add support for channel summation disable The INA3221 allows the Critical alert pin to be controlled by the summation control function. This function adds the single shunt-voltage conversions for the desired channels in order to compare the combined sum to the programmed limit. The Shunt-Voltage Sum Limit register contains the programmed value that is compared to the value in the Shunt-Voltage Sum register in order to determine if the total summed limit is exceeded. If the shunt-voltage sum limit value is exceeded, the Critical alert pin pulls low. For the summation limit to have a meaningful value, we have to use the same shunt-resistor value on all included channels. Unless equal shunt-resistor values are used for each channel, the summation control function cannot be used and it is not enabled by the driver. To address this, add support to disable the summation of specific channels via device tree property "ti,summation-disable". The channel which has this property would be excluded from the calculation of summation control function. For example, summation control function calculates Shunt-Voltage Sum as: - input_shunt_voltage_summation = input_shunt_voltage_channel1 + input_shunt_voltage_channel2 + input_shunt_voltage_channel3 If we want the summation to only use channel1 and channel3, we can add 'ti,summation-disable' property in device tree node for channel2. Then the calculation will skip channel2. - input_shunt_voltage_summation = input_shunt_voltage_channel1 + input_shunt_voltage_channel3 Note that we only want the channel to be skipped for summation control function rather than completely disabled. Therefore, even if we add the property 'ti,summation-disable', the channel is still enabled and functional. Finally, create debugfs entries that display if summation is disabled for each of the channels. Signed-off-by: Rajkumar Kasirajan Signed-off-by: Ninad Malwade Co-developed-by: Jon Hunter Signed-off-by: Jon Hunter Link: https://lore.kernel.org/r/20230929103650.86074-4-jonathanh@nvidia.com Signed-off-by: Guenter Roeck --- drivers/hwmon/ina3221.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 5ab944056ec0..5ffdc94db436 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -6,6 +6,7 @@ * Andrew F. Davis */ +#include #include #include #include @@ -99,11 +100,13 @@ enum ina3221_channels { * @label: label of channel input source * @shunt_resistor: shunt resistor value of channel input source * @disconnected: connection status of channel input source + * @summation_disable: channel summation status of input source */ struct ina3221_input { const char *label; int shunt_resistor; bool disconnected; + bool summation_disable; }; /** @@ -113,8 +116,10 @@ struct ina3221_input { * @fields: Register fields of the device * @inputs: Array of channel input source specific structures * @lock: mutex lock to serialize sysfs attribute accesses + * @debugfs: Pointer to debugfs entry for device * @reg_config: Register value of INA3221_CONFIG * @summation_shunt_resistor: equivalent shunt resistor value for summation + * @summation_channel_control: Value written to SCC field in INA3221_MASK_ENABLE * @single_shot: running in single-shot operating mode */ struct ina3221_data { @@ -123,8 +128,10 @@ struct ina3221_data { struct regmap_field *fields[F_MAX_FIELDS]; struct ina3221_input inputs[INA3221_NUM_CHANNELS]; struct mutex lock; + struct dentry *debugfs; u32 reg_config; int summation_shunt_resistor; + u32 summation_channel_control; bool single_shot; }; @@ -154,7 +161,8 @@ static inline int ina3221_summation_shunt_resistor(struct ina3221_data *ina) int i, shunt_resistor = 0; for (i = 0; i < INA3221_NUM_CHANNELS; i++) { - if (input[i].disconnected || !input[i].shunt_resistor) + if (input[i].disconnected || !input[i].shunt_resistor || + input[i].summation_disable) continue; if (!shunt_resistor) { /* Found the reference shunt resistor value */ @@ -786,6 +794,9 @@ static int ina3221_probe_child_from_dt(struct device *dev, /* Save the connected input label if available */ of_property_read_string(child, "label", &input->label); + /* summation channel control */ + input->summation_disable = of_property_read_bool(child, "ti,summation-disable"); + /* Overwrite default shunt resistor value optionally */ if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) { if (val < 1 || val > INT_MAX) { @@ -827,6 +838,7 @@ static int ina3221_probe(struct i2c_client *client) struct device *dev = &client->dev; struct ina3221_data *ina; struct device *hwmon_dev; + char name[32]; int i, ret; ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); @@ -873,6 +885,10 @@ static int ina3221_probe(struct i2c_client *client) /* Initialize summation_shunt_resistor for summation channel control */ ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina); + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + if (!ina->inputs[i].summation_disable) + ina->summation_channel_control |= BIT(14 - i); + } ina->pm_dev = dev; mutex_init(&ina->lock); @@ -900,6 +916,15 @@ static int ina3221_probe(struct i2c_client *client) goto fail; } + scnprintf(name, sizeof(name), "%s-%s", INA3221_DRIVER_NAME, dev_name(dev)); + ina->debugfs = debugfs_create_dir(name, NULL); + + for (i = 0; i < INA3221_NUM_CHANNELS; i++) { + scnprintf(name, sizeof(name), "in%d_summation_disable", i); + debugfs_create_bool(name, 0400, ina->debugfs, + &ina->inputs[i].summation_disable); + } + return 0; fail: @@ -918,6 +943,8 @@ static void ina3221_remove(struct i2c_client *client) struct ina3221_data *ina = dev_get_drvdata(&client->dev); int i; + debugfs_remove_recursive(ina->debugfs); + pm_runtime_disable(ina->pm_dev); pm_runtime_set_suspended(ina->pm_dev); @@ -978,13 +1005,13 @@ static int ina3221_resume(struct device *dev) /* Initialize summation channel control */ if (ina->summation_shunt_resistor) { /* - * Take all three channels into summation by default + * Sum only channels that are not disabled for summation. * Shunt measurements of disconnected channels should * be 0, so it does not matter for summation. */ ret = regmap_update_bits(ina->regmap, INA3221_MASK_ENABLE, INA3221_MASK_ENABLE_SCC_MASK, - INA3221_MASK_ENABLE_SCC_MASK); + ina->summation_channel_control); if (ret) { dev_err(dev, "Unable to control summation channel\n"); return ret; From 6dbd3e041d4b19c9654a630ca8c2933a1f85a7e1 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Mon, 25 Sep 2023 15:29:28 +0300 Subject: [PATCH 387/396] hwmon: (max31827) handle vref regulator Add missing implementation for the max31827 supply regulator. This is a hardware required property that is not handled. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20230925122929.10610-1-antoniu.miclaus@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/max31827.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c index 614bbf5d25fa..fd1fed1a797c 100644 --- a/drivers/hwmon/max31827.c +++ b/drivers/hwmon/max31827.c @@ -412,6 +412,10 @@ static int max31827_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(st->regmap), "Failed to allocate regmap.\n"); + err = devm_regulator_get_enable(dev, "vref"); + if (err) + return dev_err_probe(dev, err, "failed to enable regulator\n"); + err = max31827_init_client(st); if (err) return err; From f7ac3020036b500cc474f9173481fdaed964b381 Mon Sep 17 00:00:00 2001 From: Ellie Hermaszewska Date: Thu, 26 Oct 2023 18:43:22 +0800 Subject: [PATCH 388/396] hwmon: (asus-ec-sensors) add ROG Crosshair X670E Gene. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the temp sensors that I can verify are present. T_Sensor is the temperature reading of a 10kΩ β=3435K NTC thermistor optionally connected to the T_SENSOR header. The other sensors are as found on the X670E Hero. Signed-off-by: Ellie Hermaszewska Link: https://lore.kernel.org/r/20231026104332.906357-1-kernel@monoid.al Signed-off-by: Guenter Roeck --- Documentation/hwmon/asus_ec_sensors.rst | 1 + drivers/hwmon/asus-ec-sensors.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst index 7e3cd5b6686f..0bf99ba406dd 100644 --- a/Documentation/hwmon/asus_ec_sensors.rst +++ b/Documentation/hwmon/asus_ec_sensors.rst @@ -15,6 +15,7 @@ Supported boards: * ROG CROSSHAIR VIII HERO * ROG CROSSHAIR VIII IMPACT * ROG CROSSHAIR X670E HERO + * ROG CROSSHAIR X670E GENE * ROG MAXIMUS XI HERO * ROG MAXIMUS XI HERO (WI-FI) * ROG STRIX B550-E GAMING diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index 51f9c2db403e..36f9e38000d5 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -244,6 +244,8 @@ static const struct ec_sensor_info sensors_family_amd_600[] = { EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x32), [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33), + [ec_sensor_temp_t_sensor] = + EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x36), [ec_sensor_temp_water_in] = EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00), [ec_sensor_temp_water_out] = @@ -344,6 +346,14 @@ static const struct ec_board_info board_info_crosshair_x670e_hero = { .family = family_amd_600_series, }; +static const struct ec_board_info board_info_crosshair_x670e_gene = { + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | + SENSOR_TEMP_T_SENSOR | + SENSOR_TEMP_MB | SENSOR_TEMP_VRM, + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, + .family = family_amd_600_series, +}; + static const struct ec_board_info board_info_crosshair_viii_dark_hero = { .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR | @@ -490,6 +500,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_crosshair_viii_hero), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO", &board_info_crosshair_x670e_hero), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E GENE", + &board_info_crosshair_x670e_gene), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO", &board_info_maximus_xi_hero), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)", From b1f05cb4b310a8b8a48a1fac50fd76aeed30aa54 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Thu, 26 Oct 2023 09:08:50 +0200 Subject: [PATCH 389/396] dt-bindings: hwmon: ti,ina2xx: add ti,ina237 Add ti,ina237 binding to ti,ina2xx as they are very similar and may share the same properties. Signed-off-by: Richard Leitner Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231026-ina237-v2-2-dec44811a3c9@linux.dev Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml index 8648877d2d01..378d1f6aeeb3 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml @@ -26,6 +26,7 @@ properties: - ti,ina226 - ti,ina230 - ti,ina231 + - ti,ina237 - ti,ina238 reg: From 2358151bfb304aedda44348384557c161151bf57 Mon Sep 17 00:00:00 2001 From: Richard Leitner Date: Thu, 26 Oct 2023 09:08:49 +0200 Subject: [PATCH 390/396] hwmon: (ina238) add ina237 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The INA237 "85-V, 16-Bit, Precision Power Monitor With I2C Interface" is basically the same as INA328. Therefore add a corresponding compatible to the driver. According to the datasheet the main difference is the current and power monitoring accuracy: +------------------------+---------------+---------------+ | | INA238 | INA237 | +------------------------+---------------+---------------+ | Offset voltage | +/- 5µV | +/- 50µV | | Offset drift | +/- 0.02µV/°C | +/- 0.02µV/°C | | Gain error | +/- 0.1% | +/- 0.3% | | Gain error drift | +/- 25ppm/°C | +/- 50ppm/°C | | Common mode rejection | 140dB | 120dB | | Power accuracy | 0.7% | 1.6% | +------------------------+---------------+---------------+ As well as the missing DEVICE_ID register at 0x3F, which is currently not in use by the driver. Signed-off-by: Richard Leitner Link: https://lore.kernel.org/r/20231026-ina237-v2-1-dec44811a3c9@linux.dev Signed-off-by: Guenter Roeck --- drivers/hwmon/ina238.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index f519c22d3907..ca9f5d2c811b 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -33,7 +33,7 @@ #define INA238_BUS_UNDER_VOLTAGE 0xf #define INA238_TEMP_LIMIT 0x10 #define INA238_POWER_LIMIT 0x11 -#define INA238_DEVICE_ID 0x3f +#define INA238_DEVICE_ID 0x3f /* not available on INA237 */ #define INA238_CONFIG_ADCRANGE BIT(4) @@ -622,6 +622,7 @@ static const struct i2c_device_id ina238_id[] = { MODULE_DEVICE_TABLE(i2c, ina238_id); static const struct of_device_id __maybe_unused ina238_of_match[] = { + { .compatible = "ti,ina237" }, { .compatible = "ti,ina238" }, { }, }; From 205e0c0577faec05f5a9b92349cfd3454f2b00ec Mon Sep 17 00:00:00 2001 From: Lakshmi Yadlapati Date: Thu, 26 Oct 2023 23:43:46 -0500 Subject: [PATCH 391/396] hwmon: (pmbus/max31785) Add delay between bus accesses The MAX31785 has shown erratic behaviour across multiple system designs, unexpectedly clock stretching and NAKing transactions. Experimentation shows that this seems to be triggered by a register access directly back to back with a previous register write. Experimentation also shows that inserting a small delay after register writes makes the issue go away. Use a similar solution to what the max15301 driver does to solve the same problem. Create a custom set of bus read and write functions that make sure that the delay is added. Signed-off-by: Lakshmi Yadlapati Link: https://lore.kernel.org/r/20231027044346.2167548-1-lakshmiy@us.ibm.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/max31785.c | 188 +++++++++++++++++++++++++++++---- 1 file changed, 167 insertions(+), 21 deletions(-) diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index f9aa576495a5..5d13bbfc8f47 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -3,6 +3,7 @@ * Copyright (C) 2017 IBM Corp. */ +#include #include #include #include @@ -23,19 +24,119 @@ enum max31785_regs { #define MAX31785_NR_PAGES 23 #define MAX31785_NR_FAN_PAGES 6 +#define MAX31785_WAIT_DELAY_US 250 -static int max31785_read_byte_data(struct i2c_client *client, int page, - int reg) +struct max31785_data { + ktime_t access; /* Chip access time */ + struct pmbus_driver_info info; +}; + +#define to_max31785_data(x) container_of(x, struct max31785_data, info) + +/* + * MAX31785 Driver Workaround + * + * The MAX31785 fan controller occasionally exhibits communication issues. + * These issues are not indicated by the device itself, except for occasional + * NACK responses during master transactions. No error bits are set in STATUS_BYTE. + * + * To address this, we introduce a delay of 250us between consecutive accesses + * to the fan controller. This delay helps mitigate communication problems by + * allowing sufficient time between accesses. + */ +static inline void max31785_wait(const struct max31785_data *data) { - if (page < MAX31785_NR_PAGES) - return -ENODATA; + s64 delta = ktime_us_delta(ktime_get(), data->access); + + if (delta < MAX31785_WAIT_DELAY_US) + usleep_range(MAX31785_WAIT_DELAY_US - delta, + MAX31785_WAIT_DELAY_US); +} + +static int max31785_i2c_write_byte_data(struct i2c_client *client, + struct max31785_data *driver_data, + int command, u16 data) +{ + int rc; + + max31785_wait(driver_data); + rc = i2c_smbus_write_byte_data(client, command, data); + driver_data->access = ktime_get(); + return rc; +} + +static int max31785_i2c_read_word_data(struct i2c_client *client, + struct max31785_data *driver_data, + int command) +{ + int rc; + + max31785_wait(driver_data); + rc = i2c_smbus_read_word_data(client, command); + driver_data->access = ktime_get(); + return rc; +} + +static int _max31785_read_byte_data(struct i2c_client *client, + struct max31785_data *driver_data, + int page, int command) +{ + int rc; + + max31785_wait(driver_data); + rc = pmbus_read_byte_data(client, page, command); + driver_data->access = ktime_get(); + return rc; +} + +static int _max31785_write_byte_data(struct i2c_client *client, + struct max31785_data *driver_data, + int page, int command, u16 data) +{ + int rc; + + max31785_wait(driver_data); + rc = pmbus_write_byte_data(client, page, command, data); + driver_data->access = ktime_get(); + return rc; +} + +static int _max31785_read_word_data(struct i2c_client *client, + struct max31785_data *driver_data, + int page, int phase, int command) +{ + int rc; + + max31785_wait(driver_data); + rc = pmbus_read_word_data(client, page, phase, command); + driver_data->access = ktime_get(); + return rc; +} + +static int _max31785_write_word_data(struct i2c_client *client, + struct max31785_data *driver_data, + int page, int command, u16 data) +{ + int rc; + + max31785_wait(driver_data); + rc = pmbus_write_word_data(client, page, command, data); + driver_data->access = ktime_get(); + return rc; +} + +static int max31785_read_byte_data(struct i2c_client *client, int page, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct max31785_data *driver_data = to_max31785_data(info); switch (reg) { case PMBUS_VOUT_MODE: return -ENOTSUPP; case PMBUS_FAN_CONFIG_12: - return pmbus_read_byte_data(client, page - MAX31785_NR_PAGES, - reg); + return _max31785_read_byte_data(client, driver_data, + page - MAX31785_NR_PAGES, + reg); } return -ENODATA; @@ -102,16 +203,19 @@ static int max31785_get_pwm(struct i2c_client *client, int page) return rv; } -static int max31785_get_pwm_mode(struct i2c_client *client, int page) +static int max31785_get_pwm_mode(struct i2c_client *client, + struct max31785_data *driver_data, int page) { int config; int command; - config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12); + config = _max31785_read_byte_data(client, driver_data, page, + PMBUS_FAN_CONFIG_12); if (config < 0) return config; - command = pmbus_read_word_data(client, page, 0xff, PMBUS_FAN_COMMAND_1); + command = _max31785_read_word_data(client, driver_data, page, 0xff, + PMBUS_FAN_COMMAND_1); if (command < 0) return command; @@ -129,6 +233,8 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page) static int max31785_read_word_data(struct i2c_client *client, int page, int phase, int reg) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct max31785_data *driver_data = to_max31785_data(info); u32 val; int rv; @@ -157,7 +263,7 @@ static int max31785_read_word_data(struct i2c_client *client, int page, rv = max31785_get_pwm(client, page); break; case PMBUS_VIRT_PWM_ENABLE_1: - rv = max31785_get_pwm_mode(client, page); + rv = max31785_get_pwm_mode(client, driver_data, page); break; default: rv = -ENODATA; @@ -188,8 +294,36 @@ static inline u32 max31785_scale_pwm(u32 sensor_val) return (sensor_val * 100) / 255; } -static int max31785_pwm_enable(struct i2c_client *client, int page, - u16 word) +static int max31785_update_fan(struct i2c_client *client, + struct max31785_data *driver_data, int page, + u8 config, u8 mask, u16 command) +{ + int from, rv; + u8 to; + + from = _max31785_read_byte_data(client, driver_data, page, + PMBUS_FAN_CONFIG_12); + if (from < 0) + return from; + + to = (from & ~mask) | (config & mask); + + if (to != from) { + rv = _max31785_write_byte_data(client, driver_data, page, + PMBUS_FAN_CONFIG_12, to); + if (rv < 0) + return rv; + } + + rv = _max31785_write_word_data(client, driver_data, page, + PMBUS_FAN_COMMAND_1, command); + + return rv; +} + +static int max31785_pwm_enable(struct i2c_client *client, + struct max31785_data *driver_data, int page, + u16 word) { int config = 0; int rate; @@ -217,18 +351,23 @@ static int max31785_pwm_enable(struct i2c_client *client, int page, return -EINVAL; } - return pmbus_update_fan(client, page, 0, config, PB_FAN_1_RPM, rate); + return max31785_update_fan(client, driver_data, page, config, + PB_FAN_1_RPM, rate); } static int max31785_write_word_data(struct i2c_client *client, int page, int reg, u16 word) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct max31785_data *driver_data = to_max31785_data(info); + switch (reg) { case PMBUS_VIRT_PWM_1: - return pmbus_update_fan(client, page, 0, 0, PB_FAN_1_RPM, - max31785_scale_pwm(word)); + return max31785_update_fan(client, driver_data, page, 0, + PB_FAN_1_RPM, + max31785_scale_pwm(word)); case PMBUS_VIRT_PWM_ENABLE_1: - return max31785_pwm_enable(client, page, word); + return max31785_pwm_enable(client, driver_data, page, word); default: break; } @@ -303,13 +442,16 @@ static int max31785_configure_dual_tach(struct i2c_client *client, { int ret; int i; + struct max31785_data *driver_data = to_max31785_data(info); for (i = 0; i < MAX31785_NR_FAN_PAGES; i++) { - ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); + ret = max31785_i2c_write_byte_data(client, driver_data, + PMBUS_PAGE, i); if (ret < 0) return ret; - ret = i2c_smbus_read_word_data(client, MFR_FAN_CONFIG); + ret = max31785_i2c_read_word_data(client, driver_data, + MFR_FAN_CONFIG); if (ret < 0) return ret; @@ -329,6 +471,7 @@ static int max31785_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct pmbus_driver_info *info; + struct max31785_data *driver_data; bool dual_tach = false; int ret; @@ -337,13 +480,16 @@ static int max31785_probe(struct i2c_client *client) I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; - info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL); - if (!info) + driver_data = devm_kzalloc(dev, sizeof(struct max31785_data), GFP_KERNEL); + if (!driver_data) return -ENOMEM; + info = &driver_data->info; + driver_data->access = ktime_get(); *info = max31785_info; - ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255); + ret = max31785_i2c_write_byte_data(client, driver_data, + PMBUS_PAGE, 255); if (ret < 0) return ret; From 4bac088e2b12d40c49ad96c77be470eb2be7bae0 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 26 Oct 2023 13:33:12 +0300 Subject: [PATCH 392/396] dt-bindings: hwmon: ltc2991: add bindings Add dt-bindings for ltc2991 octal i2c voltage, current and temperature monitor. Signed-off-by: Antoniu Miclaus Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20231026103413.27800-1-antoniu.miclaus@analog.com Signed-off-by: Guenter Roeck --- .../bindings/hwmon/adi,ltc2991.yaml | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/adi,ltc2991.yaml diff --git a/Documentation/devicetree/bindings/hwmon/adi,ltc2991.yaml b/Documentation/devicetree/bindings/hwmon/adi,ltc2991.yaml new file mode 100644 index 000000000000..011e5b65c79c --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/adi,ltc2991.yaml @@ -0,0 +1,128 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/adi,ltc2991.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices LTC2991 Octal I2C Voltage, Current and Temperature Monitor + +maintainers: + - Antoniu Miclaus + +description: | + The LTC2991 is used to monitor system temperatures, voltages and currents. + Through the I2C serial interface, the eight monitors can individually measure + supply voltages and can be paired for differential measurements of current + sense resistors or temperature sensing transistors. + + Datasheet: + https://www.analog.com/en/products/ltc2991.html + +properties: + compatible: + const: adi,ltc2991 + + reg: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + vcc-supply: true + +patternProperties: + "^channel@[0-3]$": + type: object + description: + Represents the differential/temperature channels. + + properties: + reg: + description: + The channel number. LTC2991 can monitor 4 currents/temperatures. + items: + minimum: 0 + maximum: 3 + + shunt-resistor-micro-ohms: + description: + The value of curent sense resistor in micro ohms. Pin configuration is + set for differential input pair. + + adi,temperature-enable: + description: + Enables temperature readings. Pin configuration is set for remote + diode temperature measurement. + type: boolean + + required: + - reg + + allOf: + - if: + required: + - shunt-resistor-micro-ohms + then: + properties: + adi,temperature-enable: false + + additionalProperties: false + +required: + - compatible + - reg + - vcc-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hwmon@48 { + compatible = "adi,ltc2991"; + reg = <0x48>; + vcc-supply = <&vcc>; + }; + }; + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hwmon@48 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "adi,ltc2991"; + reg = <0x48>; + vcc-supply = <&vcc>; + + channel@0 { + reg = <0x0>; + shunt-resistor-micro-ohms = <100000>; + }; + + channel@1 { + reg = <0x1>; + shunt-resistor-micro-ohms = <100000>; + }; + + channel@2 { + reg = <0x2>; + adi,temperature-enable; + }; + + channel@3 { + reg = <0x3>; + adi,temperature-enable; + }; + }; + }; +... From 2b9ea4262ae9114b0b86ac893b4d6175d8520001 Mon Sep 17 00:00:00 2001 From: Antoniu Miclaus Date: Thu, 26 Oct 2023 13:33:13 +0300 Subject: [PATCH 393/396] hwmon: Add driver for ltc2991 Add support for LTC2991 Octal I2C Voltage, Current, and Temperature Monitor. The LTC2991 is used to monitor system temperatures, voltages and currents. Through the I2C serial interface, the eight monitors can individually measure supply voltages and can be paired for differential measurements of current sense resistors or temperature sensing transistors. Additional measurements include internal temperature and internal VCC. Signed-off-by: Antoniu Miclaus Link: https://lore.kernel.org/r/20231026103413.27800-2-antoniu.miclaus@analog.com [groeck: Fixed up documentation warning] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/ltc2991.rst | 43 ++++ MAINTAINERS | 8 + drivers/hwmon/Kconfig | 11 + drivers/hwmon/Makefile | 1 + drivers/hwmon/ltc2991.c | 437 ++++++++++++++++++++++++++++++++ 6 files changed, 501 insertions(+) create mode 100644 Documentation/hwmon/ltc2991.rst create mode 100644 drivers/hwmon/ltc2991.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 10a54644557d..72f4e6065bae 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -121,6 +121,7 @@ Hardware Monitoring Kernel Drivers ltc2947 ltc2978 ltc2990 + ltc2991 ltc3815 ltc4151 ltc4215 diff --git a/Documentation/hwmon/ltc2991.rst b/Documentation/hwmon/ltc2991.rst new file mode 100644 index 000000000000..15d8b4d7e471 --- /dev/null +++ b/Documentation/hwmon/ltc2991.rst @@ -0,0 +1,43 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver ltc2991 +===================== + +Supported chips: + + * Analog Devices LTC2991 + + Prefix: 'ltc2991' + + Addresses scanned: I2C 0x48 - 0x4f + + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2991ff.pdf + +Authors: + + - Antoniu Miclaus + + +Description +----------- + +This driver supports hardware monitoring for Analog Devices LTC2991 Octal I2C +Voltage, Current and Temperature Monitor. + +The LTC2991 is used to monitor system temperatures, voltages and currents. +Through the I2C serial interface, the eight monitors can individually measure +supply voltages and can be paired for differential measurements of current sense +resistors or temperature sensing transistors. Additional measurements include +internal temperatureand internal VCC. + + +sysfs-Interface +--------------- + +The following attributes are supported. Limits are read-only. + +=============== ================= +inX_input: voltage input +currX_input: current input +tempX_input: temperature input +=============== ================= diff --git a/MAINTAINERS b/MAINTAINERS index d0ce1a122ddf..43121073390c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12458,6 +12458,14 @@ F: drivers/hwmon/ltc2947-i2c.c F: drivers/hwmon/ltc2947-spi.c F: drivers/hwmon/ltc2947.h +LTC2991 HARDWARE MONITOR DRIVER +M: Antoniu Miclaus +L: linux-hwmon@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/hwmon/adi,ltc2991.yaml +F: drivers/hwmon/ltc2991.c + LTC2983 IIO TEMPERATURE DRIVER M: Nuno Sá L: linux-iio@vger.kernel.org diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e36f58b01f2d..cf27523eed5a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -942,6 +942,17 @@ config SENSORS_LTC2990 This driver can also be built as a module. If so, the module will be called ltc2990. +config SENSORS_LTC2991 + tristate "Analog Devices LTC2991" + depends on I2C + help + If you say yes here you get support for Analog Devices LTC2991 + Octal I2C Voltage, Current, and Temperature Monitor. The LTC2991 + supports a combination of voltage, current and temperature monitoring. + + This driver can also be built as a module. If so, the module will + be called ltc2991. + config SENSORS_LTC2992 tristate "Linear Technology LTC2992" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 019189500e5d..e84bd9685b5c 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -127,6 +127,7 @@ obj-$(CONFIG_SENSORS_LTC2947) += ltc2947-core.o obj-$(CONFIG_SENSORS_LTC2947_I2C) += ltc2947-i2c.o obj-$(CONFIG_SENSORS_LTC2947_SPI) += ltc2947-spi.o obj-$(CONFIG_SENSORS_LTC2990) += ltc2990.o +obj-$(CONFIG_SENSORS_LTC2991) += ltc2991.o obj-$(CONFIG_SENSORS_LTC2992) += ltc2992.o obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o diff --git a/drivers/hwmon/ltc2991.c b/drivers/hwmon/ltc2991.c new file mode 100644 index 000000000000..bd63c61129a9 --- /dev/null +++ b/drivers/hwmon/ltc2991.c @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Analog Devices, Inc. + * Author: Antoniu Miclaus + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LTC2991_STATUS_LOW 0x00 +#define LTC2991_CH_EN_TRIGGER 0x01 +#define LTC2991_V1_V4_CTRL 0x06 +#define LTC2991_V5_V8_CTRL 0x07 +#define LTC2991_PWM_TH_LSB_T_INT 0x08 +#define LTC2991_PWM_TH_MSB 0x09 +#define LTC2991_CHANNEL_V_MSB(x) (0x0A + ((x) * 2)) +#define LTC2991_CHANNEL_T_MSB(x) (0x0A + ((x) * 4)) +#define LTC2991_CHANNEL_C_MSB(x) (0x0C + ((x) * 4)) +#define LTC2991_T_INT_MSB 0x1A +#define LTC2991_VCC_MSB 0x1C + +#define LTC2991_V7_V8_EN BIT(7) +#define LTC2991_V5_V6_EN BIT(6) +#define LTC2991_V3_V4_EN BIT(5) +#define LTC2991_V1_V2_EN BIT(4) +#define LTC2991_T_INT_VCC_EN BIT(3) + +#define LTC2991_V3_V4_FILT_EN BIT(7) +#define LTC2991_V3_V4_TEMP_EN BIT(5) +#define LTC2991_V3_V4_DIFF_EN BIT(4) +#define LTC2991_V1_V2_FILT_EN BIT(3) +#define LTC2991_V1_V2_TEMP_EN BIT(1) +#define LTC2991_V1_V2_DIFF_EN BIT(0) + +#define LTC2991_V7_V8_FILT_EN BIT(7) +#define LTC2991_V7_V8_TEMP_EN BIT(5) +#define LTC2991_V7_V8_DIFF_EN BIT(4) +#define LTC2991_V5_V6_FILT_EN BIT(7) +#define LTC2991_V5_V6_TEMP_EN BIT(5) +#define LTC2991_V5_V6_DIFF_EN BIT(4) + +#define LTC2991_REPEAT_ACQ_EN BIT(4) +#define LTC2991_T_INT_FILT_EN BIT(3) + +#define LTC2991_MAX_CHANNEL 4 +#define LTC2991_T_INT_CH_NR 4 +#define LTC2991_VCC_CH_NR 0 + +struct ltc2991_state { + struct device *dev; + struct regmap *regmap; + u32 r_sense_uohm[LTC2991_MAX_CHANNEL]; + bool temp_en[LTC2991_MAX_CHANNEL]; +}; + +static int ltc2991_read_reg(struct ltc2991_state *st, u8 addr, u8 reg_len, + int *val) +{ + __be16 regvals; + int ret; + + if (reg_len < 2) + return regmap_read(st->regmap, addr, val); + + ret = regmap_bulk_read(st->regmap, addr, ®vals, reg_len); + if (ret) + return ret; + + *val = be16_to_cpu(regvals); + + return 0; +} + +static int ltc2991_get_voltage(struct ltc2991_state *st, u32 reg, long *val) +{ + int reg_val, ret, offset = 0; + + ret = ltc2991_read_reg(st, reg, 2, ®_val); + if (ret) + return ret; + + if (reg == LTC2991_VCC_MSB) + /* Vcc 2.5V offset */ + offset = 2500; + + /* Vx, 305.18uV/LSB */ + *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 14) * 30518, + 1000 * 100) + offset; + + return 0; +} + +static int ltc2991_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + struct ltc2991_state *st = dev_get_drvdata(dev); + u32 reg; + + switch (attr) { + case hwmon_in_input: + if (channel == LTC2991_VCC_CH_NR) + reg = LTC2991_VCC_MSB; + else + reg = LTC2991_CHANNEL_V_MSB(channel - 1); + + return ltc2991_get_voltage(st, reg, val); + default: + return -EOPNOTSUPP; + } +} + +static int ltc2991_get_curr(struct ltc2991_state *st, u32 reg, int channel, + long *val) +{ + int reg_val, ret; + + ret = ltc2991_read_reg(st, reg, 2, ®_val); + if (ret) + return ret; + + /* Vx-Vy, 19.075uV/LSB */ + *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 14) * 19075, + st->r_sense_uohm[channel]); + + return 0; +} + +static int ltc2991_read_curr(struct device *dev, u32 attr, int channel, + long *val) +{ + struct ltc2991_state *st = dev_get_drvdata(dev); + u32 reg; + + switch (attr) { + case hwmon_curr_input: + reg = LTC2991_CHANNEL_C_MSB(channel); + return ltc2991_get_curr(st, reg, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int ltc2991_get_temp(struct ltc2991_state *st, u32 reg, int channel, + long *val) +{ + int reg_val, ret; + + ret = ltc2991_read_reg(st, reg, 2, ®_val); + if (ret) + return ret; + + /* Temp LSB = 0.0625 Degrees */ + *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 12) * 1000, 16); + + return 0; +} + +static int ltc2991_read_temp(struct device *dev, u32 attr, int channel, + long *val) +{ + struct ltc2991_state *st = dev_get_drvdata(dev); + u32 reg; + + switch (attr) { + case hwmon_temp_input: + if (channel == LTC2991_T_INT_CH_NR) + reg = LTC2991_T_INT_MSB; + else + reg = LTC2991_CHANNEL_T_MSB(channel); + + return ltc2991_get_temp(st, reg, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int ltc2991_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_in: + return ltc2991_read_in(dev, attr, channel, val); + case hwmon_curr: + return ltc2991_read_curr(dev, attr, channel, val); + case hwmon_temp: + return ltc2991_read_temp(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static umode_t ltc2991_is_visible(const void *data, + enum hwmon_sensor_types type, u32 attr, + int channel) +{ + const struct ltc2991_state *st = data; + + switch (type) { + case hwmon_in: + switch (attr) { + case hwmon_in_input: + if (channel == LTC2991_VCC_CH_NR) + return 0444; + if (st->temp_en[(channel - 1) / 2]) + break; + if (channel % 2) + return 0444; + if (!st->r_sense_uohm[(channel - 1) / 2]) + return 0444; + } + break; + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + if (st->r_sense_uohm[channel]) + return 0444; + break; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + if (st->temp_en[channel] || + channel == LTC2991_T_INT_CH_NR) + return 0444; + break; + } + break; + default: + break; + } + + return 0; +} + +static const struct hwmon_ops ltc2991_hwmon_ops = { + .is_visible = ltc2991_is_visible, + .read = ltc2991_read, +}; + +static const struct hwmon_channel_info *ltc2991_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT + ), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT, + HWMON_C_INPUT, + HWMON_C_INPUT, + HWMON_C_INPUT + ), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT + ), + NULL +}; + +static const struct hwmon_chip_info ltc2991_chip_info = { + .ops = <c2991_hwmon_ops, + .info = ltc2991_info, +}; + +static const struct regmap_config ltc2991_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x1D, +}; + +static int ltc2991_init(struct ltc2991_state *st) +{ + struct fwnode_handle *child; + int ret; + u32 val, addr; + u8 v5_v8_reg_data = 0, v1_v4_reg_data = 0; + + ret = devm_regulator_get_enable(st->dev, "vcc"); + if (ret) + return dev_err_probe(st->dev, ret, + "failed to enable regulator\n"); + + device_for_each_child_node(st->dev, child) { + ret = fwnode_property_read_u32(child, "reg", &addr); + if (ret < 0) { + fwnode_handle_put(child); + return ret; + } + + if (addr > 3) { + fwnode_handle_put(child); + return -EINVAL; + } + + ret = fwnode_property_read_u32(child, + "shunt-resistor-micro-ohms", + &val); + if (!ret) { + if (!val) + return dev_err_probe(st->dev, -EINVAL, + "shunt resistor value cannot be zero\n"); + + st->r_sense_uohm[addr] = val; + + switch (addr) { + case 0: + v1_v4_reg_data |= LTC2991_V1_V2_DIFF_EN; + break; + case 1: + v1_v4_reg_data |= LTC2991_V3_V4_DIFF_EN; + break; + case 2: + v5_v8_reg_data |= LTC2991_V5_V6_DIFF_EN; + break; + case 3: + v5_v8_reg_data |= LTC2991_V7_V8_DIFF_EN; + break; + default: + break; + } + } + + ret = fwnode_property_read_bool(child, + "adi,temperature-enable"); + if (ret) { + st->temp_en[addr] = ret; + + switch (addr) { + case 0: + v1_v4_reg_data |= LTC2991_V1_V2_TEMP_EN; + break; + case 1: + v1_v4_reg_data |= LTC2991_V3_V4_TEMP_EN; + break; + case 2: + v5_v8_reg_data |= LTC2991_V5_V6_TEMP_EN; + break; + case 3: + v5_v8_reg_data |= LTC2991_V7_V8_TEMP_EN; + break; + default: + break; + } + } + } + + ret = regmap_write(st->regmap, LTC2991_V5_V8_CTRL, v5_v8_reg_data); + if (ret) + return dev_err_probe(st->dev, ret, + "Error: Failed to set V5-V8 CTRL reg.\n"); + + ret = regmap_write(st->regmap, LTC2991_V1_V4_CTRL, v1_v4_reg_data); + if (ret) + return dev_err_probe(st->dev, ret, + "Error: Failed to set V1-V4 CTRL reg.\n"); + + ret = regmap_write(st->regmap, LTC2991_PWM_TH_LSB_T_INT, + LTC2991_REPEAT_ACQ_EN); + if (ret) + return dev_err_probe(st->dev, ret, + "Error: Failed to set contiuous mode.\n"); + + /* Enable all channels and trigger conversions */ + return regmap_write(st->regmap, LTC2991_CH_EN_TRIGGER, + LTC2991_V7_V8_EN | LTC2991_V5_V6_EN | + LTC2991_V3_V4_EN | LTC2991_V1_V2_EN | + LTC2991_T_INT_VCC_EN); +} + +static int ltc2991_i2c_probe(struct i2c_client *client) +{ + int ret; + struct device *hwmon_dev; + struct ltc2991_state *st; + + st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + st->dev = &client->dev; + st->regmap = devm_regmap_init_i2c(client, <c2991_regmap_config); + if (IS_ERR(st->regmap)) + return PTR_ERR(st->regmap); + + ret = ltc2991_init(st); + if (ret) + return ret; + + hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, + client->name, st, + <c2991_chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id ltc2991_of_match[] = { + { .compatible = "adi,ltc2991" }, + { } +}; +MODULE_DEVICE_TABLE(of, ltc2991_of_match); + +static const struct i2c_device_id ltc2991_i2c_id[] = { + { "ltc2991", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ltc2991_i2c_id); + +static struct i2c_driver ltc2991_i2c_driver = { + .driver = { + .name = "ltc2991", + .of_match_table = ltc2991_of_match, + }, + .probe = ltc2991_i2c_probe, + .id_table = ltc2991_i2c_id, +}; + +module_i2c_driver(ltc2991_i2c_driver); + +MODULE_AUTHOR("Antoniu Miclaus "); +MODULE_DESCRIPTION("Analog Devices LTC2991 HWMON Driver"); +MODULE_LICENSE("GPL"); From e56a5e3dfd149573e6134b7eb373d56bc81bd0de Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Wed, 18 Oct 2023 21:19:24 +0300 Subject: [PATCH 394/396] dt-bindings: hwmon: npcm: Add npcm845 compatible string Add a compatible string for Nuvoton BMC NPCM845 Pulse Width Modulation (PWM) and Fan tach controller. Signed-off-by: Tomer Maimon Acked-by: Rob Herring Link: https://lore.kernel.org/r/20231018181925.1826042-2-tmaimon77@gmail.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/npcm750-pwm-fan.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/hwmon/npcm750-pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/npcm750-pwm-fan.txt index 8523777f560c..18095ba87a5a 100644 --- a/Documentation/devicetree/bindings/hwmon/npcm750-pwm-fan.txt +++ b/Documentation/devicetree/bindings/hwmon/npcm750-pwm-fan.txt @@ -1,12 +1,16 @@ -Nuvoton NPCM7xx PWM and Fan Tacho controller device +Nuvoton NPCM PWM and Fan Tacho controller device The Nuvoton BMC NPCM7XX supports 8 Pulse-width modulation (PWM) controller outputs and 16 Fan tachometer controller inputs. +The Nuvoton BMC NPCM8XX supports 12 Pulse-width modulation (PWM) +controller outputs and 16 Fan tachometer controller inputs. + Required properties for pwm-fan node - #address-cells : should be 1. - #size-cells : should be 0. - compatible : "nuvoton,npcm750-pwm-fan" for Poleg NPCM7XX. + : "nuvoton,npcm845-pwm-fan" for Arbel NPCM8XX. - reg : specifies physical base address and size of the registers. - reg-names : must contain: * "pwm" for the PWM registers. From ceaa22402e44e09ab34840a3a83888f93785c772 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Mon, 16 Oct 2023 10:35:58 +0200 Subject: [PATCH 395/396] hwmon: (aquacomputer_d5next) Add support for Aquacomputer High Flow USB and MPS Flow Extend aquacomputer_d5next driver to expose various hardware sensors of the Aquacomputer High Flow USB flow sensor, which communicates through a proprietary USB HID protocol. This commit also adds support for the sensors of the MPS Flow devices, as they have the same USB product ID and sensor layouts. Implemented by Leonard Anderweit [1]. Internal and external temp sensor readings are available, along with the flow sensor. Additionally, serial number and firmware version are exposed through debugfs. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/90 Originally-from: Leonard Anderweit Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20231016083559.139341-3-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aquacomputer_d5next.rst | 7 +++ drivers/hwmon/aquacomputer_d5next.c | 67 +++++++++++++++++++-- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 94dc2d93d180..cb073c79479c 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -16,6 +16,8 @@ Supported devices: * Aquacomputer Aquastream XT watercooling pump * Aquacomputer Aquastream Ultimate watercooling pump * Aquacomputer Poweradjust 3 fan controller +* Aquacomputer High Flow USB flow meter +* Aquacomputer MPS Flow devices Author: Aleksa Savic @@ -73,6 +75,11 @@ It also exposes pressure and flow speed readings. The Poweradjust 3 controller exposes a single external temperature sensor. +The High Flow USB exposes an internal and external temperature sensor, and a flow meter. + +The MPS Flow devices expose the same entries as the High Flow USB because they have +the same USB product ID and report sensors equivalently. + Depending on the device, not all sysfs and debugfs entries will be available. Writing to virtual temperature sensors is not currently supported. diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 023807859be7..0378edd52134 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0+ /* * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo, - * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield) + * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield, + * High Flow USB/MPS Flow family) * * Aquacomputer devices send HID reports (with ID 0x01) every second to report * sensor values, except for devices that communicate through the - * legacy way (currently, Poweradjust 3). + * legacy way (currently, Poweradjust 3 and High Flow USB/MPS Flow family). * * Copyright 2021 Aleksa Savic * Copyright 2022 Jack Doan @@ -35,11 +36,12 @@ #define USB_PRODUCT_ID_AQUASTREAMXT 0xf0b6 #define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b #define USB_PRODUCT_ID_POWERADJUST3 0xf0bd +#define USB_PRODUCT_ID_HIGHFLOW 0xf003 enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero, poweradjust3, aquastreamult, - aquastreamxt, leakshield + aquastreamxt, leakshield, highflow }; static const char *const aqc_device_names[] = { @@ -53,7 +55,8 @@ static const char *const aqc_device_names[] = { [aquastreamxt] = "aquastreamxt", [aquaero] = "aquaero", [aquastreamult] = "aquastreamultimate", - [poweradjust3] = "poweradjust3" + [poweradjust3] = "poweradjust3", + [highflow] = "highflow" /* Covers MPS Flow devices */ }; #define DRIVER_NAME "aquacomputer_d5next" @@ -90,6 +93,8 @@ static u8 aquaero_secondary_ctrl_report[] = { #define POWERADJUST3_STATUS_REPORT_ID 0x03 +#define HIGHFLOW_STATUS_REPORT_ID 0x02 + /* Data types for reading and writing control reports */ #define AQC_8 0 #define AQC_BE16 1 @@ -282,6 +287,17 @@ static u16 aquastreamxt_sensor_fan_offsets[] = { 0x13, 0x1b }; /* Sensor report offsets for the Poweradjust 3 */ #define POWERADJUST3_SENSOR_START 0x03 +/* Specs of the High Flow USB */ +#define HIGHFLOW_NUM_SENSORS 2 +#define HIGHFLOW_NUM_FLOW_SENSORS 1 +#define HIGHFLOW_SENSOR_REPORT_SIZE 0x76 + +/* Sensor report offsets for the High Flow USB */ +#define HIGHFLOW_FIRMWARE_VERSION 0x3 +#define HIGHFLOW_SERIAL_START 0x9 +#define HIGHFLOW_FLOW_SENSOR_OFFSET 0x23 +#define HIGHFLOW_SENSOR_START 0x2b + /* Labels for D5 Next */ static const char *const label_d5next_temp[] = { "Coolant temp" @@ -486,6 +502,16 @@ static const char *const label_poweradjust3_temp_sensors[] = { "External sensor" }; +/* Labels for Highflow */ +static const char *const label_highflow_temp[] = { + "External temp", + "Internal temp" +}; + +static const char *const label_highflow_speeds[] = { + "Flow speed [dL/h]" +}; + struct aqc_fan_structure_offsets { u8 voltage; u8 curr; @@ -819,6 +845,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 break; case aquaero: case quadro: + case highflow: /* Special case to support flow sensors */ if (channel < priv->num_fans + priv->num_flow_sensors) return 0444; @@ -962,6 +989,17 @@ static int aqc_legacy_read(struct aqc_data *priv) sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_VOLTAGE_OFFSET); priv->voltage_input[1] = DIV_ROUND_CLOSEST(sensor_value * 1000, 63); break; + case highflow: + /* Info provided with every report */ + priv->serial_number[0] = get_unaligned_le16(priv->buffer + + priv->serial_number_start_offset); + priv->firmware_version = + get_unaligned_le16(priv->buffer + priv->firmware_version_offset); + + /* Read flow speed */ + priv->speed_input[0] = get_unaligned_le16(priv->buffer + + priv->flow_sensors_start_offset); + break; default: break; } @@ -1747,6 +1785,20 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->temp_label = label_poweradjust3_temp_sensors; break; + case USB_PRODUCT_ID_HIGHFLOW: + priv->kind = highflow; + + priv->num_fans = 0; + + priv->num_temp_sensors = HIGHFLOW_NUM_SENSORS; + priv->temp_sensor_start_offset = HIGHFLOW_SENSOR_START; + priv->num_flow_sensors = HIGHFLOW_NUM_FLOW_SENSORS; + priv->flow_sensors_start_offset = HIGHFLOW_FLOW_SENSOR_OFFSET; + priv->buffer_size = HIGHFLOW_SENSOR_REPORT_SIZE; + + priv->temp_label = label_highflow_temp; + priv->speed_label = label_highflow_speeds; + break; default: break; } @@ -1772,6 +1824,12 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->status_report_id = AQUASTREAMXT_STATUS_REPORT_ID; break; + case highflow: + priv->serial_number_start_offset = HIGHFLOW_SERIAL_START; + priv->firmware_version_offset = HIGHFLOW_FIRMWARE_VERSION; + + priv->status_report_id = HIGHFLOW_STATUS_REPORT_ID; + break; default: priv->serial_number_start_offset = AQC_SERIAL_START; priv->firmware_version_offset = AQC_FIRMWARE_VERSION; @@ -1846,6 +1904,7 @@ static const struct hid_device_id aqc_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMXT) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOW) }, { } }; From 0f564130e5c76f1e5cf0008924f6a6cd138929d9 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Mon, 16 Oct 2023 10:35:57 +0200 Subject: [PATCH 396/396] hwmon: (aquacomputer_d5next) Check if temp sensors of legacy devices are connected Return -ENODATA if a temp sensor of a legacy device does not contain a reading. Originally-from: Leonard Anderweit Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20231016083559.139341-2-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aquacomputer_d5next.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 0378edd52134..4fdd2e12427b 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -953,7 +953,10 @@ static int aqc_legacy_read(struct aqc_data *priv) for (i = 0; i < priv->num_temp_sensors; i++) { sensor_value = get_unaligned_le16(priv->buffer + priv->temp_sensor_start_offset + i * AQC_SENSOR_SIZE); - priv->temp_input[i] = sensor_value * 10; + if (sensor_value == AQC_SENSOR_NA) + priv->temp_input[i] = -ENODATA; + else + priv->temp_input[i] = sensor_value * 10; } /* Special-case sensor readings */