From defdca82c107f46e980c84bffb1b2c1263522fa0 Mon Sep 17 00:00:00 2001 From: "Jason M. Bills" Date: Wed, 23 Jun 2021 16:18:49 -0700 Subject: Update to internal 0.57 Signed-off-by: Jason M. Bills --- .../files/0030-Add-Aspeed-PWM-uclass-driver.patch | 576 +++++++++++++++++++++ 1 file changed, 576 insertions(+) create mode 100644 meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch (limited to 'meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch') diff --git a/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch new file mode 100644 index 000000000..ac7262f2c --- /dev/null +++ b/meta-openbmc-mods/meta-ast2600/recipes-bsp/u-boot/files/0030-Add-Aspeed-PWM-uclass-driver.patch @@ -0,0 +1,576 @@ +From b68b7c30fa3331642e321d150017d431d8cf6f6d Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo +Date: Mon, 17 May 2021 13:11:24 -0700 +Subject: [PATCH] Add Aspeed PWM uclass driver + +This commit adds Aspeed PWM uclass driver to set default FAN speed +in u-boot. + +Signed-off-by: Jae Hyun Yoo +--- + arch/arm/dts/ast2600-intel.dts | 11 ++ + arch/arm/dts/ast2600.dtsi | 88 ++++++++++++ + board/aspeed/ast2600_intel/intel.c | 49 +++++++ + drivers/pinctrl/aspeed/pinctrl_ast2600.c | 130 ++++++++++++++++- + drivers/pwm/Kconfig | 8 ++ + drivers/pwm/Makefile | 1 + + drivers/pwm/aspeed_pwm.c | 175 +++++++++++++++++++++++ + 7 files changed, 461 insertions(+), 1 deletion(-) + create mode 100644 drivers/pwm/aspeed_pwm.c + +diff --git a/arch/arm/dts/ast2600-intel.dts b/arch/arm/dts/ast2600-intel.dts +index 5243d1a0afc3..79356d8b7a64 100644 +--- a/arch/arm/dts/ast2600-intel.dts ++++ b/arch/arm/dts/ast2600-intel.dts +@@ -53,6 +53,17 @@ + }; + }; + ++&pwm { ++ status = "okay"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default ++ &pinctrl_pwm2_default &pinctrl_pwm3_default ++ &pinctrl_pwm4_default &pinctrl_pwm5_default ++ &pinctrl_pwm12g1_default &pinctrl_pwm13g1_default ++ &pinctrl_pwm14g1_default &pinctrl_pwm15g1_default>; ++}; ++ + &gpio0 { + status = "okay"; + }; +diff --git a/arch/arm/dts/ast2600.dtsi b/arch/arm/dts/ast2600.dtsi +index e619f7118886..44ec6655fee7 100644 +--- a/arch/arm/dts/ast2600.dtsi ++++ b/arch/arm/dts/ast2600.dtsi +@@ -265,6 +265,14 @@ + #size-cells = <1>; + ranges; + ++ pwm: pwm-controller@1e610000 { ++ compatible = "aspeed,ast2600-pwm"; ++ reg = <0x1e610000 0x100>; ++ clocks = <&scu ASPEED_CLK_AHB>; ++ resets = <&rst ASPEED_RESET_PWM>; ++ status = "disabled"; ++ }; ++ + syscon: syscon@1e6e2000 { + compatible = "aspeed,g6-scu", "syscon", "simple-mfd"; + reg = <0x1e6e2000 0x1000>; +@@ -1589,6 +1597,86 @@ + groups = "PWM7"; + }; + ++ pinctrl_pwm8g1_default: pwm8g1_default { ++ function = "PWM8G1"; ++ groups = "PWM8G1"; ++ }; ++ ++ pinctrl_pwm9g1_default: pwm9g1_default { ++ function = "PWM9G1"; ++ groups = "PWM9G1"; ++ }; ++ ++ pinctrl_pwm10g1_default: pwm10g1_default { ++ function = "PWM10G1"; ++ groups = "PWM10G1"; ++ }; ++ ++ pinctrl_pwm11g1_default: pwm11g1_default { ++ function = "PWM11G1"; ++ groups = "PWM11G1"; ++ }; ++ ++ pinctrl_pwm12g1_default: pwm12g1_default { ++ function = "PWM12G1"; ++ groups = "PWM12G1"; ++ }; ++ ++ pinctrl_pwm13g1_default: pwm13g1_default { ++ function = "PWM13G1"; ++ groups = "PWM13G1"; ++ }; ++ ++ pinctrl_pwm14g1_default: pwm14g1_default { ++ function = "PWM14G1"; ++ groups = "PWM14G1"; ++ }; ++ ++ pinctrl_pwm15g1_default: pwm15g1_default { ++ function = "PWM15G1"; ++ groups = "PWM15G1"; ++ }; ++ ++ pinctrl_pwm8g0_default: pwm8g0_default { ++ function = "PWM8G0"; ++ groups = "PWM8G0"; ++ }; ++ ++ pinctrl_pwm9g0_default: pwm9g0_default { ++ function = "PWM9G0"; ++ groups = "PWM9G0"; ++ }; ++ ++ pinctrl_pwm10g0_default: pwm10g0_default { ++ function = "PWM10G0"; ++ groups = "PWM10G0"; ++ }; ++ ++ pinctrl_pwm11g0_default: pwm11g0_default { ++ function = "PWM11G0"; ++ groups = "PWM11G0"; ++ }; ++ ++ pinctrl_pwm12g0_default: pwm12g0_default { ++ function = "PWM12G0"; ++ groups = "PWM12G0"; ++ }; ++ ++ pinctrl_pwm13g0_default: pwm13g0_default { ++ function = "PWM13G0"; ++ groups = "PWM13G0"; ++ }; ++ ++ pinctrl_pwm14g0_default: pwm14g0_default { ++ function = "PWM14G0"; ++ groups = "PWM14G0"; ++ }; ++ ++ pinctrl_pwm15g0_default: pwm15g0_default { ++ function = "PWM15G0"; ++ groups = "PWM15G0"; ++ }; ++ + pinctrl_rgmii1_default: rgmii1_default { + function = "RGMII1"; + groups = "RGMII1"; +diff --git a/board/aspeed/ast2600_intel/intel.c b/board/aspeed/ast2600_intel/intel.c +index ec6b70ae6659..11b8d4dd8360 100644 +--- a/board/aspeed/ast2600_intel/intel.c ++++ b/board/aspeed/ast2600_intel/intel.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #define SYS_PWR_RESET_FLAG BIT(0) /* from scu_info.c */ + #define WATCHDOG_RESET_BIT BIT(20) +@@ -426,6 +427,53 @@ static void mailbox_init(void) + } + } + ++struct pwm_setting { ++ uint channel; ++ uint duty_pct; ++}; ++ ++static void pwm_init(void) ++{ ++#define NSEC_PER_SEC 1000000000L ++#define PWM_TARGET_FREQ 25000 ++#define PWM_TICK_NS (NSEC_PER_SEC / PWM_TARGET_FREQ) ++#define PWM_TICK_1PCT_NS (PWM_TICK_NS / 100) ++ const struct pwm_setting settings[] = { ++ {0, 65}, ++ {1, 65}, ++ {2, 65}, ++ {3, 65}, ++ {4, 65}, ++ {5, 65}, ++ {12, 65}, ++ {13, 65}, ++ {14, 65}, ++ {15, 65}, ++ }; ++ struct udevice *dev; ++ int ret, setting_size, i; ++ ++ ret = uclass_first_device(UCLASS_PWM, &dev); ++ if (ret) { ++ debug("Can't find PWM controller: %d\n", ret); ++ return; ++ } ++ ++ setting_size = sizeof(settings) / sizeof(settings[0]); ++ ++ for (i = 0; i < setting_size; i++) { ++ ret = pwm_set_config(dev, settings[i].channel, PWM_TICK_NS, ++ settings[i].duty_pct * PWM_TICK_1PCT_NS); ++ if (!ret) { ++ ret = pwm_set_enable(dev, settings[i].channel, true); ++ if (ret) ++ debug("PWM enabling failed: %d\n", ret); ++ } else { ++ debug("PWM configure failed: %d\n", ret); ++ } ++ } ++} ++ + int board_early_init_f(void) + { + /* This is called before relocation; beware! */ +@@ -613,6 +661,7 @@ int board_late_init(void) + timer_callback, (void *)1); + #endif + ++ pwm_init(); + espi_init(); + + /* Add reset reason to bootargs */ +diff --git a/drivers/pinctrl/aspeed/pinctrl_ast2600.c b/drivers/pinctrl/aspeed/pinctrl_ast2600.c +index 8a77a5d31556..980667f84e30 100644 +--- a/drivers/pinctrl/aspeed/pinctrl_ast2600.c ++++ b/drivers/pinctrl/aspeed/pinctrl_ast2600.c +@@ -326,6 +326,110 @@ static struct aspeed_sig_desc pcie1rc_link[] = { + { 0x500, BIT(24), 0 }, //dedicate rc reset + }; + ++static struct aspeed_sig_desc pwm0[] = { ++ { 0x41C, BIT(16), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm1[] = { ++ { 0x41C, BIT(17), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm2[] = { ++ { 0x41C, BIT(18), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm3[] = { ++ { 0x41C, BIT(19), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm4[] = { ++ { 0x41C, BIT(20), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm5[] = { ++ { 0x41C, BIT(21), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm6[] = { ++ { 0x41C, BIT(22), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm7[] = { ++ { 0x41C, BIT(23), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm8g1[] = { ++ { 0x41C, BIT(24), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm9g1[] = { ++ { 0x41C, BIT(25), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm10g1[] = { ++ { 0x41C, BIT(26), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm11g1[] = { ++ { 0x41C, BIT(27), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm12g1[] = { ++ { 0x41C, BIT(28), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm13g1[] = { ++ { 0x41C, BIT(29), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm14g1[] = { ++ { 0x41C, BIT(30), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm15g1[] = { ++ { 0x41C, BIT(31), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm8g0[] = { ++ { 0x414, BIT(8), 1 }, ++ { 0x4B4, BIT(8), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm9g0[] = { ++ { 0x414, BIT(9), 1 }, ++ { 0x4B4, BIT(9), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm10g0[] = { ++ { 0x414, BIT(10), 1 }, ++ { 0x4B4, BIT(10), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm11g0[] = { ++ { 0x414, BIT(11), 1 }, ++ { 0x4B4, BIT(11), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm12g0[] = { ++ { 0x414, BIT(12), 1 }, ++ { 0x4B4, BIT(12), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm13g0[] = { ++ { 0x414, BIT(13), 1 }, ++ { 0x4B4, BIT(13), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm14g0[] = { ++ { 0x414, BIT(14), 1 }, ++ { 0x4B4, BIT(14), 0 }, ++}; ++ ++static struct aspeed_sig_desc pwm15g0[] = { ++ { 0x414, BIT(15), 1 }, ++ { 0x4B4, BIT(15), 0 }, ++}; ++ + static const struct aspeed_group_config ast2600_groups[] = { + { "MAC1LINK", ARRAY_SIZE(mac1_link), mac1_link }, + { "MAC2LINK", ARRAY_SIZE(mac2_link), mac2_link }, +@@ -383,7 +487,31 @@ static const struct aspeed_group_config ast2600_groups[] = { + { "USB2AH", ARRAY_SIZE(usb2ah_link), usb2ah_link }, + { "USB2BH", ARRAY_SIZE(usb2bh_link), usb2bh_link }, + { "PCIE0RC", ARRAY_SIZE(pcie0rc_link), pcie0rc_link }, +- { "PCIE1RC", ARRAY_SIZE(pcie1rc_link), pcie1rc_link }, ++ { "PCIE1RC", ARRAY_SIZE(pcie1rc_link), pcie1rc_link }, ++ { "PWM0", ARRAY_SIZE(pwm0), pwm0 }, ++ { "PWM1", ARRAY_SIZE(pwm1), pwm1 }, ++ { "PWM2", ARRAY_SIZE(pwm2), pwm2 }, ++ { "PWM3", ARRAY_SIZE(pwm3), pwm3 }, ++ { "PWM4", ARRAY_SIZE(pwm4), pwm4 }, ++ { "PWM5", ARRAY_SIZE(pwm5), pwm5 }, ++ { "PWM6", ARRAY_SIZE(pwm6), pwm6 }, ++ { "PWM7", ARRAY_SIZE(pwm7), pwm7 }, ++ { "PWM8G1", ARRAY_SIZE(pwm8g1), pwm8g1 }, ++ { "PWM9G1", ARRAY_SIZE(pwm9g1), pwm9g1 }, ++ { "PWM10G1", ARRAY_SIZE(pwm10g1), pwm10g1 }, ++ { "PWM11G1", ARRAY_SIZE(pwm11g1), pwm11g1 }, ++ { "PWM12G1", ARRAY_SIZE(pwm12g1), pwm12g1 }, ++ { "PWM13G1", ARRAY_SIZE(pwm13g1), pwm13g1 }, ++ { "PWM14G1", ARRAY_SIZE(pwm14g1), pwm14g1 }, ++ { "PWM15G1", ARRAY_SIZE(pwm15g1), pwm15g1 }, ++ { "PWM8G0", ARRAY_SIZE(pwm8g0), pwm8g0 }, ++ { "PWM9G0", ARRAY_SIZE(pwm9g0), pwm9g0 }, ++ { "PWM10G0", ARRAY_SIZE(pwm10g0), pwm10g0 }, ++ { "PWM11G0", ARRAY_SIZE(pwm11g0), pwm11g0 }, ++ { "PWM12G0", ARRAY_SIZE(pwm12g0), pwm12g0 }, ++ { "PWM13G0", ARRAY_SIZE(pwm13g0), pwm13g0 }, ++ { "PWM14G0", ARRAY_SIZE(pwm14g0), pwm14g0 }, ++ { "PWM15G0", ARRAY_SIZE(pwm15g0), pwm15g0 }, + }; + + static int ast2600_pinctrl_get_groups_count(struct udevice *dev) +diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig +index 2984b7976637..95e82ee5ddf6 100644 +--- a/drivers/pwm/Kconfig ++++ b/drivers/pwm/Kconfig +@@ -50,3 +50,11 @@ config PWM_SUNXI + help + This PWM is found on H3, A64 and other Allwinner SoCs. It supports a + programmable period and duty cycle. A 16-bit counter is used. ++ ++config PWM_ASPEED ++ bool "Enable support for the Aspeed AST2600 PWM" ++ depends on DM_PWM ++ depends on ASPEED_AST2600 ++ help ++ This PWM is found on Aspeed AST2600 SoC. It supports a programmable ++ period and duty cycle. A 16-bit counter is used. +diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile +index a837c35ed2e3..770b054c3f3b 100644 +--- a/drivers/pwm/Makefile ++++ b/drivers/pwm/Makefile +@@ -16,3 +16,4 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o + obj-$(CONFIG_PWM_SANDBOX) += sandbox_pwm.o + obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o + obj-$(CONFIG_PWM_SUNXI) += sunxi_pwm.o ++obj-$(CONFIG_PWM_ASPEED) += aspeed_pwm.o +diff --git a/drivers/pwm/aspeed_pwm.c b/drivers/pwm/aspeed_pwm.c +new file mode 100644 +index 000000000000..111e2971d226 +--- /dev/null ++++ b/drivers/pwm/aspeed_pwm.c +@@ -0,0 +1,172 @@ ++// SPDX-License-Identifier: GPL ++// Copyright (c) 2021 Intel Corporation ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define NSEC_PER_SEC 1000000000L ++ ++#define ASPEED_PWM_CTRL 0x00 /* PWM0 General Register */ ++#define ASPEED_PWM_CTRL_CH(x) (((x) * 0x10) + ASPEED_PWM_CTRL) ++#define PWM_LOAD_AS_WDT BIT(19) ++#define PWM_DUTY_LOAD_AS_WDT_EN BIT(18) ++#define PWM_DUTY_SYNC_DIS BIT(17) ++#define PWM_CLK_ENABLE BIT(16) ++#define PWM_LEVEL_OUTPUT BIT(15) ++#define PWM_INVERSE BIT(14) ++#define PWM_OPEN_DRAIN_EN BIT(13) ++#define PWM_PIN_EN BIT(12) ++#define PWM_CLK_DIV_H_MASK GENMASK(11, 8) ++#define PWM_CLK_DIV_L_MASK GENMASK(7, 0) ++ ++#define ASPEED_PWM_DUTY_CYCLE 0x04 /* PWM0 Duty Cycle Register */ ++#define ASPEED_PWM_DUTY_CYCLE_CH(x) (((x) * 0x10) + ASPEED_PWM_DUTY_CYCLE) ++#define PWM_PERIOD_MASK GENMASK(31, 24) ++#define PWM_RISING_FALLING_AS_WDT_MASK GENMASK(23, 16) ++#define PWM_RISING_POINT_MASK GENMASK(15, 8) ++#define PWM_FALLING_POINT_MASK GENMASK(7, 0) ++ ++#define PWM_PERIOD_MAX 255 ++ ++struct aspeed_pwm_priv { ++ void __iomem *base; ++ ulong clk_freq; ++ u32 clk_tick_ns; ++}; ++ ++static int aspeed_pwm_set_config(struct udevice *dev, uint channel, ++ uint period_ns, uint duty_ns) ++{ ++ struct aspeed_pwm_priv *priv = dev_get_priv(dev); ++ u8 div_h, div_l, period_value, falling_point, rising_point; ++ u32 ctrl_value, duty_value, tick_ns; ++ ++ /* ++ * We currently avoid using 64bit arithmetic by using the ++ * fact that anything faster than 1Hz is easily representable ++ * by 32bits. ++ */ ++ if (period_ns > NSEC_PER_SEC) ++ return -ERANGE; ++ ++ for (div_l = 0; div_l <= 0xff; div_l++) { ++ for (div_h = 0; div_h <= 0xf; div_h++) { ++ tick_ns = priv->clk_tick_ns * BIT(div_h) * (div_l + 1); ++ if (tick_ns * PWM_PERIOD_MAX >= period_ns) ++ break; ++ } ++ if (tick_ns * PWM_PERIOD_MAX >= period_ns) ++ break; ++ } ++ ++ if (period_ns / tick_ns > PWM_PERIOD_MAX) ++ return -ERANGE; ++ ++ ctrl_value = FIELD_PREP(PWM_CLK_DIV_H_MASK, div_h) | ++ FIELD_PREP(PWM_CLK_DIV_L_MASK, div_l); ++ period_value = period_ns / tick_ns; ++ falling_point = 0; ++ rising_point = duty_ns / tick_ns; ++ duty_value = FIELD_PREP(PWM_PERIOD_MASK, period_value) | ++ FIELD_PREP(PWM_RISING_POINT_MASK, rising_point) | ++ FIELD_PREP(PWM_FALLING_POINT_MASK, falling_point); ++ ++ clrsetbits_le32(priv->base + ASPEED_PWM_DUTY_CYCLE_CH(channel), ++ PWM_PERIOD_MASK | PWM_RISING_POINT_MASK | ++ PWM_FALLING_POINT_MASK, duty_value); ++ clrsetbits_le32(priv->base + ASPEED_PWM_CTRL_CH(channel), ++ PWM_CLK_DIV_H_MASK | PWM_CLK_DIV_L_MASK, ctrl_value); ++ ++ return 0; ++} ++ ++static int aspeed_pwm_set_enable(struct udevice *dev, uint channel, bool enable) ++{ ++ struct aspeed_pwm_priv *priv = dev_get_priv(dev); ++ ++ debug("%s: Enable '%s' channel %u\n", __func__, dev->name, channel); ++ ++ clrsetbits_le32(priv->base + ASPEED_PWM_CTRL_CH(channel), ++ PWM_CLK_ENABLE | PWM_PIN_EN, ++ enable ? PWM_CLK_ENABLE | PWM_PIN_EN : 0); ++ ++ return 0; ++} ++ ++static int aspeed_pwm_ofdata_to_platdata(struct udevice *dev) ++{ ++ struct aspeed_pwm_priv *priv = dev_get_priv(dev); ++ struct resource res_regs; ++ int ret; ++ ++ ret = dev_read_resource(dev, 0, &res_regs); ++ if (ret < 0) ++ return ret; ++ ++ priv->base = (void __iomem *)res_regs.start; ++ ++ return 0; ++} ++ ++static int aspeed_pwm_probe(struct udevice *dev) ++{ ++ struct aspeed_pwm_priv *priv = dev_get_priv(dev); ++ struct reset_ctl reset_ctl; ++ struct clk hclk; ++ int ret; ++ ++ ret = clk_get_by_index(dev, 0, &hclk); ++ if (ret) { ++ pr_err("%s: could not get clock: %d\n", dev->name, ret); ++ return ret; ++ } ++ ++ priv->clk_freq = clk_get_rate(&hclk); ++ priv->clk_tick_ns = NSEC_PER_SEC / priv->clk_freq; ++ (void) clk_free(&hclk); ++ ++ ret = reset_get_by_index(dev, 0, &reset_ctl); ++ if (ret) { ++ pr_err("%s: Failed to get reset signal: %d\n", dev->name, ret); ++ return ret; ++ } ++ ++ ret = reset_assert(&reset_ctl); ++ if (!ret) { ++ mdelay(10); ++ ret = reset_deassert(&reset_ctl); ++ } ++ ++ return ret; ++} ++ ++static const struct pwm_ops aspeed_pwm_ops = { ++ .set_config = aspeed_pwm_set_config, ++ .set_enable = aspeed_pwm_set_enable, ++}; ++ ++static const struct udevice_id aspeed_pwm_ids[] = { ++ { .compatible = "aspeed,ast2600-pwm" }, ++ { } ++}; ++ ++U_BOOT_DRIVER(aspeed_pwm) = { ++ .name = "aspeed_pwm", ++ .id = UCLASS_PWM, ++ .of_match = aspeed_pwm_ids, ++ .ops = &aspeed_pwm_ops, ++ .ofdata_to_platdata = aspeed_pwm_ofdata_to_platdata, ++ .priv_auto_alloc_size = sizeof(struct aspeed_pwm_priv), ++ .probe = aspeed_pwm_probe, ++}; ++ ++MODULE_AUTHOR("Jae Hyun Yoo "); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Aspeed AST2600 PWM Driver"); +-- +2.17.1 + -- cgit v1.2.3