[PATCH linux v1 2/3] drivers: hwmon: Drive support for ASPEED PWM device

Jaghathiswari Rankappagounder Natarajan jaghu at google.com
Fri Oct 28 10:40:21 AEDT 2016


Signed-off-by: Jaghathiswari Rankappagounder Natarajan <jaghu at google.com>
---
 .../bindings/hwmon/aspeed_pwm_device.txt           |  32 ++
 drivers/hwmon/Kconfig                              |   5 +
 drivers/hwmon/Makefile                             |   2 +-
 drivers/hwmon/aspeed_pwm_dev.c                     | 480 +++++++++++++++++++++
 4 files changed, 518 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/hwmon/aspeed_pwm_device.txt
 create mode 100644 drivers/hwmon/aspeed_pwm_dev.c

diff --git a/Documentation/devicetree/bindings/hwmon/aspeed_pwm_device.txt b/Documentation/devicetree/bindings/hwmon/aspeed_pwm_device.txt
new file mode 100644
index 0000000..96305d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/aspeed_pwm_device.txt
@@ -0,0 +1,32 @@
+Aspeed PWM device 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-dev".
+- pinctrl-names: A pinctrl state names "default" must be defined.
+- pinctrl-0 : Phandle referencing pin configuration of the aspeed pwm channel.
+- pwm_channel_enable : Indicates the PWM channel to enable. Values 0 through 7
+  indicate PWM channels A through H respectively.
+- pwm_type : Indicates the clock type for the PWM channel. value 0 is type M
+  PWM clock. value 1 is type N PWM clock. value 2 is type O PWM clock. Value
+  0 (type M ) is default. If any other type is preferred, say type N, then
+  typen_pwm_clock array of values have to be specified in pwm-controller node.
+- rising : Indicates the PWM channel rising point bit.
+- falling : Indicates the PWM channel falling point bit.
+
+Examples:
+
+pwm0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x1E786000 0x78>;
+		compatible = "aspeed-pwm-dev";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_pwm0_default>;
+		pwm_channel_enable = /bits/ 8 <0x00>;
+		pwm_type = /bits/ 8 <0x00>;
+		rising = /bits/ 8 <0x00>;
+		falling = /bits/ 8 <0x00>;
+};
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 59d6ea4..52bdf40 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1815,6 +1815,11 @@ config SENSORS_ULTRA45
 	  This driver provides support for the Ultra45 workstation environmental
 	  sensors.

+config ASPEED_PWM_DEVICE
+	tristate "Aspeed PWM device"
+	help
+	  This driver provides support for ASPEED PWM device.
+
 if ACPI

 comment "ACPI drivers"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 83156f8..b28ad1d 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -166,6 +166,6 @@ 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/
-
+obj-$(CONFIG_ASPEED_PWM_DEV)		+= aspeed_pwm_dev.o
 ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG

diff --git a/drivers/hwmon/aspeed_pwm_dev.c b/drivers/hwmon/aspeed_pwm_dev.c
new file mode 100644
index 0000000..476001e
--- /dev/null
+++ b/drivers/hwmon/aspeed_pwm_dev.c
@@ -0,0 +1,480 @@
+/*
+ * Aspeed PWM device 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/delay.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon.h>
+#include <linux/sysfs.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+
+#include "aspeed_pwm.h"
+
+struct ast_pwm_dev_data {
+	void __iomem *base;
+	u8 pwm_channel;
+	u8 pwm_type;
+	u8 pwm_value;
+};
+
+static inline void
+ast_pwm_dev_write(struct ast_pwm_dev_data *priv, u32 val, u32 reg)
+{
+	writel(val, priv->base + reg);
+}
+
+static inline u32
+ast_pwm_dev_read(struct ast_pwm_dev_data *priv, u32 reg)
+{
+	u32 val = readl(priv->base + reg);
+	return val;
+}
+
+static void
+ast_set_pwm_enable(struct ast_pwm_dev_data *priv, u8 pwm_ch, u8 enable)
+{
+	switch (pwm_ch) {
+	case PWMA:
+		if (enable)
+			ast_pwm_dev_write(priv,
+					ast_pwm_dev_read(priv, AST_PTCR_CTRL) |
+					AST_PTCR_CTRL_PWMA_EN, AST_PTCR_CTRL);
+		else
+			ast_pwm_dev_write(priv,
+					ast_pwm_dev_read(priv, AST_PTCR_CTRL) &
+					~AST_PTCR_CTRL_PWMA_EN,
+					AST_PTCR_CTRL);
+		break;
+	case PWMB:
+		if (enable)
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv, AST_PTCR_CTRL) |
+					 AST_PTCR_CTRL_PWMB_EN),
+					AST_PTCR_CTRL);
+		else
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv, AST_PTCR_CTRL) &
+					 ~AST_PTCR_CTRL_PWMB_EN),
+					AST_PTCR_CTRL);
+		break;
+	case PWMC:
+		if (enable)
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv, AST_PTCR_CTRL) |
+					 AST_PTCR_CTRL_PWMC_EN),
+					AST_PTCR_CTRL);
+		else
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv, AST_PTCR_CTRL) &
+					 ~AST_PTCR_CTRL_PWMC_EN),
+					AST_PTCR_CTRL);
+		break;
+	case PWMD:
+		if (enable)
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv, AST_PTCR_CTRL) |
+					 AST_PTCR_CTRL_PWMD_EN),
+					AST_PTCR_CTRL);
+		else
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv, AST_PTCR_CTRL) &
+					 ~AST_PTCR_CTRL_PWMD_EN),
+					AST_PTCR_CTRL);
+		break;
+	case PWME:
+		if (enable)
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv,
+					AST_PTCR_CTRL_EXT) |
+					AST_PTCR_CTRL_PWME_EN),
+					AST_PTCR_CTRL_EXT);
+		else
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv,
+					  AST_PTCR_CTRL_EXT) &
+					 ~AST_PTCR_CTRL_PWME_EN),
+					AST_PTCR_CTRL_EXT);
+		break;
+	case PWMF:
+		if (enable)
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv,
+							  AST_PTCR_CTRL_EXT) |
+						 AST_PTCR_CTRL_PWMF_EN),
+						AST_PTCR_CTRL_EXT);
+		else
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv,
+					AST_PTCR_CTRL_EXT) &
+					 ~AST_PTCR_CTRL_PWMF_EN),
+					AST_PTCR_CTRL_EXT);
+		break;
+	case PWMG:
+		if (enable)
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv,
+					AST_PTCR_CTRL_EXT) |
+					AST_PTCR_CTRL_PWMG_EN),
+					AST_PTCR_CTRL_EXT);
+		else
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv,
+					AST_PTCR_CTRL_EXT) &
+					 ~AST_PTCR_CTRL_PWMG_EN),
+					AST_PTCR_CTRL_EXT);
+		break;
+	case PWMH:
+		if (enable)
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv,
+					AST_PTCR_CTRL_EXT) |
+					 AST_PTCR_CTRL_PWMH_EN),
+					AST_PTCR_CTRL_EXT);
+		else
+			ast_pwm_dev_write(priv,
+					(ast_pwm_dev_read(priv,
+					AST_PTCR_CTRL_EXT) &
+					 ~AST_PTCR_CTRL_PWMH_EN),
+					AST_PTCR_CTRL_EXT);
+		break;
+	}
+}
+
+static void
+ast_set_pwm_type(struct ast_pwm_dev_data *priv, u8 pwm_ch, u8 type)
+{
+	u32 tmp1, tmp2;
+
+	tmp1 = ast_pwm_dev_read(priv, AST_PTCR_CTRL);
+	tmp2 = ast_pwm_dev_read(priv, AST_PTCR_CTRL_EXT);
+
+	switch (pwm_ch) {
+	case PWMA:
+		tmp1 &= ~AST_PTCR_CTRL_SET_PWMA_TYPE_MASK;
+		tmp1 |= AST_PTCR_CTRL_SET_PWMA_TYPE(type);
+		ast_pwm_dev_write(priv, tmp1, AST_PTCR_CTRL);
+		break;
+	case PWMB:
+		tmp1 &= ~AST_PTCR_CTRL_SET_PWMB_TYPE_MASK;
+		tmp1 |= AST_PTCR_CTRL_SET_PWMB_TYPE(type);
+		ast_pwm_dev_write(priv, tmp1, AST_PTCR_CTRL);
+		break;
+	case PWMC:
+		tmp1 &= ~AST_PTCR_CTRL_SET_PWMC_TYPE_MASK;
+		tmp1 |= AST_PTCR_CTRL_SET_PWMC_TYPE(type);
+		ast_pwm_dev_write(priv, tmp1, AST_PTCR_CTRL);
+		break;
+	case PWMD:
+		tmp1 &= ~AST_PTCR_CTRL_SET_PWMD_TYPE_MASK;
+		tmp1 |= AST_PTCR_CTRL_SET_PWMD_TYPE(type);
+		ast_pwm_dev_write(priv, tmp1, AST_PTCR_CTRL);
+		break;
+	case PWME:
+		tmp2 &= ~AST_PTCR_CTRL_SET_PWME_TYPE_MASK;
+		tmp2 |= AST_PTCR_CTRL_SET_PWME_TYPE(type);
+		ast_pwm_dev_write(priv, tmp2, AST_PTCR_CTRL_EXT);
+		break;
+	case PWMF:
+		tmp2 &= ~AST_PTCR_CTRL_SET_PWMF_TYPE_MASK;
+		tmp2 |= AST_PTCR_CTRL_SET_PWMF_TYPE(type);
+		ast_pwm_dev_write(priv, tmp2, AST_PTCR_CTRL_EXT);
+		break;
+	case PWMG:
+		tmp2 &= ~AST_PTCR_CTRL_SET_PWMG_TYPE_MASK;
+		tmp2 |= AST_PTCR_CTRL_SET_PWMG_TYPE(type);
+		ast_pwm_dev_write(priv, tmp2, AST_PTCR_CTRL_EXT);
+		break;
+	case PWMH:
+		tmp2 &= ~AST_PTCR_CTRL_SET_PWMH_TYPE_MASK;
+		tmp2 |= AST_PTCR_CTRL_SET_PWMH_TYPE(type);
+		ast_pwm_dev_write(priv, tmp2, AST_PTCR_CTRL_EXT);
+		break;
+	}
+}
+
+static void
+ast_set_pwm_duty_rising(struct ast_pwm_dev_data *priv, u8 pwm_ch, u8 rising)
+{
+	u32 tmp = 0;
+
+	switch (pwm_ch) {
+	case PWMA:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY0_CTRL);
+		tmp &= ~DUTY_CTRL_PWM1_RISE_POINT_MASK;
+		tmp |= rising;
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY0_CTRL);
+		break;
+	case PWMB:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY0_CTRL);
+		tmp &= ~DUTY_CTRL_PWM2_RISE_POINT_MASK;
+		tmp |= (rising << DUTY_CTRL_PWM2_RISE_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY0_CTRL);
+		break;
+	case PWMC:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY1_CTRL);
+		tmp &= ~DUTY_CTRL_PWM1_RISE_POINT_MASK;
+		tmp |= rising;
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY1_CTRL);
+		break;
+	case PWMD:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY1_CTRL);
+		tmp &= ~DUTY_CTRL_PWM2_RISE_POINT_MASK;
+		tmp |= (rising << DUTY_CTRL_PWM2_RISE_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY1_CTRL);
+		break;
+	case PWME:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY2_CTRL);
+		tmp &= ~DUTY_CTRL_PWM1_RISE_POINT_MASK;
+		tmp |= rising;
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY2_CTRL);
+		break;
+	case PWMF:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY2_CTRL);
+		tmp &= ~DUTY_CTRL_PWM2_RISE_POINT_MASK;
+		tmp |= (rising << DUTY_CTRL_PWM2_RISE_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY2_CTRL);
+		break;
+	case PWMG:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY3_CTRL);
+		tmp &= ~DUTY_CTRL_PWM1_RISE_POINT_MASK;
+		tmp |= rising;
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY3_CTRL);
+		break;
+	case PWMH:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY3_CTRL);
+		tmp &= ~DUTY_CTRL_PWM2_RISE_POINT_MASK;
+		tmp |= (rising << DUTY_CTRL_PWM2_RISE_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY3_CTRL);
+		break;
+	}
+}
+
+static void
+ast_set_pwm_duty_falling(struct ast_pwm_dev_data *priv, u8 pwm_ch, u8 falling)
+{
+	u32 tmp = 0;
+
+	switch (pwm_ch) {
+	case PWMA:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY0_CTRL);
+		tmp &= ~DUTY_CTRL_PWM1_FALL_POINT_MASK;
+		tmp |= (falling << DUTY_CTRL_PWM1_FALL_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY0_CTRL);
+		break;
+	case PWMB:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY0_CTRL);
+		tmp &= ~DUTY_CTRL_PWM2_FALL_POINT_MASK;
+		tmp |= (falling << DUTY_CTRL_PWM2_FALL_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY0_CTRL);
+		break;
+	case PWMC:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY1_CTRL);
+		tmp &= ~DUTY_CTRL_PWM1_FALL_POINT_MASK;
+		tmp |= (falling << DUTY_CTRL_PWM1_FALL_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY1_CTRL);
+		break;
+	case PWMD:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY1_CTRL);
+		tmp &= ~DUTY_CTRL_PWM2_FALL_POINT_MASK;
+		tmp |= (falling << DUTY_CTRL_PWM2_FALL_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY1_CTRL);
+		break;
+	case PWME:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY2_CTRL);
+		tmp &= ~DUTY_CTRL_PWM1_FALL_POINT_MASK;
+		tmp |= (falling << DUTY_CTRL_PWM1_FALL_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY2_CTRL);
+		break;
+	case PWMF:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY2_CTRL);
+		tmp &= ~DUTY_CTRL_PWM2_FALL_POINT_MASK;
+		tmp |= (falling << DUTY_CTRL_PWM2_FALL_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY2_CTRL);
+		break;
+	case PWMG:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY3_CTRL);
+		tmp &= ~DUTY_CTRL_PWM1_FALL_POINT_MASK;
+		tmp |= (falling << DUTY_CTRL_PWM1_FALL_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY3_CTRL);
+		break;
+	case PWMH:
+		tmp = ast_pwm_dev_read(priv, AST_PTCR_DUTY3_CTRL);
+		tmp &= ~DUTY_CTRL_PWM2_FALL_POINT_MASK;
+		tmp |= (falling << DUTY_CTRL_PWM2_FALL_POINT);
+		ast_pwm_dev_write(priv, tmp, AST_PTCR_DUTY3_CTRL);
+		break;
+	}
+}
+
+static u8
+ast_get_pwm_clock_unit(struct ast_pwm_dev_data *priv, u8 pwm_type)
+{
+	u8 tmp = 0;
+
+	switch (pwm_type) {
+	case PWM_TYPE_M:
+		tmp = (ast_pwm_dev_read(priv, AST_PTCR_CLK_CTRL) &
+			AST_PTCR_CLK_CTRL_TYPEM_UNIT_MASK) >>
+			AST_PTCR_CLK_CTRL_TYPEM_UNIT;
+		break;
+	case PWM_TYPE_N:
+		tmp = (ast_pwm_dev_read(priv, AST_PTCR_CLK_CTRL) &
+			AST_PTCR_CLK_CTRL_TYPEN_UNIT_MASK) >>
+			 AST_PTCR_CLK_CTRL_TYPEN_UNIT;
+		break;
+	case PWM_TYPE_O:
+		tmp = (ast_pwm_dev_read(priv, AST_PTCR_CLK_EXT_CTRL) &
+			AST_PTCR_CLK_CTRL_TYPEO_UNIT_MASK) >>
+			AST_PTCR_CLK_CTRL_TYPEO_UNIT;
+		break;
+	}
+	return tmp;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct ast_pwm_dev_data *priv = dev_get_drvdata(dev);
+	u8 period;
+	u8 val;
+	u8 duty;
+	int ret;
+
+	period = ast_get_pwm_clock_unit(priv, priv->pwm_type);
+	period += 1;
+	ret = kstrtou8(buf, 10, &val);
+	if (ret)
+		return -EINVAL;
+
+	duty = (val * period) / 100;
+	if (duty == 0) {
+		ast_set_pwm_enable(priv, priv->pwm_channel, 0);
+	} else {
+		if (duty == period) {
+			duty = 0;
+		}
+		priv->pwm_value = val;
+		ast_set_pwm_duty_rising(priv, priv->pwm_channel, 0);
+		ast_set_pwm_duty_falling(priv, priv->pwm_channel, duty);
+		ast_set_pwm_enable(priv, priv->pwm_channel, 1);
+	}
+	return count;
+}
+
+static ssize_t show_pwm(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct ast_pwm_dev_data *priv = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", priv->pwm_value);
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
+
+static struct attribute *pwm_dev_attrs[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	NULL,
+};
+
+ATTRIBUTE_GROUPS(pwm_dev);
+
+static int aspeed_pwm_dev_probe(struct platform_device *pdev)
+{
+	struct device *hwmon;
+	struct device_node *np;
+	struct ast_pwm_dev_data *priv;
+	struct resource *res;
+	u8 val;
+	int err = 0;
+
+	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;
+	}
+
+	platform_set_drvdata(pdev, priv);
+
+	hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwm_dev",
+		priv, pwm_dev_groups);
+	if (IS_ERR(hwmon)) {
+		dev_err(&pdev->dev, "Failed to register hwmon device\n");
+		return PTR_ERR(hwmon);
+	}
+
+	err = of_property_read_u8(np, "pwm_channel_enable", &val);
+	if (!err) {
+		priv->pwm_channel = val;
+		ast_set_pwm_enable(priv, priv->pwm_channel, 1);
+	} else {
+		return err;
+	}
+
+	err = of_property_read_u8(np, "pwm_type", &val);
+	if (!err) {
+		priv->pwm_type = val;
+		ast_set_pwm_type(priv, priv->pwm_channel, val);
+	} else {
+		return err;
+	}
+
+	err = of_property_read_u8(np, "rising", &val);
+	if (!err) {
+		ast_set_pwm_duty_rising(priv, priv->pwm_channel, val);
+	} else {
+		return err;
+	}
+
+	err = of_property_read_u8(np, "falling", &val);
+	if (!err) {
+		ast_set_pwm_duty_falling(priv, priv->pwm_channel, val);
+	} else {
+		return err;
+	}
+	return 0;
+
+}
+
+static int aspeed_pwm_dev_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id of_pwm_dev_match_table[] = {
+	{ .compatible = "aspeed-pwm-dev", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_pwm_dev_match_table);
+
+static struct platform_driver aspeed_pwm_dev_driver = {
+	.probe		= aspeed_pwm_dev_probe,
+	.remove		= aspeed_pwm_dev_remove,
+	.driver		= {
+		.name	= "aspeed_pwm_dev",
+		.owner	= THIS_MODULE,
+		.of_match_table	= of_pwm_dev_match_table,
+	},
+};
+
+module_platform_driver(aspeed_pwm_dev_driver);
+
+MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu at google.com>");
+MODULE_DESCRIPTION("ASPEED PWM dev driver");
+MODULE_LICENSE("GPL");
--
2.8.0.rc3.226.g39d4020



More information about the openbmc mailing list