hwmon: Add NPCM7xx PWM driver support
Tomer Maimon
maintainercover hwmon: Add NPCM7xx PWM driver support
This patch set adds Pulse Width Modulation (PWM) support for the Nuvoton NPCM7xx Baseboard Management Controller (BMC).
The NPCM7xx PWM controller can support 8 PWM output ports.
The hwmon driver provides sysfs entries through which the user can configure and get the duty cycle between 0 (disable the specific PWM) to 255 of particular PWM output port.
The NPCM7xx PWM driver tested on NPCM750 evaluation board.
Tomer Maimon (2):
dt-binding: hwmon: Add NPCM7xx PWM documentation
hwmon: npcm-pwm: add NPCM7xx PWM driver
.../devicetree/bindings/hwmon/npcm7xx-pwm.txt | 25 ++ drivers/hwmon/Kconfig | 6 + drivers/hwmon/Makefile | 1 + drivers/hwmon/npcm7xx-pwm.c | 363 +++++++++++++++++++++ 4 files changed, 395 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt create mode 100644 drivers/hwmon/npcm7xx-pwm.c
Signature · 1 line
2.14.1
Tomer Maimon
maintainerPATCH 1/2 dt-binding: hwmon: Add NPCM7xx PWM documentation
Added device tree binding documentation for Nuvoton BMC NPCM7xx Pulse Width Modulation (PWM) controller.
--- .../devicetree/bindings/hwmon/npcm7xx-pwm.txt | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt
Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt new file +25 -0
@@ -0,0 +1,25 @@ +Nuvoton NPCM7xx Pulse-width modulation (PWM) controller device driver + +The NPCM7xx has two identical PWM controller modules, +Each module has four PWM controller outputs. +NPCM7xx PWM controller module 0 outputs PWM0-3 and NPCM7xx PWM controller +module 1 outputs PWM4-7. + +Required properties: +- compatible : "nuvoton,npcm750-pwm" for Poleg NPCM7XX. +- reg : Offset and length of the registers set for the device. +- clocks : phandle of pwm reference clock. +- pinctrl-names : a pinctrl state named "default" must be defined. +- pinctrl-0 : phandle referencing pin configuration of the PWM ports. + +pwm:pwm@f0103000 { + compatible = "nuvoton,npcm750-pwm"; + reg = <0xf0103000 0x50 + 0xf0104000 0x50>; + clocks = <&clk NPCM7XX_CLK_APB3>; + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_pins &pwm1_pins + &pwm2_pins &pwm3_pins + &pwm4_pins &pwm5_pins + &pwm6_pins &pwm7_pins>; +};
Signature · 1 line
2.14.1
Guenter Roeck
maintainerRe: [PATCH v1 1/2] dt-binding: hwmon: Add NPCM7xx PWM documentation
Quoted 3 lines · Tomer Maimon
Added device tree binding documentation for Nuvoton BMC NPCM7xx Pulse Width Modulation (PWM) controller.
As mentioned in the other commit, this should be a pwm driver, not a hwmon driver.
Guenter
Quoted 44 lines
Signed-off-by Tomer Maimon <[email protected]>--- .../devicetree/bindings/hwmon/npcm7xx-pwm.txt | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/npcm7xx-pwm.txtDocumentation/devicetree/bindings/hwmon/npcm7xx-pwm.txt new file +25
-0@@ -0,0 +1,25 @@ +Nuvoton NPCM7xx Pulse-width modulation (PWM) controller device driver + +The NPCM7xx has two identical PWM controller modules, +Each module has four PWM controller outputs. +NPCM7xx PWM controller module 0 outputs PWM0-3 and NPCM7xx PWM controller +module 1 outputs PWM4-7. + +Required properties: +- compatible : "nuvoton,npcm750-pwm" for Poleg NPCM7XX. +- reg : Offset and length of the registers set for the device. +- clocks : phandle of pwm reference clock. +- pinctrl-names : a pinctrl state named "default" must be defined. +- pinctrl-0 : phandle referencing pin configuration of the PWM ports. + +pwm:pwm@f0103000 { + compatible = "nuvoton,npcm750-pwm"; + reg = <0xf0103000 0x50 + 0xf0104000 0x50>; + clocks = <&clk NPCM7XX_CLK_APB3>; + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_pins &pwm1_pins + &pwm2_pins &pwm3_pins + &pwm4_pins &pwm5_pins + &pwm6_pins &pwm7_pins>; +};Signature · 6 lines
2.14.1 -- To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Tomer Maimon
maintainerPATCH 2/2 hwmon: npcm-pwm: add NPCM7xx PWM driver
In reply to Tomer MaimonAdd Nuvoton BMC NPCM7xx Pulse Width Modulation (PWM) driver.
The Nuvoton BMC NPCM7xx has two identical PWM controller modules, each module has four PWM controller outputs.
--- drivers/hwmon/Kconfig | 6 + drivers/hwmon/Makefile | 1 + drivers/hwmon/npcm7xx-pwm.c | 363 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 370 insertions(+) create mode 100644 drivers/hwmon/npcm7xx-pwm.c
drivers/hwmon/Kconfig +6 -0
@@ -1891,6 +1891,12 @@ config SENSORS_XGENE If you say yes here you get support for the temperature and power sensors for APM X-Gene SoC. +config SENSORS_NPCM7XX + tristate "Nuvoton NPCM7XX PWM driver" + help + This driver provides support for Nuvoton NPCM7XX PWM + controller. + if ACPI comment "ACPI drivers"
drivers/hwmon/Makefile +1 -0
@@ -174,6 +174,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o +obj-$(CONFIG_SENSORS_NPCM7XX) += npcm7xx-pwm.o obj-$(CONFIG_PMBUS) += pmbus/
drivers/hwmon/npcm7xx-pwm.c new file +363 -0
363 lines not on this page · raw message
Signature · 1 line
2.14.1
Guenter Roeck
maintainerRe: [PATCH v1 2/2] hwmon: npcm-pwm: add NPCM7xx PWM driver
Quoted 5 lines · Tomer Maimon
Add Nuvoton BMC NPCM7xx Pulse Width Modulation (PWM) driver.
The Nuvoton BMC NPCM7xx has two identical PWM controller modules, each module has four PWM controller outputs.
I don't see it guaranteed that all future NPCM7xx devices will be PWM controllers, much less that they will be compatible to the chip really supported here. NPCM750, I presume ? I would suggest name the driver accordingly.
As a generic pwm driver, not specifically tied to a fan controller, this driver does not belong into hwmon. It should be added to the pwm subsystem. Copying the maintainer and mailing list.
If the pwm chip is used to control fans, the existing pwm-fan driver can then be used to create the necessary mapping from pwm controls to fans.
Guenter
Quoted 413 lines
Signed-off-by Tomer Maimon <[email protected]>--- drivers/hwmon/Kconfig | 6 + drivers/hwmon/Makefile | 1 + drivers/hwmon/npcm7xx-pwm.c | 363 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 370 insertions(+) create mode 100644 drivers/hwmon/npcm7xx-pwm.cdrivers/hwmon/Kconfig +6
-0@@ -1891,6 +1891,12 @@ config SENSORS_XGENE If you say yes here you get support for the temperature and power sensors for APM X-Gene SoC. +config SENSORS_NPCM7XX + tristate "Nuvoton NPCM7XX PWM driver" + help + This driver provides support for Nuvoton NPCM7XX PWM + controller. + if ACPI comment "ACPI drivers"drivers/hwmon/Makefile +1
-0@@ -174,6 +174,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o +obj-$(CONFIG_SENSORS_NPCM7XX) += npcm7xx-pwm.o obj-$(CONFIG_PMBUS) += pmbus/drivers/hwmon/npcm7xx-pwm.c new file +363
-0@@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2014-2018 Nuvoton Technology corporation. + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/sysfs.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> + +/* NPCM7XX PWM port base address */ +#define NPCM7XX_PWM_REG_PR 0x0 +#define NPCM7XX_PWM_REG_CSR 0x4 +#define NPCM7XX_PWM_REG_CR 0x8 +#define NPCM7XX_PWM_REG_CNRx (PORT ) (0xC + (12 * PORT)) +#define NPCM7XX_PWM_REG_CMRx (PORT ) (0x10 + (12 * PORT)) +#define NPCM7XX_PWM_REG_PDRx (PORT ) (0x14 + (12 * PORT)) +#define NPCM7XX_PWM_REG_PIER 0x3C +#define NPCM7XX_PWM_REG_PIIR 0x40 + +#define NPCM7XX_PWM_CTRL_CH0_MODE_BIT BIT(3) +#define NPCM7XX_PWM_CTRL_CH1_MODE_BIT BIT(11) +#define NPCM7XX_PWM_CTRL_CH2_MODE_BIT BIT(15) +#define NPCM7XX_PWM_CTRL_CH3_MODE_BIT BIT(19) + +#define NPCM7XX_PWM_CTRL_CH0_INV_BIT BIT(2) +#define NPCM7XX_PWM_CTRL_CH1_INV_BIT BIT(10) +#define NPCM7XX_PWM_CTRL_CH2_INV_BIT BIT(14) +#define NPCM7XX_PWM_CTRL_CH3_INV_BIT BIT(18) + +#define NPCM7XX_PWM_CTRL_CH0_EN_BIT BIT(0) +#define NPCM7XX_PWM_CTRL_CH1_EN_BIT BIT(8) +#define NPCM7XX_PWM_CTRL_CH2_EN_BIT BIT(12) +#define NPCM7XX_PWM_CTRL_CH3_EN_BIT BIT(16) + +/* Define the maximum PWM channel number */ +#define NPCM7XX_PWM_MAX_CHN_NUM 8 +#define NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE 4 +#define NPCM7XX_PWM_MAX_MODULES 2 + +/* Define the Counter Register, value = 100 for match 100% */ +#define NPCM7XX_PWM_COUNTER_DEFALUT_NUM 255 +#define NPCM7XX_PWM_COMPARATOR_DEFALUT_NUM 127 + +#define NPCM7XX_PWM_COMPARATOR_MAX 255 + + +/* default all PWM channels PRESCALE2 = 1 */ +#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH0 0x4 +#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH1 0x40 +#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH2 0x400 +#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH3 0x4000 + +#define PWM_OUTPUT_FREQ_25KHZ 25000 +#define PWN_CNT_DEFAULT 256 +#define MIN_PRESCALE1 2 +#define NPCM7XX_PWM_PRESCALE_SHIFT_CH01 8 + +#define NPCM7XX_PWM_PRESCALE2_DEFALUT (NPCM7XX_PWM_PRESCALE2_DEFALUT_CH0 | \ + NPCM7XX_PWM_PRESCALE2_DEFALUT_CH1 | \ + NPCM7XX_PWM_PRESCALE2_DEFALUT_CH2 | \ + NPCM7XX_PWM_PRESCALE2_DEFALUT_CH3) + +#define NPCM7XX_PWM_CTRL_MODE_DEFALUT (NPCM7XX_PWM_CTRL_CH0_MODE_BIT | \ + NPCM7XX_PWM_CTRL_CH1_MODE_BIT | \ + NPCM7XX_PWM_CTRL_CH2_MODE_BIT | \ + NPCM7XX_PWM_CTRL_CH3_MODE_BIT) + +#define NPCM7XX_PWM_CTRL_EN_DEFALUT (NPCM7XX_PWM_CTRL_CH0_EN_BIT | \ + NPCM7XX_PWM_CTRL_CH1_EN_BIT | \ + NPCM7XX_PWM_CTRL_CH2_EN_BIT | \ + NPCM7XX_PWM_CTRL_CH3_EN_BIT) + +struct npcm7xx_pwm_data { +unsigned long clk_freq; +void __iomem *pwm_base[NPCM7XX_PWM_MAX_MODULES ]; +struct mutex npcm7xx_pwm_lock[NPCM7XX_PWM_MAX_CHN_NUM ]; +}; + +static const struct of_device_id pwm_dt_id[]; + +static int npcm7xx_pwm_config_set (struct npcm7xx_pwm_data *data,int channel, +u16 val) +{ +u32 PWMChannel = (channel %NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE ); +u32 n_module = (channel /NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE ); +u32 u32TmpBuf =0 , ctrl_en_bit; + +/* +* Config PWM Comparator register for setting duty cycle +*/ +if (val <0 || val >NPCM7XX_PWM_COMPARATOR_MAX ) +return -EINVAL ; + +/* write new CMR value */ +iowrite32 (val, data->pwm_base[n_module] + +NPCM7XX_PWM_REG_CMRx (PWMChannel)); + + u32TmpBuf =ioread32 (data->pwm_base[n_module] +NPCM7XX_PWM_REG_CR ); + +switch (PWMChannel) { +case 0 : + ctrl_en_bit =NPCM7XX_PWM_CTRL_CH0_EN_BIT ; +break ; +case 1 : + ctrl_en_bit =NPCM7XX_PWM_CTRL_CH1_EN_BIT ; +break ; +case 2 : + ctrl_en_bit =NPCM7XX_PWM_CTRL_CH2_EN_BIT ; +break ; +case 3 : + ctrl_en_bit =NPCM7XX_PWM_CTRL_CH3_EN_BIT ; +break ; +default : +return -ENODEV ; + } + +if (val ==0 ) +/* Disable PWM */ + u32TmpBuf &= ~(ctrl_en_bit); +else +/* Enable PWM */ + u32TmpBuf |= ctrl_en_bit; + +mutex_lock (&data->npcm7xx_pwm_lock[n_module]); +iowrite32 (u32TmpBuf, data->pwm_base[n_module] +NPCM7XX_PWM_REG_CR ); +mutex_unlock (&data->npcm7xx_pwm_lock[n_module]); + +return 0 ; +} + +static int npcm7xx_read_pwm (struct device *dev,u32 attr,int channel, +long *val) +{ +struct npcm7xx_pwm_data *data =dev_get_drvdata (dev); +u32 PWMChannel = (channel %NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE ); +u32 n_module = (channel /NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE ); + +if (IS_ERR (data)) +return PTR_ERR (data); + +switch (attr) { +case hwmon_pwm_input: + *val = (long )ioread32 (data->pwm_base[n_module] + +NPCM7XX_PWM_REG_CMRx (PWMChannel)); +return 0 ; +default : +return -EOPNOTSUPP ; + } +} + +static int npcm7xx_write_pwm (struct device *dev,u32 attr,int channel, +long val) +{ +struct npcm7xx_pwm_data *data =dev_get_drvdata (dev); +int err =0 ; + +switch (attr) { +case hwmon_pwm_input: + err =npcm7xx_pwm_config_set (data, channel, (u16 )val); +break ; +default : + err = -EOPNOTSUPP ; +break ; + } + +return err; +} + +static umode_t npcm7xx_pwm_is_visible (const void *_data,u32 attr,int channel) +{ +switch (attr) { +case hwmon_pwm_input: +return 0644 ; +default : +return 0 ; + } +} + +static int npcm7xx_read (struct device *dev,enum hwmon_sensor_types type, +u32 attr,int channel,long *val) +{ +switch (type) { +case hwmon_pwm: +return npcm7xx_read_pwm (dev, attr, channel, val); +default : +return -EOPNOTSUPP ; + } +} + +static int npcm7xx_write (struct device *dev,enum hwmon_sensor_types type, +u32 attr,int channel,long val) +{ +switch (type) { +case hwmon_pwm: +return npcm7xx_write_pwm (dev, attr, channel, val); +default : +return -EOPNOTSUPP ; + } +} + +static umode_t npcm7xx_is_visible (const void *data, +enum hwmon_sensor_types type, +u32 attr,int channel) +{ +switch (type) { +case hwmon_pwm: +return npcm7xx_pwm_is_visible (data, attr, channel); +default : +return 0 ; + } +} + +static const u32 npcm7xx_pwm_config[] = { +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +0 +}; + +static const struct hwmon_channel_info npcm7xx_pwm = { + .type = hwmon_pwm, + .config = npcm7xx_pwm_config, +}; + +static const struct hwmon_channel_info *npcm7xx_info[] = { + &npcm7xx_pwm, +NULL +}; + +static const struct hwmon_ops npcm7xx_hwmon_ops = { + .is_visible = npcm7xx_is_visible, + .read = npcm7xx_read, + .write = npcm7xx_write, +}; + +static const struct hwmon_chip_info npcm7xx_chip_info = { + .ops = &npcm7xx_hwmon_ops, + .info = npcm7xx_info, +}; + +static int npcm7xx_pwm_probe (struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct npcm7xx_pwm_data *data; +struct resource res[NPCM7XX_PWM_MAX_MODULES ]; +struct device *hwmon; +struct clk *clk; +int m, ch, res_cnt, ret; +u32 Prescale_val, output_freq; + + data =devm_kzalloc (dev,sizeof (*data),GFP_KERNEL ); +if (!data) +return -ENOMEM ; + +for (res_cnt =0 ; res_cnt <NPCM7XX_PWM_MAX_MODULES ; res_cnt++) { + ret =of_address_to_resource (dev->of_node, res_cnt, + &res[res_cnt]); +if (ret) { +pr_err ("PWM of_address_to_resource fail ret %d\n" , + ret); +return -EINVAL ; + } + + data->pwm_base[res_cnt] = +devm_ioremap_resource (dev, &(res[res_cnt])); +pr_debug ("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n" , + res_cnt, (u32 )data->pwm_base[res_cnt], + res[res_cnt].start,resource_size (&(res[res_cnt]))); + +if (!data->pwm_base[res_cnt]) { +pr_err ("pwm probe failed: can't read pwm base address for resource %d.\n" , + res_cnt); +return -ENOMEM ; + } + +mutex_init (&data->npcm7xx_pwm_lock[res_cnt]); + } + + clk =devm_clk_get (dev,NULL ); +if (IS_ERR (clk)) +return -ENODEV ; + + data->clk_freq =clk_get_rate (clk); + +/* Adjust NPCM7xx PWMs output frequency to ~25Khz */ + output_freq = data->clk_freq /PWN_CNT_DEFAULT ; + Prescale_val =DIV_ROUND_CLOSEST (output_freq,PWM_OUTPUT_FREQ_25KHZ ); + +/* If Prescale_val = 0, then the prescale output clock is stopped */ +if (Prescale_val <MIN_PRESCALE1 ) + Prescale_val =MIN_PRESCALE1 ; +/* +* Prescale_val need to decrement in one because in the PWM Prescale +* register the Prescale value increment by one +*/ + Prescale_val--; + +/* Setting PWM Prescale Register value register to both modules */ + Prescale_val |= (Prescale_val <<NPCM7XX_PWM_PRESCALE_SHIFT_CH01 ); + +for (m =0 ; m <NPCM7XX_PWM_MAX_MODULES ; m++) { +iowrite32 (Prescale_val, + data->pwm_base[m] +NPCM7XX_PWM_REG_PR ); +iowrite32 (NPCM7XX_PWM_PRESCALE2_DEFALUT , + data->pwm_base[m] +NPCM7XX_PWM_REG_CSR ); +iowrite32 (NPCM7XX_PWM_CTRL_MODE_DEFALUT , + data->pwm_base[m] +NPCM7XX_PWM_REG_CR ); + +for (ch =0 ; ch <NPCM7XX_PWM_MAX_CHN_NUM ; ch++) { +iowrite32 (NPCM7XX_PWM_COUNTER_DEFALUT_NUM , + data->pwm_base[m] +NPCM7XX_PWM_REG_CNRx (ch)); +iowrite32 (NPCM7XX_PWM_COMPARATOR_DEFALUT_NUM , + data->pwm_base[m] +NPCM7XX_PWM_REG_CMRx (ch)); + } + +iowrite32 (NPCM7XX_PWM_CTRL_MODE_DEFALUT | +NPCM7XX_PWM_CTRL_EN_DEFALUT , + data->pwm_base[m] +NPCM7XX_PWM_REG_CR ); + } + + hwmon =devm_hwmon_device_register_with_info (dev,"npcm7xx_pwm" , data, + &npcm7xx_chip_info,NULL ); + +if (IS_ERR (hwmon)) { +pr_err ("PWM Driver failed - devm_hwmon_device_register_with_groups failed\n" ); +return PTR_ERR (hwmon); + } + +pr_info ("NPCM7XX PWM Driver probed, PWM output Freq %dHz\n" , + output_freq / ((Prescale_val &0xf ) +1 )); + +return 0 ; +} + +static const struct of_device_id of_pwm_match_table[] = { + { .compatible ="nuvoton,npcm750-pwm" , }, + {}, +}; +MODULE_DEVICE_TABLE (of, of_pwm_match_table); + +static struct platform_driver npcm7xx_pwm_driver = { + .probe = npcm7xx_pwm_probe, + .driver = { + .name ="npcm7xx_pwm" , + .of_match_table = of_pwm_match_table, + }, +}; + +module_platform_driver (npcm7xx_pwm_driver); + +MODULE_DESCRIPTION ("Nuvoton NPCM7XX PWM Driver" ); +MODULE_AUTHOR ("Tomer Maimon <[email protected]>" ); +MODULE_LICENSE ("GPL v2" );Signature · 6 lines
2.14.1 -- To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Tomer Maimon
maintainerRe: [PATCH v1 2/2] hwmon: npcm-pwm: add NPCM7xx PWM driver
Hi Guenter,
Thanks for your prompt reply!
Quoted 10 lines · Guenter Roeck
Quoted 5 lines · Tomer Maimon
Add Nuvoton BMC NPCM7xx Pulse Width Modulation (PWM) driver.
The Nuvoton BMC NPCM7xx has two identical PWM controller modules, each module has four PWM controller outputs.
I don't see it guaranteed that all future NPCM7xx devices will be PWM controllers, much less that they will be compatible to the chip really
Actually all NPCM7xx family have PWM and FAN modules support,
Quoted 3 lines
supported here. NPCM750, I presume ? I would suggest name the driver accordingly.
The compatible name can not be a family name like nuvoton,npcm7xx-pwm, only a specific chip name. (in our case the NPCM750 is the full modules SOC) still you think i should change the driver name? (note: all of our NPCM7xx unique modules drivers are named npcm7xx-*.c or *-npcm7xx.c)
Quoted 5 lines
As a generic pwm driver, not specifically tied to a fan controller, this driver does not belong into hwmon. It should be added to the pwm subsystem. Copying the maintainer and mailing list.
In the NPCM7xx we have PWM and FAN controller modules, usually in the
aspect of our BMC clients the two module
are used together to control the fans.
But because in the NPCM7xx the PWM and the FAN controller are separate modules we
thought to do two separate drivers in the hwmon
is it possible? or you think it is better to do one hwmon driver for the PWM and the FAN controller.
note that we were going to submit soon also the FAN controller driver under hwmon.
Quoted 5 lines
If the pwm chip is used to control fans, the existing pwm-fan driver can then be used to create the necessary mapping from pwm controls to fans.
Guenter
Thanks,
Tomer
Quoted 437 lines
Quoted 6 lines
Signed-off-by Tomer Maimon <[email protected]>--- drivers/hwmon/Kconfig | 6 + drivers/hwmon/Makefile | 1 + drivers/hwmon/npcm7xx-pwm.c | 363 ++++++++++++++++++++++++++++++++++++++++++++
Quoted 91 lines
3 files changed, 370 insertions(+) create mode 100644 drivers/hwmon/npcm7xx-pwm.cdrivers/hwmon/Kconfig +6
-0@@ -1891,6 +1891,12 @@ config SENSORS_XGENE If you say yes here you get support for the temperature and power sensors for APM X-Gene SoC. +config SENSORS_NPCM7XX + tristate "Nuvoton NPCM7XX PWM driver" + help + This driver provides support for Nuvoton NPCM7XX PWM + controller. + if ACPI comment "ACPI drivers"drivers/hwmon/Makefile +1
-0@@ -174,6 +174,7 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o +obj-$(CONFIG_SENSORS_NPCM7XX) += npcm7xx-pwm.o obj-$(CONFIG_PMBUS) += pmbus/drivers/hwmon/npcm7xx-pwm.c new file +53
-0@@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2014-2018 Nuvoton Technology corporation. + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/sysfs.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> + +/* NPCM7XX PWM port base address */ +#define NPCM7XX_PWM_REG_PR 0x0 +#define NPCM7XX_PWM_REG_CSR 0x4 +#define NPCM7XX_PWM_REG_CR 0x8 +#define NPCM7XX_PWM_REG_CNRx (PORT ) (0xC + (12 * PORT)) +#define NPCM7XX_PWM_REG_CMRx (PORT ) (0x10 + (12 * PORT)) +#define NPCM7XX_PWM_REG_PDRx (PORT ) (0x14 + (12 * PORT)) +#define NPCM7XX_PWM_REG_PIER 0x3C +#define NPCM7XX_PWM_REG_PIIR 0x40 + +#define NPCM7XX_PWM_CTRL_CH0_MODE_BIT BIT(3) +#define NPCM7XX_PWM_CTRL_CH1_MODE_BIT BIT(11) +#define NPCM7XX_PWM_CTRL_CH2_MODE_BIT BIT(15) +#define NPCM7XX_PWM_CTRL_CH3_MODE_BIT BIT(19) + +#define NPCM7XX_PWM_CTRL_CH0_INV_BIT BIT(2) +#define NPCM7XX_PWM_CTRL_CH1_INV_BIT BIT(10) +#define NPCM7XX_PWM_CTRL_CH2_INV_BIT BIT(14) +#define NPCM7XX_PWM_CTRL_CH3_INV_BIT BIT(18) + +#define NPCM7XX_PWM_CTRL_CH0_EN_BIT BIT(0) +#define NPCM7XX_PWM_CTRL_CH1_EN_BIT BIT(8) +#define NPCM7XX_PWM_CTRL_CH2_EN_BIT BIT(12) +#define NPCM7XX_PWM_CTRL_CH3_EN_BIT BIT(16) + +/* Define the maximum PWM channel number */ +#define NPCM7XX_PWM_MAX_CHN_NUM 8 +#define NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE 4 +#define NPCM7XX_PWM_MAX_MODULES 2 + +/* Define the Counter Register, value = 100 for match 100% */ +#define NPCM7XX_PWM_COUNTER_DEFALUT_NUM 255 +#define NPCM7XX_PWM_COMPARATOR_DEFALUT_NUM 127 + +#define NPCM7XX_PWM_COMPARATOR_MAX 255 + + +/* default all PWM channels PRESCALE2 = 1 */ +#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH0 0x4drivers/hwmon/npcm7xx-pwm.c line 63
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH1 0x40 +#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH2 0x400 +#define NPCM7XX_PWM_PRESCALE2_DEFALUT_CH3 0x4000 + +#define PWM_OUTPUT_FREQ_25KHZ 25000 +#define PWN_CNT_DEFAULT 256 +#define MIN_PRESCALE1 2 +#define NPCM7XX_PWM_PRESCALE_SHIFT_CH01 8 + +#define NPCM7XX_PWM_PRESCALE2_DEFALUT (NPCM7XX_PWM_PRESCALE2_DEFALUT_CH0| \
drivers/hwmon/npcm7xx-pwm.c line 64
Quoted 1 line
drivers/hwmon/npcm7xx-pwm.c new file +1
-0+NPCM7XX_PWM_PRESCALE2_DEFALUT_CH1 | \
drivers/hwmon/npcm7xx-pwm.c line 65
Quoted 1 line
drivers/hwmon/npcm7xx-pwm.c new file +1
-0+NPCM7XX_PWM_PRESCALE2_DEFALUT_CH2 | \
drivers/hwmon/npcm7xx-pwm.c
Quoted 3 lines
drivers/hwmon/npcm7xx-pwm.c new file +3
-0+ NPCM7XX_PWM_PRESCALE2_DEFALUT_CH3) + +#define NPCM7XX_PWM_CTRL_MODE_DEFALUT (
NPCM7XX_PWM_CTRL_CH0_MODE_BIT| \Quoted 8 lines
drivers/hwmon/npcm7xx-pwm.c new file +8
-0+NPCM7XX_PWM_CTRL_CH1_MODE_BIT | \ +NPCM7XX_PWM_CTRL_CH2_MODE_BIT | \ + NPCM7XX_PWM_CTRL_CH3_MODE_BIT) + +#define NPCM7XX_PWM_CTRL_EN_DEFALUT (NPCM7XX_PWM_CTRL_CH0_EN_BIT | \ +NPCM7XX_PWM_CTRL_CH1_EN_BIT | \ +NPCM7XX_PWM_CTRL_CH2_EN_BIT | \ +NPCM7XX_PWM_CTRL_CH3_EN_BIT )drivers/hwmon/npcm7xx-pwm.c
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+ +struct npcm7xx_pwm_data { +unsigned long clk_freq; +void __iomem *pwm_base[NPCM7XX_PWM_MAX_MODULES ]; +struct mutex npcm7xx_pwm_lock[NPCM7XX_PWM_MAX_CHN_NUM ]; +}; + +static const struct of_device_id pwm_dt_id[]; + +static int npcm7xx_pwm_config_set(struct npcm7xx_pwm_data *data, intchannel,
Quoted 7 lines
drivers/hwmon/npcm7xx-pwm.c new file +7
-0+ u16 val) +{ +u32 PWMChannel = (channel %NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE ); +u32 n_module = (channel /NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE ); +u32 u32TmpBuf =0 , ctrl_en_bit; + +/* drivers/hwmon/npcm7xx-pwm.c
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+* Config PWM Comparator register for setting duty cycle +*/ +if (val <0 || val >NPCM7XX_PWM_COMPARATOR_MAX ) +return -EINVAL ; + +/* write new CMR value */ +iowrite32 (val, data->pwm_base[n_module] + +NPCM7XX_PWM_REG_CMRx (PWMChannel)); + + u32TmpBuf = ioread32(data->pwm_base[n_module] +
NPCM7XX_PWM_REG_CR);Quoted 17 lines
drivers/hwmon/npcm7xx-pwm.c new file +17
-0+ +switch (PWMChannel) { +case 0 : + ctrl_en_bit =NPCM7XX_PWM_CTRL_CH0_EN_BIT ; +break ; +case 1 : + ctrl_en_bit =NPCM7XX_PWM_CTRL_CH1_EN_BIT ; +break ; +case 2 : + ctrl_en_bit =NPCM7XX_PWM_CTRL_CH2_EN_BIT ; +break ; +case 3 : + ctrl_en_bit =NPCM7XX_PWM_CTRL_CH3_EN_BIT ; +break ; +default : +return -ENODEV ; + }drivers/hwmon/npcm7xx-pwm.c
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+ +if (val ==0 ) +/* Disable PWM */ + u32TmpBuf &= ~(ctrl_en_bit); +else +/* Enable PWM */ + u32TmpBuf |= ctrl_en_bit; + +mutex_lock (&data->npcm7xx_pwm_lock[n_module]); + iowrite32(u32TmpBuf, data->pwm_base[n_module] +
NPCM7XX_PWM_REG_CR);Quoted 34 lines
drivers/hwmon/npcm7xx-pwm.c new file +34
-0+mutex_unlock (&data->npcm7xx_pwm_lock[n_module]); + +return 0 ; +} + +static int npcm7xx_read_pwm (struct device *dev,u32 attr,int channel, +long *val) +{ +struct npcm7xx_pwm_data *data =dev_get_drvdata (dev); +u32 PWMChannel = (channel %NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE ); +u32 n_module = (channel /NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE ); + +if (IS_ERR (data)) +return PTR_ERR (data); + +switch (attr) { +case hwmon_pwm_input: + *val = (long )ioread32 (data->pwm_base[n_module] + +NPCM7XX_PWM_REG_CMRx (PWMChannel)); +return 0 ; +default : +return -EOPNOTSUPP ; + } +} + +static int npcm7xx_write_pwm (struct device *dev,u32 attr,int channel, +long val) +{ +struct npcm7xx_pwm_data *data =dev_get_drvdata (dev); +int err =0 ; + +switch (attr) { +case hwmon_pwm_input: + err =npcm7xx_pwm_config_set (data, channel, (u16 )val);drivers/hwmon/npcm7xx-pwm.c
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+break ; +default : + err = -EOPNOTSUPP ; +break ; + } + +return err; +} + +static umode_t npcm7xx_pwm_is_visible(const void *_data, u32 attr, intchannel)
drivers/hwmon/npcm7xx-pwm.c
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+{ +switch (attr) { +case hwmon_pwm_input: +return 0644 ; +default : +return 0 ; + } +} + +static int npcm7xx_read(struct device *dev, enum hwmon_sensor_typestype,
drivers/hwmon/npcm7xx-pwm.c
Quoted 11 lines
drivers/hwmon/npcm7xx-pwm.c new file +11
-0+ u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_pwm: + return npcm7xx_read_pwm(dev, attr, channel, val); +default : +return -EOPNOTSUPP ; + } +} + +static int npcm7xx_write(struct device *dev, enum hwmon_sensor_typestype,
Quoted 71 lines
drivers/hwmon/npcm7xx-pwm.c new file +71
-0+ u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_pwm: + return npcm7xx_write_pwm(dev, attr, channel, val); +default : +return -EOPNOTSUPP ; + } +} + +static umode_t npcm7xx_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ +switch (type) { +case hwmon_pwm: +return npcm7xx_pwm_is_visible (data, attr, channel); +default : +return 0 ; + } +} + +static const u32 npcm7xx_pwm_config[] = { +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +HWMON_PWM_INPUT , +0 +}; + +static const struct hwmon_channel_info npcm7xx_pwm = { + .type = hwmon_pwm, + .config = npcm7xx_pwm_config, +}; + +static const struct hwmon_channel_info *npcm7xx_info[] = { + &npcm7xx_pwm, +NULL +}; + +static const struct hwmon_ops npcm7xx_hwmon_ops = { + .is_visible = npcm7xx_is_visible, + .read = npcm7xx_read, + .write = npcm7xx_write, +}; + +static const struct hwmon_chip_info npcm7xx_chip_info = { + .ops = &npcm7xx_hwmon_ops, + .info = npcm7xx_info, +}; + +static int npcm7xx_pwm_probe(struct platform_device *pdev) +{ +struct device *dev = &pdev->dev; +struct npcm7xx_pwm_data *data; +struct resource res[NPCM7XX_PWM_MAX_MODULES ]; +struct device *hwmon; +struct clk *clk; +int m, ch, res_cnt, ret; +u32 Prescale_val, output_freq; + + data =devm_kzalloc (dev,sizeof (*data),GFP_KERNEL ); +if (!data) +return -ENOMEM ; + +for (res_cnt =0 ; res_cnt <NPCM7XX_PWM_MAX_MODULES ; res_cnt++) { + ret = of_address_to_resource(dev->of_node, res_cnt,drivers/hwmon/npcm7xx-pwm.c
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+ &res[res_cnt]); +if (ret) { +pr_err ("PWM of_address_to_resource fail ret %d\n" , + ret); +return -EINVAL ; + } + + data->pwm_base[res_cnt] = +devm_ioremap_resource (dev, &(res[res_cnt])); + pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size0x%08X\n",
drivers/hwmon/npcm7xx-pwm.c line 278
Quoted 2 lines
drivers/hwmon/npcm7xx-pwm.c new file +2
-0+ res_cnt, (u32 )data->pwm_base[res_cnt], + res[res_cnt].start,resource_size (&(res[res_cnt])));
drivers/hwmon/npcm7xx-pwm.c
Quoted 3 lines
drivers/hwmon/npcm7xx-pwm.c new file +3
-0+ +if (!data->pwm_base[res_cnt]) { + pr_err("pwm probe failed: can't read pwm baseaddress for resource %d.\n",
Quoted 6 lines
drivers/hwmon/npcm7xx-pwm.c new file +6
-0+ res_cnt); +return -ENOMEM ; + } + +mutex_init (&data->npcm7xx_pwm_lock[res_cnt]); + }drivers/hwmon/npcm7xx-pwm.c
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+ + clk =devm_clk_get (dev,NULL ); +if (IS_ERR (clk)) +return -ENODEV ; + + data->clk_freq =clk_get_rate (clk); + +/* Adjust NPCM7xx PWMs output frequency to ~25Khz */ + output_freq = data->clk_freq /PWN_CNT_DEFAULT ; + Prescale_val = DIV_ROUND_CLOSEST(output_freq,
PWM_OUTPUT_FREQ_25KHZ);drivers/hwmon/npcm7xx-pwm.c line 299
Quoted 2 lines
drivers/hwmon/npcm7xx-pwm.c new file +2
-0+ +/* If Prescale_val = 0, then the prescale output clock is stopped */
drivers/hwmon/npcm7xx-pwm.c
Quoted 4 lines
drivers/hwmon/npcm7xx-pwm.c new file +4
-0+if (Prescale_val <MIN_PRESCALE1 ) + Prescale_val =MIN_PRESCALE1 ; +/* +* Prescale_val need to decrement in one because in the PWM Prescale
Quoted 8 lines
drivers/hwmon/npcm7xx-pwm.c new file +8
-0+* register the Prescale value increment by one +*/ + Prescale_val--; + +/* Setting PWM Prescale Register value register to both modules */ + Prescale_val |= (Prescale_val <<NPCM7XX_PWM_PRESCALE_SHIFT_CH01 ); + +for (m =0 ; m <NPCM7XX_PWM_MAX_MODULES ; m++) {drivers/hwmon/npcm7xx-pwm.c
Quoted 10 lines
drivers/hwmon/npcm7xx-pwm.c new file +10
-0+iowrite32 (Prescale_val, + data->pwm_base[m] +NPCM7XX_PWM_REG_PR ); +iowrite32 (NPCM7XX_PWM_PRESCALE2_DEFALUT , + data->pwm_base[m] +NPCM7XX_PWM_REG_CSR ); +iowrite32 (NPCM7XX_PWM_CTRL_MODE_DEFALUT , + data->pwm_base[m] +NPCM7XX_PWM_REG_CR ); + +for (ch =0 ; ch <NPCM7XX_PWM_MAX_CHN_NUM ; ch++) { + iowrite32(NPCM7XX_PWM_COUNTER_DEFALUT_NUM, + data->pwm_base[m] +
NPCM7XX_PWM_REG_CNRx(ch));drivers/hwmon/npcm7xx-pwm.c line 323
Quoted 2 lines
drivers/hwmon/npcm7xx-pwm.c new file +2
-0+ iowrite32(NPCM7XX_PWM_COMPARATOR_DEFALUT_NUM, + data->pwm_base[m] +
NPCM7XX_PWM_REG_CMRx(ch));drivers/hwmon/npcm7xx-pwm.c
Quoted 8 lines
drivers/hwmon/npcm7xx-pwm.c new file +8
-0+ } + +iowrite32 (NPCM7XX_PWM_CTRL_MODE_DEFALUT | +NPCM7XX_PWM_CTRL_EN_DEFALUT , + data->pwm_base[m] +NPCM7XX_PWM_REG_CR ); + } + + hwmon = devm_hwmon_device_register_with_info(dev, "npcm7xx_pwm",data,
drivers/hwmon/npcm7xx-pwm.c line 332
Quoted 1 line
drivers/hwmon/npcm7xx-pwm.c new file +1
-0+ &npcm7xx_chip_info,NULL);
drivers/hwmon/npcm7xx-pwm.c
Quoted 3 lines
drivers/hwmon/npcm7xx-pwm.c new file +3
-0+ +if (IS_ERR (hwmon)) { + pr_err("PWM Driver failed - devm_hwmon_device_register_with_groupsfailed\n");
Quoted 35 lines
drivers/hwmon/npcm7xx-pwm.c new file +28
-1+return PTR_ERR (hwmon); + } + +pr_info ("NPCM7XX PWM Driver probed, PWM output Freq %dHz\n" , + output_freq / ((Prescale_val &0xf ) +1 )); + +return 0 ; +} + +static const struct of_device_id of_pwm_match_table[] = { + { .compatible ="nuvoton,npcm750-pwm" , }, + {}, +}; +MODULE_DEVICE_TABLE (of, of_pwm_match_table); + +static struct platform_driver npcm7xx_pwm_driver = { + .probe = npcm7xx_pwm_probe, + .driver = { + .name ="npcm7xx_pwm" , + .of_match_table = of_pwm_match_table, + }, +}; + +module_platform_driver (npcm7xx_pwm_driver); + +MODULE_DESCRIPTION ("Nuvoton NPCM7XX PWM Driver" ); +MODULE_AUTHOR ("Tomer Maimon <[email protected]>" ); +MODULE_LICENSE ("GPL v2" ); --2.14.1
--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Guenter Roeck
maintainerRe: [PATCH v1 2/2] hwmon: npcm-pwm: add NPCM7xx PWM driver
Quoted 21 lines · Tomer Maimon
Hi Guenter,
Thanks for your prompt reply!
Quoted 10 lines · Guenter Roeck
Quoted 5 lines · Tomer Maimon
Add Nuvoton BMC NPCM7xx Pulse Width Modulation (PWM) driver.
The Nuvoton BMC NPCM7xx has two identical PWM controller modules, each module has four PWM controller outputs.
I don't see it guaranteed that all future NPCM7xx devices will be PWM controllers, much less that they will be compatible to the chip really
Actually all NPCM7xx family have PWM and FAN modules support,
Quoted 9 lines
Quoted 3 lines
supported here. NPCM750, I presume ? I would suggest name the driver accordingly.
The compatible name can not be a family name like nuvoton,npcm7xx-pwm, only a specific chip name. (in our case the NPCM750 is the full modules SOC) still you think i should change the driver name? (note: all of our NPCM7xx unique modules drivers are named npcm7xx-*.c or *-npcm7xx.c)
drivers/watchdog/npcm_wdt.c contradicts that statement.
Please discuss with the pwm maintainer. In hwmon, wildcards in driver file names are discouraged and will not be accepted. Our recommendation is to pick one chip from the family and use it as part of the file name.
Quoted 6 lines
Quoted 6 lines
As a generic pwm driver, not specifically tied to a fan controller, this driver does not belong into hwmon. It should be added to the pwm subsystem. Copying the maintainer and mailing list.
In the NPCM7xx we have PWM and FAN controller modules, usually in the
Quoted 9 lines
aspect of our BMC clients the two module
are used together to control the fans.But because in the NPCM7xx the PWM and the FAN controller are separate modules we
thought to do two separate drivers in the hwmon
is it possible? or you think it is better to do one hwmon driver for the PWM and the FAN controller.
That depends on how closely the two modules are intertwined. If the pwm module is generic, it belongs into the pwm subsystem. It only belongs into hwmon if it can _only_ be used for fan control, eg if the data reported by the fan module is used by the hardware to control the pwm output based on some fan speed <-> pw value mapping which is programmed into the chip, and/or if the pwm output can only connect to a fan and nothing else, and if the relationship between pwm output and fan input is well defined.
If both end up in hwmon, I don't see the benefit of having two separate drivers. That means two hwmon devices for the same fan or set of fans, one being all but useless in respect to output from the 'sensors' command. You'll have to convince me why that would make sense; I just don't see the point. In that case, I would also not see the point of having two separate devicetree nodes; to me, that would be similar to having two interfaces for a single serial line, one for receive and one for transmit.
Quoted 3 lines
note that we were going to submit soon also the FAN controller driver under hwmon.
No problem with that as long as there are no wildcards in the file name.
Guenter
Tomer Maimon
maintainerRe: [PATCH v1 2/2] hwmon: npcm-pwm: add NPCM7xx PWM driver
Hi Guenter,
Thanks for the prompt and detailed reply,
Quoted 34 lines · Guenter Roeck
Quoted 18 lines · Tomer Maimon
Hi Guenter,
Thanks for your prompt reply!
Quoted 10 lines · Guenter Roeck
Quoted 5 lines · Tomer Maimon
Add Nuvoton BMC NPCM7xx Pulse Width Modulation (PWM) driver.
The Nuvoton BMC NPCM7xx has two identical PWM controller modules, each module has four PWM controller outputs.
I don't see it guaranteed that all future NPCM7xx devices will be PWM controllers, much less that they will be compatible to the chip really
Quoted 8 lines
Actually all NPCM7xx family have PWM and FAN modules support,
Quoted 3 lines
supported here. NPCM750, I presume ? I would suggest name the driver accordingly.
The compatible name can not be a family name like nuvoton,npcm7xx-pwm,
only
Quoted 2 lines
a specific chip name. (in our case the NPCM750 is the full modules SOC) still you think i should change the driver name? (note: all of our
NPCM7xx
Quoted 2 lines
unique modules drivers are named npcm7xx-*.c or *-npcm7xx.c)
Quoted 7 lines
drivers/watchdog/npcm_wdt.ccontradicts that statement.Please discuss with the pwm maintainer. In hwmon, wildcards in driver file names are discouraged and will not be accepted. Our recommendation is to pick
one chip from the family and use it as part of the file name.
Thanks for the clarification, we will name the driver according your recommendation.
Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
As a generic pwm driver, not specifically tied to a fan controller, this driver does not belong into hwmon. It should be added to the pwm subsystem. Copying the maintainer and mailing list.
In the NPCM7xx we have PWM and FAN controller modules, usually in the
Quoted 9 lines
aspect of our BMC clients the two module
are used together to control the fans.But because in the NPCM7xx the PWM and the FAN controller are separate modules we
thought to do two separate drivers in the hwmon
is it possible? or you think it is better to do one hwmon driver for the PWM and the FAN controller.
Quoted 11 lines
That depends on how closely the two modules are intertwined. If the pwm module
is generic, it belongs into the pwm subsystem. It only belongs into hwmon if it can _only_ be used for fan control, eg if the data reported by the fan
module is used by the hardware to control the pwm output based on some fan speed <-> pw value mapping which is programmed into the chip, and/or if the pwm output can only connect to a fan and nothing else, and if the relationship between pwm output and fan input is well defined.
Again thank you for your clarification, our PWM module was designed to work with fan devices and for fan control.
i.e. on all server boards the pwm output is only connect to a fan device.
Quoted 8 lines
If both end up in hwmon, I don't see the benefit of having two separate drivers. That means two hwmon devices for the same fan or set of fans, one being all but useless in respect to output from the 'sensors' command. You'll have to convince me why that would make sense; I just don't see the point. In that case, I would also not see the point of having two separate devicetree nodes; to me, that would be similar to having two interfaces for a single serial line, one for receive and one for transmit.
Since our PWM and FAN are made only for handling the fans we will use them in a single hwmon driver as you recommended
Quoted 8 lines
note that we were going to submit soon also the FAN controller driver under
Quoted 2 lines
hwmon.
No problem with that as long as there are no wildcards in the file name.
Guenter
Thanks,
Tomer
kbuild test robot
build botRe: [PATCH v1 2/2] hwmon: npcm-pwm: add NPCM7xx PWM driver
In reply to Tomer MaimonI love your patch! Perhaps something to improve:
Hi Tomer,
I love your patch! Perhaps something to improve:
[auto build test WARNING on hwmon/hwmon-next]
[also build test WARNING on v4.17-rc7]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Tomer-Maimon/dt-binding-hwmon-Add-NPCM7xx-PWM-documentation/20180531-034040 base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next config: x86_64-allmodconfig compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:
make ARCH=x86_64 allmodconfig
make ARCH=x86_64
All warnings (new ones prefixed by >>):
vim +277 drivers/hwmon/npcm7xx-pwm.c
250
251 static int npcm7xx_pwm_probe(struct platform_device *pdev)
252 {
253 struct device *dev = &pdev->dev;
254 struct npcm7xx_pwm_data *data;
255 struct resource res[NPCM7XX_PWM_MAX_MODULES];
256 struct device *hwmon;
257 struct clk *clk;
258 int m, ch, res_cnt, ret;
259 u32 Prescale_val, output_freq;
260
261 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
262 if (!data)
263 return -ENOMEM;
264
265 for (res_cnt = 0; res_cnt < NPCM7XX_PWM_MAX_MODULES ; res_cnt++) {
266 ret = of_address_to_resource(dev->of_node, res_cnt,
267 &res[res_cnt]);
268 if (ret) {
269 pr_err("PWM of_address_to_resource fail ret %d\n",
270 ret);
271 return -EINVAL;
272 }
273
274 data->pwm_base[res_cnt] =
275 devm_ioremap_resource(dev, &(res[res_cnt]));
> 276 pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
> 277 res_cnt, (u32)data->pwm_base[res_cnt], 278 res[res_cnt].start, resource_size(&(res[res_cnt])));
279
280 if (!data->pwm_base[res_cnt]) {
281 pr_err("pwm probe failed: can't read pwm base address for resource %d.\n",
282 res_cnt);
283 return -ENOMEM;
284 }
285
286 mutex_init(&data->npcm7xx_pwm_lock[res_cnt]);
287 }
288
289 clk = devm_clk_get(dev, NULL);
290 if (IS_ERR(clk))
291 return -ENODEV;
292
293 data->clk_freq = clk_get_rate(clk);
294
295 /* Adjust NPCM7xx PWMs output frequency to ~25Khz */
296 output_freq = data->clk_freq / PWN_CNT_DEFAULT;
297 Prescale_val = DIV_ROUND_CLOSEST(output_freq, PWM_OUTPUT_FREQ_25KHZ);
298
299 /* If Prescale_val = 0, then the prescale output clock is stopped */
300 if (Prescale_val < MIN_PRESCALE1)
301 Prescale_val = MIN_PRESCALE1;
302 /*
303 * Prescale_val need to decrement in one because in the PWM Prescale
304 * register the Prescale value increment by one
305 */
306 Prescale_val--;
307
308 /* Setting PWM Prescale Register value register to both modules */
309 Prescale_val |= (Prescale_val << NPCM7XX_PWM_PRESCALE_SHIFT_CH01);
310
311 for (m = 0; m < NPCM7XX_PWM_MAX_MODULES ; m++) {
312 iowrite32(Prescale_val,
313 data->pwm_base[m] + NPCM7XX_PWM_REG_PR);
314 iowrite32(NPCM7XX_PWM_PRESCALE2_DEFALUT,
315 data->pwm_base[m] + NPCM7XX_PWM_REG_CSR);
316 iowrite32(NPCM7XX_PWM_CTRL_MODE_DEFALUT,
317 data->pwm_base[m] + NPCM7XX_PWM_REG_CR);
318
319 for (ch = 0; ch < NPCM7XX_PWM_MAX_CHN_NUM; ch++) {
320 iowrite32(NPCM7XX_PWM_COUNTER_DEFALUT_NUM,
321 data->pwm_base[m] + NPCM7XX_PWM_REG_CNRx(ch));
322 iowrite32(NPCM7XX_PWM_COMPARATOR_DEFALUT_NUM,
323 data->pwm_base[m] + NPCM7XX_PWM_REG_CMRx(ch));
324 }
325
326 iowrite32(NPCM7XX_PWM_CTRL_MODE_DEFALUT |
327 NPCM7XX_PWM_CTRL_EN_DEFALUT,
328 data->pwm_base[m] + NPCM7XX_PWM_REG_CR);
329 }
330
331 hwmon = devm_hwmon_device_register_with_info(dev, "npcm7xx_pwm", data,
332 &npcm7xx_chip_info, NULL);
333
334 if (IS_ERR(hwmon)) {
335 pr_err("PWM Driver failed - devm_hwmon_device_register_with_groups failed\n");
336 return PTR_ERR(hwmon);
337 }
338
339 pr_info("NPCM7XX PWM Driver probed, PWM output Freq %dHz\n",
340 output_freq / ((Prescale_val & 0xf) + 1));
341
342 return 0;
343 }
344
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Guenter Roeck
maintainerRe: [PATCH v1 2/2] hwmon: npcm-pwm: add NPCM7xx PWM driver
Quoted 47 lines · kbuild test robot
Hi Tomer,
I love your patch! Perhaps something to improve:
[auto build test WARNING on hwmon/hwmon-next]
[also build test WARNING on v4.17-rc7]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]url: https://github.com/0day-ci/linux/commits/Tomer-Maimon/dt-binding-hwmon-Add-NPCM7xx-PWM-documentation/20180531-034040 base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next config: x86_64-allmodconfig compiler: gcc-7 (Debian 7.3.0-16) 7.3.0reproduce:
make ARCH=x86_64 allmodconfig
make ARCH=x86_64All warnings (new ones prefixed by >>):
vim +277
drivers/hwmon/npcm7xx-pwm.c250 251 static int npcm7xx_pwm_probe(struct platform_device *pdev) 252 { 253 struct device *dev = &pdev->dev; 254 struct npcm7xx_pwm_data *data; 255 struct resource res[NPCM7XX_PWM_MAX_MODULES]; 256 struct device *hwmon; 257 struct clk *clk; 258 int m, ch, res_cnt, ret; 259 u32 Prescale_val, output_freq; 260 261 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 262 if (!data) 263 return -ENOMEM; 264 265 for (res_cnt = 0; res_cnt < NPCM7XX_PWM_MAX_MODULES ; res_cnt++) { 266 ret = of_address_to_resource(dev->of_node, res_cnt, 267 &res[res_cnt]); 268 if (ret) { 269 pr_err("PWM of_address_to_resource fail ret %d\n", 270 ret); 271 return -EINVAL; 272 } 273 274 data->pwm_base[res_cnt] = 275 devm_ioremap_resource(dev, &(res[res_cnt]));
Quoted 4 lines
Quoted 2 lines
276 pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
277res_cnt, (u32)data->pwm_base[res_cnt],278 res[res_cnt].start, resource_size(&(res[res_cnt]))); 279
No idea what the tool is complaining about, but the messages should use dev_ functions.
Quoted 74 lines
280 if (!data->pwm_base[res_cnt]) { 281 pr_err("pwm probe failed: can't read pwm base address for resource %d.\n", 282 res_cnt); 283 return -ENOMEM; 284 } 285 286 mutex_init(&data->npcm7xx_pwm_lock[res_cnt]); 287 } 288 289 clk = devm_clk_get(dev, NULL); 290 if (IS_ERR(clk)) 291 return -ENODEV; 292 293 data->clk_freq = clk_get_rate(clk); 294 295 /* Adjust NPCM7xx PWMs output frequency to ~25Khz */ 296 output_freq = data->clk_freq / PWN_CNT_DEFAULT; 297 Prescale_val = DIV_ROUND_CLOSEST(output_freq, PWM_OUTPUT_FREQ_25KHZ); 298 299 /* If Prescale_val = 0, then the prescale output clock is stopped */ 300 if (Prescale_val < MIN_PRESCALE1) 301 Prescale_val = MIN_PRESCALE1; 302 /* 303 * Prescale_val need to decrement in one because in the PWM Prescale 304 * register the Prescale value increment by one 305 */ 306 Prescale_val--; 307 308 /* Setting PWM Prescale Register value register to both modules */ 309 Prescale_val |= (Prescale_val << NPCM7XX_PWM_PRESCALE_SHIFT_CH01); 310 311 for (m = 0; m < NPCM7XX_PWM_MAX_MODULES ; m++) { 312 iowrite32(Prescale_val, 313 data->pwm_base[m] + NPCM7XX_PWM_REG_PR); 314 iowrite32(NPCM7XX_PWM_PRESCALE2_DEFALUT, 315 data->pwm_base[m] + NPCM7XX_PWM_REG_CSR); 316 iowrite32(NPCM7XX_PWM_CTRL_MODE_DEFALUT, 317 data->pwm_base[m] + NPCM7XX_PWM_REG_CR); 318 319 for (ch = 0; ch < NPCM7XX_PWM_MAX_CHN_NUM; ch++) { 320 iowrite32(NPCM7XX_PWM_COUNTER_DEFALUT_NUM, 321 data->pwm_base[m] + NPCM7XX_PWM_REG_CNRx(ch)); 322 iowrite32(NPCM7XX_PWM_COMPARATOR_DEFALUT_NUM, 323 data->pwm_base[m] + NPCM7XX_PWM_REG_CMRx(ch)); 324 } 325 326 iowrite32(NPCM7XX_PWM_CTRL_MODE_DEFALUT | 327 NPCM7XX_PWM_CTRL_EN_DEFALUT, 328 data->pwm_base[m] + NPCM7XX_PWM_REG_CR); 329 } 330 331 hwmon = devm_hwmon_device_register_with_info(dev, "npcm7xx_pwm", data, 332 &npcm7xx_chip_info, NULL); 333 334 if (IS_ERR(hwmon)) { 335 pr_err("PWM Driver failed - devm_hwmon_device_register_with_groups failed\n"); 336 return PTR_ERR(hwmon); 337 } 338 339 pr_info("NPCM7XX PWM Driver probed, PWM output Freq %dHz\n", 340 output_freq / ((Prescale_val & 0xf) + 1)); 341 342 return 0; 343 } 344---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
kbuild test robot
build botRe: [PATCH v1 2/2] hwmon: npcm-pwm: add NPCM7xx PWM driver
In reply to Tomer MaimonI love your patch! Perhaps something to improve:
Hi Tomer,
I love your patch! Perhaps something to improve:
[auto build test WARNING on hwmon/hwmon-next]
[also build test WARNING on v4.17 next-20180608]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Tomer-Maimon/dt-binding-hwmon-Add-NPCM7xx-PWM-documentation/20180531-034040 base: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next config: i386-randconfig-x079-06101602 (attached as .config) compiler: gcc-7 (Debian 7.3.0-16) 7.3.0 reproduce: # save the attached .config to linux build tree make ARCH=i386
All warnings (new ones prefixed by >>):
In file included from include/linux/printk.h:7:0,
from include/linux/kernel.h:14, from include/linux/list.h:9,
from include/linux/module.h:9,
from drivers//hwmon/npcm7xx-pwm.c:4:
drivers//hwmon/npcm7xx-pwm.c: In function 'npcm7xx_pwm_probe':
>> include/linux/kern_levels.h:5:18: warning: format '%X' expects argument of type 'unsigned int', but argument 4 has type 'resource_size_t {aka long long unsigned int}' [-Wformat=]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
^~~~~~~~
include/linux/printk.h:339:9: note: in expansion of macro 'KERN_DEBUG'
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~
drivers//hwmon/npcm7xx-pwm.c:276:3: note: in expansion of macro 'pr_debug'
pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
^~~~~~~~
drivers//hwmon/npcm7xx-pwm.c:276:50: note: format string is defined here
pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
~~~^
%08llX
In file included from include/linux/printk.h:7:0,
from include/linux/kernel.h:14,
from include/linux/list.h:9,
from include/linux/module.h:9,
from drivers//hwmon/npcm7xx-pwm.c:4:
include/linux/kern_levels.h:5:18: warning: format '%X' expects argument of type 'unsigned int', but argument 5 has type 'resource_size_t {aka long long unsigned int}' [-Wformat=]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
^~~~~~~~
include/linux/printk.h:339:9: note: in expansion of macro 'KERN_DEBUG'
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~
drivers//hwmon/npcm7xx-pwm.c:276:3: note: in expansion of macro 'pr_debug'
pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
^~~~~~~~
drivers//hwmon/npcm7xx-pwm.c:276:64: note: format string is defined here
pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
~~~^
%08llX--
In file included from include/linux/printk.h:7:0,
from include/linux/kernel.h:14, from include/linux/list.h:9,
from include/linux/module.h:9, from drivers/hwmon/npcm7xx-pwm.c:4:
drivers/hwmon/npcm7xx-pwm.c: In function 'npcm7xx_pwm_probe':
>> include/linux/kern_levels.h:5:18: warning: format '%X' expects argument of type 'unsigned int', but argument 4 has type 'resource_size_t {aka long long unsigned int}' [-Wformat=]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
^~~~~~~~
include/linux/printk.h:339:9: note: in expansion of macro 'KERN_DEBUG'
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~
drivers/hwmon/npcm7xx-pwm.c:276:3: note: in expansion of macro 'pr_debug'
pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
^~~~~~~~
drivers/hwmon/npcm7xx-pwm.c:276:50: note: format string is defined here
pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
~~~^
%08llX
In file included from include/linux/printk.h:7:0,
from include/linux/kernel.h:14,
from include/linux/list.h:9,
from include/linux/module.h:9,
from drivers/hwmon/npcm7xx-pwm.c:4:
include/linux/kern_levels.h:5:18: warning: format '%X' expects argument of type 'unsigned int', but argument 5 has type 'resource_size_t {aka long long unsigned int}' [-Wformat=]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:15:20: note: in expansion of macro 'KERN_SOH'
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
^~~~~~~~
include/linux/printk.h:339:9: note: in expansion of macro 'KERN_DEBUG'
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~~
drivers/hwmon/npcm7xx-pwm.c:276:3: note: in expansion of macro 'pr_debug'
pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
^~~~~~~~
drivers/hwmon/npcm7xx-pwm.c:276:64: note: format string is defined here
pr_debug("pwm%d base is 0x%08X, res.start 0x%08X , size 0x%08X\n",
~~~^
%08llXvim +5 include/linux/kern_levels.h
314ba352 Joe Perches 2012-07-30 404d2c8c8 Joe Perches 2012-07-30 @5 #define KERN_SOH "\001" /* ASCII Start Of Header */04d2c8c8 Joe Perches 2012-07-30 6 #define KERN_SOH_ASCII '\001'04d2c8c8 Joe Perches 2012-07-30 7
:::::: The code at line 5 was first introduced by commit
:::::: 04d2c8c83d0e3ac5f78aeede51babb3236200112 printk: convert the format for KERN_<LEVEL> to a 2 byte pattern
:::::: TO: Joe Perches <[email protected]>
:::::: CC: Linus Torvalds <[email protected]>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation