Message ID | 1477611622-28120-2-git-send-email-jaghu@google.com |
---|---|
State | Superseded, archived |
Headers | show |
On Thu, Oct 27, 2016 at 4:40 PM, Jaghathiswari Rankappagounder Natarajan < jaghu@google.com> wrote: > Support to give all the common information required by all the PWM > channels. > > This description doesn't help me understand what problem you are solving. From Section 2, Describe Your Changes, of https://www.kernel.org/doc/Documentation/SubmittingPatches: "Convince the reviewer that there is a problem worth fixing and that it makes sense for them to read past the first paragraph." I suggest reading that whole section. > Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com> > --- > .../bindings/hwmon/aspeed_pwm_controller.txt | 33 +++ > drivers/hwmon/Kconfig | 5 + > drivers/hwmon/Makefile | 2 +- > drivers/hwmon/aspeed_pwm.h | 159 ++++++++++++++ > drivers/hwmon/aspeed_pwm_controller.c | 237 > +++++++++++++++++++++ > 5 files changed, 435 insertions(+), 1 deletion(-) > create mode 100644 Documentation/devicetree/bindings/hwmon/aspeed_pwm_ > controller.txt > create mode 100644 drivers/hwmon/aspeed_pwm.h > create mode 100644 drivers/hwmon/aspeed_pwm_controller.c > > diff --git a/Documentation/devicetree/bindings/hwmon/aspeed_pwm_controller.txt > b/Documentation/devicetree/bindings/hwmon/aspeed_pwm_controller.txt > new file mode 100644 > index 0000000..2b5c895 > --- /dev/null > +++ b/Documentation/devicetree/bindings/hwmon/aspeed_pwm_controller.txt > Per https://www.kernel.org/doc/Documentation/devicetree/bindings/submitting-patches.txt, the binding documentation updates should be a separate patch. > @@ -0,0 +1,33 @@ > +Aspeed PWM controller driver > You're implying that there is only one PWM controller they have _and_ _will_ ever use. Including AST2400/2500 in the description puts some reasonable bounds and directs people to the correct SoCs that will have documentation in their datasheets. > + > +Required properties: > +- reg : address and length of the register set for the device. > +- #address-cells : should be 1. > +- #size-cells : should be 1. > +- compatible : should be "aspeed-pwm-controller". > I thought the format was "<manufacturer>,<chip>-<device>" so "aspeed,ast2500-pwm" > +- clock_enable : option to enable PWM and fan tach clock. should be 1. > +- clock_source : option for clock source selection. 0 indicates 24MHz > clock > + and 1 indicates MCLK. > +- typem_pwm_clock : This array contains 3 values. The first value > indicates > + the type M PWM clock division L bit. The second value indicates type M > PWM > + clock divison H bit. The third value indicates type M PWM period bit. > I have no idea what any of this means. What is type M clock division? How do I determine the L, H, and period bits? > + > +Optional properties: > +- typen_pwm_clock : This array contains 3 values. The first value > indicates > + the type N PWM clock division L bit. The second value indicates type N > PWM > + clock division H bit. The third value indicates type N PWM period bit. > +- typeo_pwm_clock : This array contains 3 values. The first value > indicates > + the type O PWM clock division L bit. The second value indicates type O > PWM > + clock divison H bit. The third value indicates type O PWM period bit. > + > +Examples: > + > +pwm_controller { > + #address-cells = <1>; > + #size-cells = <1>; > + reg = <0x1E786000 0x78>; > + compatible = "aspeed-pwm-controller"; > + clock_enable = /bits/ 8 <0x01>; > + clock_source = /bits/ 8 <0x00>; > + typem_pwm_clock = <5 0 95>; > +}; > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig > index d4de8d5..59d6ea4 100644 > --- a/drivers/hwmon/Kconfig > +++ b/drivers/hwmon/Kconfig > @@ -1803,6 +1803,11 @@ config SENSORS_WM8350 > This driver can also be built as a module. If so, the module > will be called wm8350-hwmon. > > +config ASPEED_PWM_CONTROLLER > + tristate "Aspeed PWM controller" > + help > + This driver provides support for ASPEED PWM controller. > + > config SENSORS_ULTRA45 > tristate "Sun Ultra45 PIC16F747" > depends on SPARC64 > diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile > index 4455478..83156f8 100644 > --- a/drivers/hwmon/Makefile > +++ b/drivers/hwmon/Makefile > @@ -164,7 +164,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o > obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o > obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o > obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o > - > +obj-$(CONFIG_ASPEED_PWM_CONTROLLER) += aspeed_pwm_controller.o > obj-$(CONFIG_PMBUS) += pmbus/ > > ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG > diff --git a/drivers/hwmon/aspeed_pwm.h b/drivers/hwmon/aspeed_pwm.h > new file mode 100644 > index 0000000..b3dd6b1 > --- /dev/null > +++ b/drivers/hwmon/aspeed_pwm.h > @@ -0,0 +1,159 @@ > +/* > + * Aspeed PWM header file > + * * Copyright (c) 2016 Google, Inc > + * > + * * This program is free software; you can redistribute it and/or modify > + * * it under the terms of the GNU General Public License version 2 as > + * * published by the Free Software Foundation. > + * > + */ > + > +#ifndef __ASPEED_PWM_H > +#define __ASPEED_PWM_H __FILE__ > + > +/* AST PWM & FAN Register Definition */ > +#define AST_PTCR_CTRL 0x00 > +#define AST_PTCR_CLK_CTRL 0x04 > +#define AST_PTCR_DUTY0_CTRL 0x08 > +#define AST_PTCR_DUTY1_CTRL 0x0c > +#define AST_PTCR_TYPEM_CTRL0 0x10 > +#define AST_PTCR_TYPEM_CTRL1 0x14 > +#define AST_PTCR_TYPEN_CTRL0 0x18 > +#define AST_PTCR_TYPEN_CTRL1 0x1c > +#define AST_PTCR_TACH_SOURCE 0x20 > +#define AST_PTCR_TRIGGER 0x28 > +#define AST_PTCR_RESULT 0x2c > +#define AST_PTCR_INTR_CTRL 0x30 > +#define AST_PTCR_INTR_STS 0x34 > +#define AST_PTCR_TYPEM_LIMIT 0x38 > +#define AST_PTCR_TYPEN_LIMIT 0x3C > +#define AST_PTCR_CTRL_EXT 0x40 > +#define AST_PTCR_CLK_EXT_CTRL 0x44 > +#define AST_PTCR_DUTY2_CTRL 0x48 > +#define AST_PTCR_DUTY3_CTRL 0x4c > +#define AST_PTCR_TYPEO_CTRL0 0x50 > +#define AST_PTCR_TYPEO_CTRL1 0x54 > +#define AST_PTCR_TACH_SOURCE_EXT 0x60 > +#define AST_PTCR_TYPEO_LIMIT 0x78 > + > +/* COMMON Definition */ > +#define PWM_TYPE_M 0x0 > +#define PWM_TYPE_N 0x1 > +#define PWM_TYPE_O 0x2 > + > +#define PWMA 0x0 > +#define PWMB 0x1 > +#define PWMC 0x2 > +#define PWMD 0x3 > +#define PWME 0x4 > +#define PWMF 0x5 > +#define PWMG 0x6 > +#define PWMH 0x7 > + > +#define DUTY_CTRL_PWM2_FALL_POINT (24) > +#define DUTY_CTRL_PWM2_FALL_POINT_MASK (0xff<<24) > +#define DUTY_CTRL_PWM2_RISE_POINT (16) > +#define DUTY_CTRL_PWM2_RISE_POINT_MASK (0xff<<16) > +#define DUTY_CTRL_PWM1_FALL_POINT (8) > +#define DUTY_CTRL_PWM1_FALL_POINT_MASK (0xff<<8) > +#define DUTY_CTRL_PWM1_RISE_POINT (0) > +#define DUTY_CTRL_PWM1_RISE_POINT_MASK (0xff) > + > +/* AST_PTCR_CTRL : 0x00 - General Control Register */ > +#define AST_PTCR_CTRL_SET_PWMD_TYPE(x) ((x & 0x1) << 15 | \ > + (x & 0x2) << 6) > +#define AST_PTCR_CTRL_GET_PWMD_TYPE(x) (((x & (0x1 << 7)) >> 6) | > \ > + ((x & (0x1 << 15)) >> 15)) > +#define AST_PTCR_CTRL_SET_PWMD_TYPE_MASK ((0x1 << 7) | (0x1 << 15)) > + > +#define AST_PTCR_CTRL_SET_PWMC_TYPE(x) ((x & 0x1) << 14 | \ > + (x & 0x2) << 5) > +#define AST_PTCR_CTRL_GET_PWMC_TYPE(x) (((x & (0x1 << 6)) >> 5) | > \ > + ((x & (0x1 << 14)) >> 14)) > +#define AST_PTCR_CTRL_SET_PWMC_TYPE_MASK ((0x1 << 6) | (0x1 << 14)) > + > +#define AST_PTCR_CTRL_SET_PWMB_TYPE(x) ((x & 0x1) << 13 | \ > + (x & 0x2) << 4) > +#define AST_PTCR_CTRL_GET_PWMB_TYPE(x) (((x & (0x1 << 5)) >> 4) | > \ > + ((x & (0x1 << 13)) >> 13)) > +#define AST_PTCR_CTRL_SET_PWMB_TYPE_MASK ((0x1 << 5) | (0x1 << 13)) > + > +#define AST_PTCR_CTRL_SET_PWMA_TYPE(x) ((x & 0x1) << 12 | \ > + (x & 0x2) << 3) > +#define AST_PTCR_CTRL_GET_PWMA_TYPE(x) (((x & (0x1 << 4)) >> 3) | > \ > + ((x & (0x1 << 12)) >> 12)) > +#define AST_PTCR_CTRL_SET_PWMA_TYPE_MASK ((0x1 << 4) | (0x1 << 12)) > + > +#define AST_PTCR_CTRL_PWMD (11) > +#define AST_PTCR_CTRL_PWMD_EN (0x1 << 11) > +#define AST_PTCR_CTRL_PWMC (10) > +#define AST_PTCR_CTRL_PWMC_EN (0x1 << 10) > +#define AST_PTCR_CTRL_PWMB (9) > +#define AST_PTCR_CTRL_PWMB_EN (0x1 << 9) > +#define AST_PTCR_CTRL_PWMA (8) > +#define AST_PTCR_CTRL_PWMA_EN (0x1 << 8) > + > +/*0:24Mhz, 1:MCLK */ > +#define AST_PTCR_CTRL_CLK_SRC 0x2 > +#define AST_PTCR_CTRL_CLK_EN 0x1 > + > +/* AST_PTCR_CLK_CTRL : 0x04 - Clock Control Register */ > +/* TYPE N */ > +#define AST_PTCR_CLK_CTRL_TYPEN_UNIT (24) > +#define AST_PTCR_CLK_CTRL_TYPEN_UNIT_MASK (0xff << 24) > +#define AST_PTCR_CLK_CTRL_TYPEN_H (20) > +#define AST_PTCR_CLK_CTRL_TYPEN_H_MASK (0xf << 20) > +#define AST_PTCR_CLK_CTRL_TYPEN_L (16) > +#define AST_PTCR_CLK_CTRL_TYPEN_L_MASK (0xf << 16) > +/* TYPE M */ > +#define AST_PTCR_CLK_CTRL_TYPEM_UNIT (8) > +#define AST_PTCR_CLK_CTRL_TYPEM_UNIT_MASK (0xff << 8) > +#define AST_PTCR_CLK_CTRL_TYPEM_H (4) > +#define AST_PTCR_CLK_CTRL_TYPEM_H_MASK (0xf << 4) > +#define AST_PTCR_CLK_CTRL_TYPEM_L (0) > +#define AST_PTCR_CLK_CTRL_TYPEM_L_MASK (0xf) > + > +/* AST_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */ > +#define AST_PTCR_CTRL_SET_PWMH_TYPE(x) ((x & 0x1) << 15 | \ > + (x & 0x2) << 6) > +#define AST_PTCR_CTRL_GET_PWMH_TYPE(x) (((x & (0x1 << 7)) >> 6) | > \ > + ((x & (0x1 << 15)) >> 15)) > +#define AST_PTCR_CTRL_SET_PWMH_TYPE_MASK ((0x1 << 7) | (0x1 << 15)) > + > +#define AST_PTCR_CTRL_SET_PWMG_TYPE(x) ((x & 0x1) << 14 | \ > + (x & 0x2) << 5) > +#define AST_PTCR_CTRL_GET_PWMG_TYPE(x) (((x & (0x1 << 6)) >> 5) | > \ > + ((x & (0x1 << 14)) >> 14)) > +#define AST_PTCR_CTRL_SET_PWMG_TYPE_MASK ((0x1 << 6) | (0x1 << 14)) > + > +#define AST_PTCR_CTRL_SET_PWMF_TYPE(x) ((x & 0x1) << 13 | \ > + (x & 0x2) << 4) > +#define AST_PTCR_CTRL_GET_PWMF_TYPE(x) (((x & (0x1 << 5)) >> 4) | > \ > + ((x & (0x1 << 13)) >> 13)) > +#define AST_PTCR_CTRL_SET_PWMF_TYPE_MASK ((0x1 << 5) | (0x1 << 13)) > + > +#define AST_PTCR_CTRL_SET_PWME_TYPE(x) ((x & 0x1) << 12 | \ > + (x & 0x2) << 3) > +#define AST_PTCR_CTRL_GET_PWME_TYPE(x) (((x & (0x1 << 4)) >> 3) | > \ > + ((x & (0x1 << 12)) >> 12)) > +#define AST_PTCR_CTRL_SET_PWME_TYPE_MASK ((0x1 << 4) | (0x1 << 12)) > + > +#define AST_PTCR_CTRL_PWMH (11) > +#define AST_PTCR_CTRL_PWMH_EN (0x1 << 11) > +#define AST_PTCR_CTRL_PWMG (10) > +#define AST_PTCR_CTRL_PWMG_EN (0x1 << 10) > +#define AST_PTCR_CTRL_PWMF (9) > +#define AST_PTCR_CTRL_PWMF_EN (0x1 << 9) > +#define AST_PTCR_CTRL_PWME (8) > +#define AST_PTCR_CTRL_PWME_EN (0x1 << 8) > + > +/* AST_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */ > +/* TYPE O */ > +#define AST_PTCR_CLK_CTRL_TYPEO_UNIT (8) > +#define AST_PTCR_CLK_CTRL_TYPEO_UNIT_MASK (0xff << 8) > +#define AST_PTCR_CLK_CTRL_TYPEO_H (4) > +#define AST_PTCR_CLK_CTRL_TYPEO_H_MASK (0xf << 4) > +#define AST_PTCR_CLK_CTRL_TYPEO_L (0) > +#define AST_PTCR_CLK_CTRL_TYPEO_L_MASK (0xf) > + > +#endif /* __ASPEED_PWM_H */ > diff --git a/drivers/hwmon/aspeed_pwm_controller.c > b/drivers/hwmon/aspeed_pwm_controller.c > new file mode 100644 > index 0000000..f846132 > --- /dev/null > +++ b/drivers/hwmon/aspeed_pwm_controller.c > @@ -0,0 +1,237 @@ > +/* > + * Aspeed PWM controller driver > + * * Copyright (c) 2016 Google, Inc > + * > + * * This program is free software; you can redistribute it and/or modify > + * * it under the terms of the GNU General Public License version 2 as > + * * published by the Free Software Foundation. > + * > + */ > + > +#include <linux/platform_device.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/of_platform.h> > +#include <linux/of_device.h> > +#include <linux/io.h> > + > +#include "aspeed_pwm.h" > + > +struct ast_pwm_controller_data { > + void __iomem *base; > +}; > + > +static inline void > +ast_pwm_controller_write(struct ast_pwm_controller_data *priv, u32 val, > u32 reg) > +{ > + writel(val, priv->base + reg); > +} > + > +static inline u32 > +ast_pwm_controller_read(struct ast_pwm_controller_data *priv, u32 reg) > +{ > + u32 val = readl(priv->base + reg); > + return val; > +} > + > +static void > +ast_set_pwm_clock_enable(struct ast_pwm_controller_data *priv, u8 val) > +{ > + if (val) { > + ast_pwm_controller_write(priv, > + ast_pwm_controller_read(priv, AST_PTCR_CTRL) | > + AST_PTCR_CTRL_CLK_EN, AST_PTCR_CTRL); > + } else { > + ast_pwm_controller_write(priv, > + ast_pwm_controller_read(priv, AST_PTCR_CTRL) & > + ~AST_PTCR_CTRL_CLK_EN, AST_PTCR_CTRL); > + } > +} > + > +static void > +ast_set_pwm_clock_source(struct ast_pwm_controller_data *priv, u8 val) > +{ > + if (val) { > + ast_pwm_controller_write(priv, > + ast_pwm_controller_read(priv, AST_PTCR_CTRL) | > + AST_PTCR_CTRL_CLK_SRC, AST_PTCR_CTRL); > + } else { > + ast_pwm_controller_write(priv, > + ast_pwm_controller_read(priv, AST_PTCR_CTRL) & > + ~AST_PTCR_CTRL_CLK_SRC, AST_PTCR_CTRL); > + } > +} > + > +static void > +ast_set_pwm_clock_division_h(struct ast_pwm_controller_data *priv, > + u8 pwm_type, u8 div_high) > +{ > + switch (pwm_type) { > + case PWM_TYPE_M: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEM_H_MASK) | > + (div_high << AST_PTCR_CLK_CTRL_TYPEM_H), > + AST_PTCR_CLK_CTRL); > + break; > + case PWM_TYPE_N: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEN_H_MASK) | > + (div_high << AST_PTCR_CLK_CTRL_TYPEN_H), > + AST_PTCR_CLK_CTRL); > + break; > + case PWM_TYPE_O: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, > AST_PTCR_CLK_EXT_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEO_H_MASK) | > + (div_high << AST_PTCR_CLK_CTRL_TYPEO_H), > + AST_PTCR_CLK_EXT_CTRL); > + break; > + } > +} > + > +static void > +ast_set_pwm_clock_division_l(struct ast_pwm_controller_data *priv, > + u8 pwm_type, u8 div_low) > +{ > + switch (pwm_type) { > + case PWM_TYPE_M: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEM_L_MASK) | > + (div_low << AST_PTCR_CLK_CTRL_TYPEM_L), > + AST_PTCR_CLK_CTRL); > + break; > + case PWM_TYPE_N: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEN_L_MASK) | > + (div_low << AST_PTCR_CLK_CTRL_TYPEN_L), > + AST_PTCR_CLK_CTRL); > + break; > + case PWM_TYPE_O: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, > AST_PTCR_CLK_EXT_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEO_L_MASK) | > + (div_low << AST_PTCR_CLK_CTRL_TYPEO_L), > + AST_PTCR_CLK_EXT_CTRL); > + break; > + } > +} > + > +static void > +ast_set_pwm_clock_unit(struct ast_pwm_controller_data *priv, u8 pwm_type, > + u8 unit) > +{ > + switch (pwm_type) { > + case PWM_TYPE_M: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEM_UNIT_MASK) | > + (unit << AST_PTCR_CLK_CTRL_TYPEM_UNIT), > + AST_PTCR_CLK_CTRL); > + break; > + case PWM_TYPE_N: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEN_UNIT_MASK) | > + (unit << AST_PTCR_CLK_CTRL_TYPEN_UNIT), > + AST_PTCR_CLK_CTRL); > + break; > + case PWM_TYPE_O: > + ast_pwm_controller_write(priv, > + (ast_pwm_controller_read(priv, > AST_PTCR_CLK_EXT_CTRL) & > + ~AST_PTCR_CLK_CTRL_TYPEO_UNIT_MASK) | > + (unit << AST_PTCR_CLK_CTRL_TYPEO_UNIT), > + AST_PTCR_CLK_EXT_CTRL); > + break; > + } > +} > + > +static int > +aspeed_pwm_controller_probe(struct platform_device *pdev) > +{ > + u32 buf[3]; > + int err; > + struct device_node *np; > + struct resource *res; > + u8 val; > + struct ast_pwm_controller_data *priv; > + > + np = pdev->dev.of_node; > + > + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + > + priv->base = devm_ioremap(&pdev->dev, res->start, > resource_size(res)); > + if (!priv->base) > + return -ENOMEM; > + > + err = of_property_read_u8(np, "clock_enable", &val); > + if (!err) { > + ast_set_pwm_clock_enable(priv, val); > + } else { > + return err; > + } > + err = of_property_read_u8(np, "clock_source", &val); > + if (!err) { > + ast_set_pwm_clock_source(priv, val); > + } else { > + return err; > + } > + > + err = of_property_read_u32_array(np, "typem_pwm_clock", buf, 3); > + if (!err) { > + ast_set_pwm_clock_division_l(priv, PWM_TYPE_M, buf[0]); > + ast_set_pwm_clock_division_h(priv, PWM_TYPE_M, buf[1]); > + ast_set_pwm_clock_unit(priv, PWM_TYPE_M, buf[2]); > + } > + > + err = of_property_read_u32_array(np, "typen_pwm_clock", buf, 3); > + if (!err) { > + ast_set_pwm_clock_division_l(priv, PWM_TYPE_N, buf[0]); > + ast_set_pwm_clock_division_h(priv, PWM_TYPE_N, buf[1]); > + ast_set_pwm_clock_unit(priv, PWM_TYPE_N, buf[2]); > + } > + > + err = of_property_read_u32_array(np, "typeo_pwm_clock", buf, 3); > + if (!err) { > + ast_set_pwm_clock_division_l(priv, PWM_TYPE_O, buf[0]); > + ast_set_pwm_clock_division_h(priv, PWM_TYPE_O, buf[1]); > + ast_set_pwm_clock_unit(priv, PWM_TYPE_O, buf[2]); > + } > + > + return 0; > +} > + > +static int > +aspeed_pwm_controller_remove(struct platform_device *pdev) > +{ > + return 0; > +} > + > +static const struct of_device_id of_pwm_controller_match_table[] = { > + { .compatible = "aspeed-pwm-controller", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, of_pwm_controller_match_table); > + > +static struct platform_driver aspeed_pwm_controller_driver = { > + .probe = aspeed_pwm_controller_probe, > + .remove = aspeed_pwm_controller_remove, > + .driver = { > + .name = "aspeed_pwm_controller", > + .owner = THIS_MODULE, > + .of_match_table = of_pwm_controller_match_table, > + }, > +}; > + > +module_platform_driver(aspeed_pwm_controller_driver); > + > +MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com > >"); > +MODULE_DESCRIPTION("ASPEED PWM controller driver"); > +MODULE_LICENSE("GPL"); > -- > 2.8.0.rc3.226.g39d4020 > > _______________________________________________ > openbmc mailing list > openbmc@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/openbmc >
diff --git a/Documentation/devicetree/bindings/hwmon/aspeed_pwm_controller.txt b/Documentation/devicetree/bindings/hwmon/aspeed_pwm_controller.txt new file mode 100644 index 0000000..2b5c895 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/aspeed_pwm_controller.txt @@ -0,0 +1,33 @@ +Aspeed PWM controller driver + +Required properties: +- reg : address and length of the register set for the device. +- #address-cells : should be 1. +- #size-cells : should be 1. +- compatible : should be "aspeed-pwm-controller". +- clock_enable : option to enable PWM and fan tach clock. should be 1. +- clock_source : option for clock source selection. 0 indicates 24MHz clock + and 1 indicates MCLK. +- typem_pwm_clock : This array contains 3 values. The first value indicates + the type M PWM clock division L bit. The second value indicates type M PWM + clock divison H bit. The third value indicates type M PWM period bit. + +Optional properties: +- typen_pwm_clock : This array contains 3 values. The first value indicates + the type N PWM clock division L bit. The second value indicates type N PWM + clock division H bit. The third value indicates type N PWM period bit. +- typeo_pwm_clock : This array contains 3 values. The first value indicates + the type O PWM clock division L bit. The second value indicates type O PWM + clock divison H bit. The third value indicates type O PWM period bit. + +Examples: + +pwm_controller { + #address-cells = <1>; + #size-cells = <1>; + reg = <0x1E786000 0x78>; + compatible = "aspeed-pwm-controller"; + clock_enable = /bits/ 8 <0x01>; + clock_source = /bits/ 8 <0x00>; + typem_pwm_clock = <5 0 95>; +}; diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d4de8d5..59d6ea4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1803,6 +1803,11 @@ config SENSORS_WM8350 This driver can also be built as a module. If so, the module will be called wm8350-hwmon. +config ASPEED_PWM_CONTROLLER + tristate "Aspeed PWM controller" + help + This driver provides support for ASPEED PWM controller. + config SENSORS_ULTRA45 tristate "Sun Ultra45 PIC16F747" depends on SPARC64 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 4455478..83156f8 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -164,7 +164,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o - +obj-$(CONFIG_ASPEED_PWM_CONTROLLER) += aspeed_pwm_controller.o obj-$(CONFIG_PMBUS) += pmbus/ ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG diff --git a/drivers/hwmon/aspeed_pwm.h b/drivers/hwmon/aspeed_pwm.h new file mode 100644 index 0000000..b3dd6b1 --- /dev/null +++ b/drivers/hwmon/aspeed_pwm.h @@ -0,0 +1,159 @@ +/* + * Aspeed PWM header file + * * Copyright (c) 2016 Google, Inc + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License version 2 as + * * published by the Free Software Foundation. + * + */ + +#ifndef __ASPEED_PWM_H +#define __ASPEED_PWM_H __FILE__ + +/* AST PWM & FAN Register Definition */ +#define AST_PTCR_CTRL 0x00 +#define AST_PTCR_CLK_CTRL 0x04 +#define AST_PTCR_DUTY0_CTRL 0x08 +#define AST_PTCR_DUTY1_CTRL 0x0c +#define AST_PTCR_TYPEM_CTRL0 0x10 +#define AST_PTCR_TYPEM_CTRL1 0x14 +#define AST_PTCR_TYPEN_CTRL0 0x18 +#define AST_PTCR_TYPEN_CTRL1 0x1c +#define AST_PTCR_TACH_SOURCE 0x20 +#define AST_PTCR_TRIGGER 0x28 +#define AST_PTCR_RESULT 0x2c +#define AST_PTCR_INTR_CTRL 0x30 +#define AST_PTCR_INTR_STS 0x34 +#define AST_PTCR_TYPEM_LIMIT 0x38 +#define AST_PTCR_TYPEN_LIMIT 0x3C +#define AST_PTCR_CTRL_EXT 0x40 +#define AST_PTCR_CLK_EXT_CTRL 0x44 +#define AST_PTCR_DUTY2_CTRL 0x48 +#define AST_PTCR_DUTY3_CTRL 0x4c +#define AST_PTCR_TYPEO_CTRL0 0x50 +#define AST_PTCR_TYPEO_CTRL1 0x54 +#define AST_PTCR_TACH_SOURCE_EXT 0x60 +#define AST_PTCR_TYPEO_LIMIT 0x78 + +/* COMMON Definition */ +#define PWM_TYPE_M 0x0 +#define PWM_TYPE_N 0x1 +#define PWM_TYPE_O 0x2 + +#define PWMA 0x0 +#define PWMB 0x1 +#define PWMC 0x2 +#define PWMD 0x3 +#define PWME 0x4 +#define PWMF 0x5 +#define PWMG 0x6 +#define PWMH 0x7 + +#define DUTY_CTRL_PWM2_FALL_POINT (24) +#define DUTY_CTRL_PWM2_FALL_POINT_MASK (0xff<<24) +#define DUTY_CTRL_PWM2_RISE_POINT (16) +#define DUTY_CTRL_PWM2_RISE_POINT_MASK (0xff<<16) +#define DUTY_CTRL_PWM1_FALL_POINT (8) +#define DUTY_CTRL_PWM1_FALL_POINT_MASK (0xff<<8) +#define DUTY_CTRL_PWM1_RISE_POINT (0) +#define DUTY_CTRL_PWM1_RISE_POINT_MASK (0xff) + +/* AST_PTCR_CTRL : 0x00 - General Control Register */ +#define AST_PTCR_CTRL_SET_PWMD_TYPE(x) ((x & 0x1) << 15 | \ + (x & 0x2) << 6) +#define AST_PTCR_CTRL_GET_PWMD_TYPE(x) (((x & (0x1 << 7)) >> 6) | \ + ((x & (0x1 << 15)) >> 15)) +#define AST_PTCR_CTRL_SET_PWMD_TYPE_MASK ((0x1 << 7) | (0x1 << 15)) + +#define AST_PTCR_CTRL_SET_PWMC_TYPE(x) ((x & 0x1) << 14 | \ + (x & 0x2) << 5) +#define AST_PTCR_CTRL_GET_PWMC_TYPE(x) (((x & (0x1 << 6)) >> 5) | \ + ((x & (0x1 << 14)) >> 14)) +#define AST_PTCR_CTRL_SET_PWMC_TYPE_MASK ((0x1 << 6) | (0x1 << 14)) + +#define AST_PTCR_CTRL_SET_PWMB_TYPE(x) ((x & 0x1) << 13 | \ + (x & 0x2) << 4) +#define AST_PTCR_CTRL_GET_PWMB_TYPE(x) (((x & (0x1 << 5)) >> 4) | \ + ((x & (0x1 << 13)) >> 13)) +#define AST_PTCR_CTRL_SET_PWMB_TYPE_MASK ((0x1 << 5) | (0x1 << 13)) + +#define AST_PTCR_CTRL_SET_PWMA_TYPE(x) ((x & 0x1) << 12 | \ + (x & 0x2) << 3) +#define AST_PTCR_CTRL_GET_PWMA_TYPE(x) (((x & (0x1 << 4)) >> 3) | \ + ((x & (0x1 << 12)) >> 12)) +#define AST_PTCR_CTRL_SET_PWMA_TYPE_MASK ((0x1 << 4) | (0x1 << 12)) + +#define AST_PTCR_CTRL_PWMD (11) +#define AST_PTCR_CTRL_PWMD_EN (0x1 << 11) +#define AST_PTCR_CTRL_PWMC (10) +#define AST_PTCR_CTRL_PWMC_EN (0x1 << 10) +#define AST_PTCR_CTRL_PWMB (9) +#define AST_PTCR_CTRL_PWMB_EN (0x1 << 9) +#define AST_PTCR_CTRL_PWMA (8) +#define AST_PTCR_CTRL_PWMA_EN (0x1 << 8) + +/*0:24Mhz, 1:MCLK */ +#define AST_PTCR_CTRL_CLK_SRC 0x2 +#define AST_PTCR_CTRL_CLK_EN 0x1 + +/* AST_PTCR_CLK_CTRL : 0x04 - Clock Control Register */ +/* TYPE N */ +#define AST_PTCR_CLK_CTRL_TYPEN_UNIT (24) +#define AST_PTCR_CLK_CTRL_TYPEN_UNIT_MASK (0xff << 24) +#define AST_PTCR_CLK_CTRL_TYPEN_H (20) +#define AST_PTCR_CLK_CTRL_TYPEN_H_MASK (0xf << 20) +#define AST_PTCR_CLK_CTRL_TYPEN_L (16) +#define AST_PTCR_CLK_CTRL_TYPEN_L_MASK (0xf << 16) +/* TYPE M */ +#define AST_PTCR_CLK_CTRL_TYPEM_UNIT (8) +#define AST_PTCR_CLK_CTRL_TYPEM_UNIT_MASK (0xff << 8) +#define AST_PTCR_CLK_CTRL_TYPEM_H (4) +#define AST_PTCR_CLK_CTRL_TYPEM_H_MASK (0xf << 4) +#define AST_PTCR_CLK_CTRL_TYPEM_L (0) +#define AST_PTCR_CLK_CTRL_TYPEM_L_MASK (0xf) + +/* AST_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */ +#define AST_PTCR_CTRL_SET_PWMH_TYPE(x) ((x & 0x1) << 15 | \ + (x & 0x2) << 6) +#define AST_PTCR_CTRL_GET_PWMH_TYPE(x) (((x & (0x1 << 7)) >> 6) | \ + ((x & (0x1 << 15)) >> 15)) +#define AST_PTCR_CTRL_SET_PWMH_TYPE_MASK ((0x1 << 7) | (0x1 << 15)) + +#define AST_PTCR_CTRL_SET_PWMG_TYPE(x) ((x & 0x1) << 14 | \ + (x & 0x2) << 5) +#define AST_PTCR_CTRL_GET_PWMG_TYPE(x) (((x & (0x1 << 6)) >> 5) | \ + ((x & (0x1 << 14)) >> 14)) +#define AST_PTCR_CTRL_SET_PWMG_TYPE_MASK ((0x1 << 6) | (0x1 << 14)) + +#define AST_PTCR_CTRL_SET_PWMF_TYPE(x) ((x & 0x1) << 13 | \ + (x & 0x2) << 4) +#define AST_PTCR_CTRL_GET_PWMF_TYPE(x) (((x & (0x1 << 5)) >> 4) | \ + ((x & (0x1 << 13)) >> 13)) +#define AST_PTCR_CTRL_SET_PWMF_TYPE_MASK ((0x1 << 5) | (0x1 << 13)) + +#define AST_PTCR_CTRL_SET_PWME_TYPE(x) ((x & 0x1) << 12 | \ + (x & 0x2) << 3) +#define AST_PTCR_CTRL_GET_PWME_TYPE(x) (((x & (0x1 << 4)) >> 3) | \ + ((x & (0x1 << 12)) >> 12)) +#define AST_PTCR_CTRL_SET_PWME_TYPE_MASK ((0x1 << 4) | (0x1 << 12)) + +#define AST_PTCR_CTRL_PWMH (11) +#define AST_PTCR_CTRL_PWMH_EN (0x1 << 11) +#define AST_PTCR_CTRL_PWMG (10) +#define AST_PTCR_CTRL_PWMG_EN (0x1 << 10) +#define AST_PTCR_CTRL_PWMF (9) +#define AST_PTCR_CTRL_PWMF_EN (0x1 << 9) +#define AST_PTCR_CTRL_PWME (8) +#define AST_PTCR_CTRL_PWME_EN (0x1 << 8) + +/* AST_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */ +/* TYPE O */ +#define AST_PTCR_CLK_CTRL_TYPEO_UNIT (8) +#define AST_PTCR_CLK_CTRL_TYPEO_UNIT_MASK (0xff << 8) +#define AST_PTCR_CLK_CTRL_TYPEO_H (4) +#define AST_PTCR_CLK_CTRL_TYPEO_H_MASK (0xf << 4) +#define AST_PTCR_CLK_CTRL_TYPEO_L (0) +#define AST_PTCR_CLK_CTRL_TYPEO_L_MASK (0xf) + +#endif /* __ASPEED_PWM_H */ diff --git a/drivers/hwmon/aspeed_pwm_controller.c b/drivers/hwmon/aspeed_pwm_controller.c new file mode 100644 index 0000000..f846132 --- /dev/null +++ b/drivers/hwmon/aspeed_pwm_controller.c @@ -0,0 +1,237 @@ +/* + * Aspeed PWM controller driver + * * Copyright (c) 2016 Google, Inc + * + * * This program is free software; you can redistribute it and/or modify + * * it under the terms of the GNU General Public License version 2 as + * * published by the Free Software Foundation. + * + */ + +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/of_device.h> +#include <linux/io.h> + +#include "aspeed_pwm.h" + +struct ast_pwm_controller_data { + void __iomem *base; +}; + +static inline void +ast_pwm_controller_write(struct ast_pwm_controller_data *priv, u32 val, u32 reg) +{ + writel(val, priv->base + reg); +} + +static inline u32 +ast_pwm_controller_read(struct ast_pwm_controller_data *priv, u32 reg) +{ + u32 val = readl(priv->base + reg); + return val; +} + +static void +ast_set_pwm_clock_enable(struct ast_pwm_controller_data *priv, u8 val) +{ + if (val) { + ast_pwm_controller_write(priv, + ast_pwm_controller_read(priv, AST_PTCR_CTRL) | + AST_PTCR_CTRL_CLK_EN, AST_PTCR_CTRL); + } else { + ast_pwm_controller_write(priv, + ast_pwm_controller_read(priv, AST_PTCR_CTRL) & + ~AST_PTCR_CTRL_CLK_EN, AST_PTCR_CTRL); + } +} + +static void +ast_set_pwm_clock_source(struct ast_pwm_controller_data *priv, u8 val) +{ + if (val) { + ast_pwm_controller_write(priv, + ast_pwm_controller_read(priv, AST_PTCR_CTRL) | + AST_PTCR_CTRL_CLK_SRC, AST_PTCR_CTRL); + } else { + ast_pwm_controller_write(priv, + ast_pwm_controller_read(priv, AST_PTCR_CTRL) & + ~AST_PTCR_CTRL_CLK_SRC, AST_PTCR_CTRL); + } +} + +static void +ast_set_pwm_clock_division_h(struct ast_pwm_controller_data *priv, + u8 pwm_type, u8 div_high) +{ + switch (pwm_type) { + case PWM_TYPE_M: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEM_H_MASK) | + (div_high << AST_PTCR_CLK_CTRL_TYPEM_H), + AST_PTCR_CLK_CTRL); + break; + case PWM_TYPE_N: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEN_H_MASK) | + (div_high << AST_PTCR_CLK_CTRL_TYPEN_H), + AST_PTCR_CLK_CTRL); + break; + case PWM_TYPE_O: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_EXT_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEO_H_MASK) | + (div_high << AST_PTCR_CLK_CTRL_TYPEO_H), + AST_PTCR_CLK_EXT_CTRL); + break; + } +} + +static void +ast_set_pwm_clock_division_l(struct ast_pwm_controller_data *priv, + u8 pwm_type, u8 div_low) +{ + switch (pwm_type) { + case PWM_TYPE_M: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEM_L_MASK) | + (div_low << AST_PTCR_CLK_CTRL_TYPEM_L), + AST_PTCR_CLK_CTRL); + break; + case PWM_TYPE_N: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEN_L_MASK) | + (div_low << AST_PTCR_CLK_CTRL_TYPEN_L), + AST_PTCR_CLK_CTRL); + break; + case PWM_TYPE_O: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_EXT_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEO_L_MASK) | + (div_low << AST_PTCR_CLK_CTRL_TYPEO_L), + AST_PTCR_CLK_EXT_CTRL); + break; + } +} + +static void +ast_set_pwm_clock_unit(struct ast_pwm_controller_data *priv, u8 pwm_type, + u8 unit) +{ + switch (pwm_type) { + case PWM_TYPE_M: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEM_UNIT_MASK) | + (unit << AST_PTCR_CLK_CTRL_TYPEM_UNIT), + AST_PTCR_CLK_CTRL); + break; + case PWM_TYPE_N: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEN_UNIT_MASK) | + (unit << AST_PTCR_CLK_CTRL_TYPEN_UNIT), + AST_PTCR_CLK_CTRL); + break; + case PWM_TYPE_O: + ast_pwm_controller_write(priv, + (ast_pwm_controller_read(priv, AST_PTCR_CLK_EXT_CTRL) & + ~AST_PTCR_CLK_CTRL_TYPEO_UNIT_MASK) | + (unit << AST_PTCR_CLK_CTRL_TYPEO_UNIT), + AST_PTCR_CLK_EXT_CTRL); + break; + } +} + +static int +aspeed_pwm_controller_probe(struct platform_device *pdev) +{ + u32 buf[3]; + int err; + struct device_node *np; + struct resource *res; + u8 val; + struct ast_pwm_controller_data *priv; + + np = pdev->dev.of_node; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + priv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!priv->base) + return -ENOMEM; + + err = of_property_read_u8(np, "clock_enable", &val); + if (!err) { + ast_set_pwm_clock_enable(priv, val); + } else { + return err; + } + err = of_property_read_u8(np, "clock_source", &val); + if (!err) { + ast_set_pwm_clock_source(priv, val); + } else { + return err; + } + + err = of_property_read_u32_array(np, "typem_pwm_clock", buf, 3); + if (!err) { + ast_set_pwm_clock_division_l(priv, PWM_TYPE_M, buf[0]); + ast_set_pwm_clock_division_h(priv, PWM_TYPE_M, buf[1]); + ast_set_pwm_clock_unit(priv, PWM_TYPE_M, buf[2]); + } + + err = of_property_read_u32_array(np, "typen_pwm_clock", buf, 3); + if (!err) { + ast_set_pwm_clock_division_l(priv, PWM_TYPE_N, buf[0]); + ast_set_pwm_clock_division_h(priv, PWM_TYPE_N, buf[1]); + ast_set_pwm_clock_unit(priv, PWM_TYPE_N, buf[2]); + } + + err = of_property_read_u32_array(np, "typeo_pwm_clock", buf, 3); + if (!err) { + ast_set_pwm_clock_division_l(priv, PWM_TYPE_O, buf[0]); + ast_set_pwm_clock_division_h(priv, PWM_TYPE_O, buf[1]); + ast_set_pwm_clock_unit(priv, PWM_TYPE_O, buf[2]); + } + + return 0; +} + +static int +aspeed_pwm_controller_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id of_pwm_controller_match_table[] = { + { .compatible = "aspeed-pwm-controller", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_pwm_controller_match_table); + +static struct platform_driver aspeed_pwm_controller_driver = { + .probe = aspeed_pwm_controller_probe, + .remove = aspeed_pwm_controller_remove, + .driver = { + .name = "aspeed_pwm_controller", + .owner = THIS_MODULE, + .of_match_table = of_pwm_controller_match_table, + }, +}; + +module_platform_driver(aspeed_pwm_controller_driver); + +MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>"); +MODULE_DESCRIPTION("ASPEED PWM controller driver"); +MODULE_LICENSE("GPL");
Support to give all the common information required by all the PWM channels. Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu@google.com> --- .../bindings/hwmon/aspeed_pwm_controller.txt | 33 +++ drivers/hwmon/Kconfig | 5 + drivers/hwmon/Makefile | 2 +- drivers/hwmon/aspeed_pwm.h | 159 ++++++++++++++ drivers/hwmon/aspeed_pwm_controller.c | 237 +++++++++++++++++++++ 5 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/hwmon/aspeed_pwm_controller.txt create mode 100644 drivers/hwmon/aspeed_pwm.h create mode 100644 drivers/hwmon/aspeed_pwm_controller.c -- 2.8.0.rc3.226.g39d4020