mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
pwm: rockchip: support more features
1.support counter, frequency meter, global control and wave generator. 2.add struct rockchip_pwm_funcs and modify struct rockchip_pwm_data for compatibility and extensibility. 3.rename current .enable/.config/.irq_handler to v1. 4.not to return ERRNO if failed to get irq in probing for pwm_v3. Signed-off-by: Damon Ding <damon.ding@rock-chips.com> Change-Id: I28c6a2946ccb9072f464397d6b25f4b6803fa8c5
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#define _PWM_ROCKCHIP_IRQ_CALLBACKS_H_
|
||||
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm-rockchip.h>
|
||||
|
||||
static void rockchip_pwm_oneshot_callback(struct pwm_device *pwm, struct pwm_state *state)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm-rockchip.h>
|
||||
#include <linux/time.h>
|
||||
#include "pwm-rockchip-irq-callbacks.h"
|
||||
|
||||
@@ -52,7 +53,6 @@
|
||||
|
||||
#define PWM_ONESHOT_COUNT_SHIFT 24
|
||||
#define PWM_ONESHOT_COUNT_MASK (0xff << PWM_ONESHOT_COUNT_SHIFT)
|
||||
#define PWM_ONESHOT_COUNT_MAX 256
|
||||
|
||||
#define PWM_REG_INTSTS(n) ((3 - (n)) * 0x10 + 0x10)
|
||||
#define PWM_REG_INT_EN(n) ((3 - (n)) * 0x10 + 0x14)
|
||||
@@ -73,8 +73,12 @@ struct rockchip_pwm_chip {
|
||||
bool vop_pwm_en; /* indicate voppwm mirror register state */
|
||||
bool center_aligned;
|
||||
bool oneshot_en;
|
||||
bool freq_meter_support;
|
||||
bool counter_support;
|
||||
bool wave_support;
|
||||
int channel_id;
|
||||
int irq;
|
||||
u8 capture_cnt;
|
||||
};
|
||||
|
||||
struct rockchip_pwm_regs {
|
||||
@@ -82,16 +86,45 @@ struct rockchip_pwm_regs {
|
||||
unsigned long period;
|
||||
unsigned long cntr;
|
||||
unsigned long ctrl;
|
||||
unsigned long version;
|
||||
};
|
||||
|
||||
struct rockchip_pwm_funcs {
|
||||
int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm, bool enable);
|
||||
void (*config)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state);
|
||||
void (*set_capture)(struct pwm_chip *chip, struct pwm_device *pwm, bool enable);
|
||||
int (*get_capture_result)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_capture *catpure_res);
|
||||
int (*set_counter)(struct pwm_chip *chip, struct pwm_device *pwm, bool enable);
|
||||
int (*get_counter_result)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
unsigned long *counter_res, bool is_clear);
|
||||
int (*set_freq_meter)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
bool enable, unsigned long delay_ms);
|
||||
int (*get_freq_meter_result)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
unsigned long delay_ms, unsigned long *freq_hz);
|
||||
int (*global_ctrl)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
enum rockchip_pwm_global_ctrl_cmd cmd);
|
||||
int (*set_wave_table)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct rockchip_pwm_wave_table *table_config,
|
||||
enum rockchip_pwm_wave_table_width_mode width_mode);
|
||||
int (*set_wave)(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct rockchip_pwm_wave_config *config);
|
||||
irqreturn_t (*irq_handler)(int irq, void *data);
|
||||
};
|
||||
|
||||
struct rockchip_pwm_data {
|
||||
struct rockchip_pwm_regs regs;
|
||||
struct rockchip_pwm_funcs funcs;
|
||||
unsigned int prescaler;
|
||||
bool supports_polarity;
|
||||
bool supports_lock;
|
||||
bool vop_pwm;
|
||||
u32 enable_conf;
|
||||
u32 enable_conf_mask;
|
||||
u32 oneshot_cnt_max;
|
||||
u32 oneshot_rpt_max;
|
||||
u32 wave_table_max;
|
||||
};
|
||||
|
||||
static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
|
||||
@@ -107,7 +140,7 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
|
||||
u32 enable_conf = pc->data->enable_conf;
|
||||
u64 tmp;
|
||||
u32 val;
|
||||
u32 dclk_div;
|
||||
u32 dclk_div = 1;
|
||||
int ret;
|
||||
|
||||
if (!pc->oneshot_en) {
|
||||
@@ -140,7 +173,7 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
|
||||
clk_disable(pc->pclk);
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_pwm_oneshot_irq(int irq, void *data)
|
||||
static irqreturn_t rockchip_pwm_irq_v1(int irq, void *data)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = data;
|
||||
struct pwm_state state;
|
||||
@@ -168,8 +201,8 @@ static irqreturn_t rockchip_pwm_oneshot_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
static void rockchip_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
|
||||
unsigned long period, duty, delay_ns;
|
||||
@@ -179,7 +212,7 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
u8 dclk_div = 1;
|
||||
|
||||
#ifdef CONFIG_PWM_ROCKCHIP_ONESHOT
|
||||
if (state->oneshot_count > 0 && state->oneshot_count <= PWM_ONESHOT_COUNT_MAX)
|
||||
if (state->oneshot_count > 0 && state->oneshot_count <= pc->data->oneshot_cnt_max)
|
||||
dclk_div = 2;
|
||||
#endif
|
||||
|
||||
@@ -210,7 +243,7 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PWM_ROCKCHIP_ONESHOT
|
||||
if (state->oneshot_count > 0 && state->oneshot_count <= PWM_ONESHOT_COUNT_MAX) {
|
||||
if (state->oneshot_count > 0 && state->oneshot_count <= pc->data->oneshot_cnt_max) {
|
||||
u32 int_ctrl;
|
||||
|
||||
/*
|
||||
@@ -233,9 +266,11 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
ctrl &= ~PWM_ONESHOT_COUNT_MASK;
|
||||
ctrl |= (state->oneshot_count - 1) << PWM_ONESHOT_COUNT_SHIFT;
|
||||
|
||||
int_ctrl = readl_relaxed(pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
int_ctrl |= PWM_CH_INT(pc->channel_id);
|
||||
writel_relaxed(int_ctrl, pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
if (pc->irq >= 0) {
|
||||
int_ctrl = readl_relaxed(pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
int_ctrl |= PWM_CH_INT(pc->channel_id);
|
||||
writel_relaxed(int_ctrl, pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
}
|
||||
} else {
|
||||
u32 int_ctrl;
|
||||
|
||||
@@ -244,7 +279,8 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
ctrl |= PWM_SEL_NO_SCALED_CLOCK;
|
||||
|
||||
if (state->oneshot_count)
|
||||
dev_err(chip->dev, "Oneshot_count must be between 1 and 256.\n");
|
||||
dev_err(chip->dev, "Oneshot_count must be between 1 and %d.\n",
|
||||
pc->data->oneshot_cnt_max);
|
||||
|
||||
pc->oneshot_en = false;
|
||||
ctrl &= ~PWM_MODE_MASK;
|
||||
@@ -292,9 +328,7 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static int rockchip_pwm_enable(struct pwm_chip *chip,
|
||||
struct pwm_device *pwm,
|
||||
bool enable)
|
||||
static int rockchip_pwm_enable_v1(struct pwm_chip *chip, struct pwm_device *pwm, bool enable)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
|
||||
u32 enable_conf = pc->data->enable_conf;
|
||||
@@ -333,6 +367,21 @@ static int rockchip_pwm_enable(struct pwm_chip *chip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
pc->data->funcs.config(chip, pwm, state);
|
||||
}
|
||||
|
||||
static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm, bool enable)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
return pc->data->funcs.enable(chip, pwm, enable);
|
||||
}
|
||||
|
||||
static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
@@ -374,6 +423,235 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rockchip_pwm_set_counter(struct pwm_device *pwm, bool enable)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct rockchip_pwm_chip *pc;
|
||||
struct pwm_state curstate;
|
||||
int ret = 0;
|
||||
|
||||
if (!pwm)
|
||||
return -EINVAL;
|
||||
|
||||
chip = pwm->chip;
|
||||
pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
if (!pc->counter_support ||
|
||||
!pc->data->funcs.set_counter || !pc->data->funcs.get_counter_result) {
|
||||
dev_err(chip->dev, "Unsupported counter mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pwm_get_state(pwm, &curstate);
|
||||
if (curstate.enabled) {
|
||||
dev_err(chip->dev, "Failed to enable counter mode because PWM%d is busy\n",
|
||||
pc->channel_id);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pc->data->funcs.set_counter(chip, pwm, enable);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to abtain counter arbitration for PWM%d\n",
|
||||
pc->channel_id);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
|
||||
err_disable_pclk:
|
||||
clk_disable(pc->pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_pwm_set_counter);
|
||||
|
||||
int rockchip_pwm_get_counter_result(struct pwm_device *pwm,
|
||||
unsigned long *counter_res, bool is_clear)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct rockchip_pwm_chip *pc;
|
||||
int ret = 0;
|
||||
|
||||
if (!pwm || !counter_res)
|
||||
return -EINVAL;
|
||||
|
||||
chip = pwm->chip;
|
||||
pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
if (!pc->counter_support ||
|
||||
!pc->data->funcs.set_counter || !pc->data->funcs.get_counter_result) {
|
||||
dev_err(chip->dev, "Unsupported counter mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pc->data->funcs.get_counter_result(chip, pwm, counter_res, is_clear);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to get counter result for PWM%d\n",
|
||||
pc->channel_id);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
|
||||
err_disable_pclk:
|
||||
clk_disable(pc->pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_pwm_get_counter_result);
|
||||
|
||||
int rockchip_pwm_set_freq_meter(struct pwm_device *pwm, unsigned long delay_ms,
|
||||
unsigned long *freq_hz)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct rockchip_pwm_chip *pc;
|
||||
struct pwm_state curstate;
|
||||
int ret = 0;
|
||||
|
||||
if (!pwm || !freq_hz)
|
||||
return -EINVAL;
|
||||
|
||||
chip = pwm->chip;
|
||||
pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
if (!pc->freq_meter_support ||
|
||||
!pc->data->funcs.set_freq_meter || !pc->data->funcs.get_freq_meter_result) {
|
||||
dev_err(chip->dev, "Unsupported frequency meter mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pwm_get_state(pwm, &curstate);
|
||||
if (curstate.enabled) {
|
||||
dev_err(chip->dev, "Failed to enable frequency meter mode because PWM%d is busy\n",
|
||||
pc->channel_id);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pc->data->funcs.set_freq_meter(chip, pwm, true, delay_ms);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to abtain frequency meter arbitration for PWM%d\n",
|
||||
pc->channel_id);
|
||||
} else {
|
||||
ret = pc->data->funcs.get_freq_meter_result(chip, pwm, delay_ms, freq_hz);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to get frequency meter result for PWM%d\n",
|
||||
pc->channel_id);
|
||||
}
|
||||
}
|
||||
pc->data->funcs.set_freq_meter(chip, pwm, false, 0);
|
||||
|
||||
clk_disable(pc->pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_pwm_set_freq_meter);
|
||||
|
||||
int rockchip_pwm_global_ctrl(struct pwm_device *pwm, enum rockchip_pwm_global_ctrl_cmd cmd)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct rockchip_pwm_chip *pc;
|
||||
struct pwm_state curstate;
|
||||
int ret = 0;
|
||||
|
||||
if (!pwm)
|
||||
return -EINVAL;
|
||||
|
||||
chip = pwm->chip;
|
||||
pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
if (!pc->data->funcs.global_ctrl) {
|
||||
dev_err(chip->dev, "Unsupported global control\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pwm_get_state(pwm, &curstate);
|
||||
if (curstate.enabled) {
|
||||
dev_err(chip->dev, "Failed to execute global ctrl cmd %d because PWM%d is busy\n",
|
||||
cmd, pc->channel_id);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pc->data->funcs.global_ctrl(chip, pwm, cmd);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to execute global ctrl cmd %d for PWM%d\n",
|
||||
cmd, pc->channel_id);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
|
||||
err_disable_pclk:
|
||||
clk_disable(pc->pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_pwm_global_ctrl);
|
||||
|
||||
int rockchip_pwm_set_wave(struct pwm_device *pwm, struct rockchip_pwm_wave_config *config)
|
||||
{
|
||||
struct pwm_chip *chip;
|
||||
struct rockchip_pwm_chip *pc;
|
||||
int ret = 0;
|
||||
|
||||
if (!pwm || !config)
|
||||
return -EINVAL;
|
||||
|
||||
chip = pwm->chip;
|
||||
pc = to_rockchip_pwm_chip(chip);
|
||||
|
||||
if (!pc->wave_support ||
|
||||
!pc->data->funcs.set_wave_table || !pc->data->funcs.set_wave) {
|
||||
dev_err(chip->dev, "Unsupported wave generator mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_enable(pc->pclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (config->duty_table) {
|
||||
ret = pc->data->funcs.set_wave_table(chip, pwm, config->duty_table,
|
||||
config->width_mode);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to set wave duty table for PWM%d\n",
|
||||
pc->channel_id);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->period_table) {
|
||||
ret = pc->data->funcs.set_wave_table(chip, pwm, config->period_table,
|
||||
config->width_mode);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to set wave period table for PWM%d\n",
|
||||
pc->channel_id);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
}
|
||||
|
||||
ret = pc->data->funcs.set_wave(chip, pwm, config);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to set wave generator for PWM%d\n", pc->channel_id);
|
||||
goto err_disable_pclk;
|
||||
}
|
||||
|
||||
err_disable_pclk:
|
||||
clk_disable(pc->pclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rockchip_pwm_set_wave);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int rockchip_pwm_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
@@ -433,6 +711,7 @@ static const struct pwm_ops rockchip_pwm_ops = {
|
||||
|
||||
static const struct rockchip_pwm_data pwm_data_v1 = {
|
||||
.regs = {
|
||||
.version = 0x5c,
|
||||
.duty = 0x04,
|
||||
.period = 0x08,
|
||||
.cntr = 0x00,
|
||||
@@ -444,10 +723,16 @@ static const struct rockchip_pwm_data pwm_data_v1 = {
|
||||
.vop_pwm = false,
|
||||
.enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
|
||||
.enable_conf_mask = BIT(1) | BIT(3),
|
||||
.oneshot_cnt_max = 0x100,
|
||||
.funcs = {
|
||||
.enable = rockchip_pwm_enable_v1,
|
||||
.config = rockchip_pwm_config_v1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rockchip_pwm_data pwm_data_v2 = {
|
||||
.regs = {
|
||||
.version = 0x5c,
|
||||
.duty = 0x08,
|
||||
.period = 0x04,
|
||||
.cntr = 0x00,
|
||||
@@ -460,10 +745,16 @@ static const struct rockchip_pwm_data pwm_data_v2 = {
|
||||
.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
|
||||
PWM_CONTINUOUS,
|
||||
.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
|
||||
.oneshot_cnt_max = 0x100,
|
||||
.funcs = {
|
||||
.enable = rockchip_pwm_enable_v1,
|
||||
.config = rockchip_pwm_config_v1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rockchip_pwm_data pwm_data_vop = {
|
||||
.regs = {
|
||||
.version = 0x5c,
|
||||
.duty = 0x08,
|
||||
.period = 0x04,
|
||||
.cntr = 0x0c,
|
||||
@@ -476,10 +767,16 @@ static const struct rockchip_pwm_data pwm_data_vop = {
|
||||
.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
|
||||
PWM_CONTINUOUS,
|
||||
.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
|
||||
.oneshot_cnt_max = 0x100,
|
||||
.funcs = {
|
||||
.enable = rockchip_pwm_enable_v1,
|
||||
.config = rockchip_pwm_config_v1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rockchip_pwm_data pwm_data_v3 = {
|
||||
.regs = {
|
||||
.version = 0x5c,
|
||||
.duty = 0x08,
|
||||
.period = 0x04,
|
||||
.cntr = 0x00,
|
||||
@@ -492,6 +789,12 @@ static const struct rockchip_pwm_data pwm_data_v3 = {
|
||||
.enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
|
||||
PWM_CONTINUOUS,
|
||||
.enable_conf_mask = GENMASK(2, 0) | BIT(5) | BIT(8),
|
||||
.oneshot_cnt_max = 0x100,
|
||||
.funcs = {
|
||||
.enable = rockchip_pwm_enable_v1,
|
||||
.config = rockchip_pwm_config_v1,
|
||||
.irq_handler = rockchip_pwm_irq_v1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_pwm_dt_ids[] = {
|
||||
@@ -580,23 +883,6 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
|
||||
goto err_pclk;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_ROCKCHIP_ONESHOT)) {
|
||||
pc->irq = platform_get_irq(pdev, 0);
|
||||
if (pc->irq < 0) {
|
||||
dev_err(&pdev->dev, "Get oneshot mode irq failed\n");
|
||||
ret = pc->irq;
|
||||
goto err_pclk;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, pc->irq, rockchip_pwm_oneshot_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_SHARED,
|
||||
"rk_pwm_oneshot_irq", pc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Claim oneshot IRQ failed\n");
|
||||
goto err_pclk;
|
||||
}
|
||||
}
|
||||
|
||||
pc->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(pc->pinctrl)) {
|
||||
dev_err(&pdev->dev, "Get pinctrl failed!\n");
|
||||
@@ -620,6 +906,22 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
|
||||
pc->chip.npwm = 1;
|
||||
pc->clk_rate = clk_get_rate(pc->clk);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_ROCKCHIP_ONESHOT) && pc->data->funcs.irq_handler) {
|
||||
pc->irq = platform_get_irq_optional(pdev, 0);
|
||||
if (pc->irq < 0) {
|
||||
dev_warn(&pdev->dev,
|
||||
"Can't get oneshot mode irq and oneshot interrupt is unsupported\n");
|
||||
} else {
|
||||
ret = devm_request_irq(&pdev->dev, pc->irq, pc->data->funcs.irq_handler,
|
||||
IRQF_NO_SUSPEND | IRQF_SHARED,
|
||||
"rk_pwm_oneshot_irq", pc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Claim oneshot IRQ failed\n");
|
||||
goto err_pclk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pc->data->supports_polarity) {
|
||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pc->chip.of_pwm_n_cells = 3;
|
||||
|
||||
187
include/linux/pwm-rockchip.h
Normal file
187
include/linux/pwm-rockchip.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _PWM_ROCKCHIP_H_
|
||||
#define _PWM_ROCKCHIP_H_
|
||||
|
||||
#include <linux/pwm.h>
|
||||
|
||||
/**
|
||||
* enum rockchip_pwm_global_ctrl_cmd - commands for pwm global ctrl
|
||||
* @PWM_GLOBAL_CTRL_JOIN: join the global control group
|
||||
* @PWM_GLOBAL_CTRL_EXIT: exit the global control group
|
||||
* @PWM_GLOBAL_CTRL_GRANT: obtian the permission of global control
|
||||
* @PWM_GLOBAL_CTRL_RECLAIM: reclaim the permission of global control
|
||||
* @PWM_GLOBAL_CTRL_UPDATE: update the configs for all channels in group
|
||||
* @PWM_GLOBAL_CTRL_ENABLE: enable all channels in group
|
||||
* @PWM_GLOBAL_CTRL_DISABLE: disable all channels in group
|
||||
*/
|
||||
enum rockchip_pwm_global_ctrl_cmd {
|
||||
PWM_GLOBAL_CTRL_JOIN,
|
||||
PWM_GLOBAL_CTRL_EXIT,
|
||||
PWM_GLOBAL_CTRL_GRANT,
|
||||
PWM_GLOBAL_CTRL_RECLAIM,
|
||||
PWM_GLOBAL_CTRL_UPDATE,
|
||||
PWM_GLOBAL_CTRL_ENABLE,
|
||||
PWM_GLOBAL_CTRL_DISABLE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_pwm_wave_table - wave table config object
|
||||
* @offset: the offset of wave table to set
|
||||
* @len: the length of wave table to set
|
||||
* @table: the values of wave table to set (in nanoseconds)
|
||||
* @
|
||||
*/
|
||||
struct rockchip_pwm_wave_table {
|
||||
u16 offset;
|
||||
u16 len;
|
||||
u64 *table;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum rockchip_pwm_wave_table_width_mode - element width of pwm wave table
|
||||
* @PWM_WAVE_TABLE_8BITS_WIDTH: each element in table is 8bits
|
||||
* @PWM_WAVE_TABLE_16BITS_WIDTH: each element in table is 16bits
|
||||
*/
|
||||
enum rockchip_pwm_wave_table_width_mode {
|
||||
PWM_WAVE_TABLE_8BITS_WIDTH,
|
||||
PWM_WAVE_TABLE_16BITS_WIDTH,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum rockchip_pwm_wave_update_mode - update mode of wave generator
|
||||
* @PWM_WAVE_INCREASING:
|
||||
* The wave table address will wrap back to minimum address when increase to
|
||||
* maximum and then increase again.
|
||||
* @PWM_WAVE_INCREASING_THEN_DECREASING:
|
||||
* The wave table address will change to decreasing when increasing to the maximum
|
||||
* address. it will return to increasing when decrease to the minimum value.
|
||||
*/
|
||||
enum rockchip_pwm_wave_update_mode {
|
||||
PWM_WAVE_INCREASING,
|
||||
PWM_WAVE_INCREASING_THEN_DECREASING,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_pwm_wave_config - wave generator config object
|
||||
* @duty_table: the wave table config of duty
|
||||
* @period_table: the wave table config of period
|
||||
* @enable: enable or disable wave generator
|
||||
* @duty_en: to update duty by duty table or not
|
||||
* @period_en: to update period by period table or not
|
||||
* @width_mode: the width mode of wave table
|
||||
* @update_mode: the update mode of wave generator
|
||||
* @duty_max: the maximum address of duty table
|
||||
* @duty_min: the minimum address of duty table
|
||||
* @period_max: the maximum address of period table
|
||||
* @period_min: the minimum address of period table
|
||||
* @offset: the initial offset address of duty and period
|
||||
* @middle: the middle address of duty and period
|
||||
* @max_hold: the time to stop at maximum address
|
||||
* @min_hold: the time to stop at minimum address
|
||||
* @middle_hold: the time to stop at middle address
|
||||
*/
|
||||
struct rockchip_pwm_wave_config {
|
||||
struct rockchip_pwm_wave_table *duty_table;
|
||||
struct rockchip_pwm_wave_table *period_table;
|
||||
bool enable;
|
||||
bool duty_en;
|
||||
bool period_en;
|
||||
u16 rpt;
|
||||
u32 width_mode;
|
||||
u32 update_mode;
|
||||
u32 duty_max;
|
||||
u32 duty_min;
|
||||
u32 period_max;
|
||||
u32 period_min;
|
||||
u32 offset;
|
||||
u32 middle;
|
||||
u32 max_hold;
|
||||
u32 min_hold;
|
||||
u32 middle_hold;
|
||||
};
|
||||
|
||||
#if IS_REACHABLE(CONFIG_PWM_ROCKCHIP)
|
||||
/**
|
||||
* rockchip_pwm_set_counter() - setup pwm counter mode
|
||||
* @pwm: PWM device
|
||||
* @enable: enable/disable counter mode
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int rockchip_pwm_set_counter(struct pwm_device *pwm, bool enable);
|
||||
|
||||
/**
|
||||
* rockchip_pwm_get_counter_result() - get counter result
|
||||
* @pwm: PWM device
|
||||
* @counter_res: number of input waveforms
|
||||
* @is_clear: clear counter result or not
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int rockchip_pwm_get_counter_result(struct pwm_device *pwm,
|
||||
unsigned long *counter_res, bool is_clear);
|
||||
|
||||
/**
|
||||
* rockchip_pwm_set_freq_meter() - setup pwm frequency meter mode
|
||||
* @pwm: PWM device
|
||||
* @delay_ms: time to wait, in milliseconds, before getting frequency meter result
|
||||
* @freq_hz: parameter in Hz to fill with frequency meter result
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int rockchip_pwm_set_freq_meter(struct pwm_device *pwm, unsigned long delay_ms,
|
||||
unsigned long *freq_hz);
|
||||
|
||||
/**
|
||||
* rockchip_pwm_global_ctrl() - execute global control commands
|
||||
* @pwm: PWM device
|
||||
* @cmd: command type to execute
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int rockchip_pwm_global_ctrl(struct pwm_device *pwm, enum rockchip_pwm_global_ctrl_cmd cmd);
|
||||
|
||||
/**
|
||||
* rockchip_pwm_set_wave() - setup pwm wave generator mode
|
||||
* @pwm: PWM device
|
||||
* @config: configs of wave generator mode
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int rockchip_pwm_set_wave(struct pwm_device *pwm, struct rockchip_pwm_wave_config *config);
|
||||
#else
|
||||
static inline int rockchip_pwm_set_counter(struct pwm_device *pwm, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rockchip_pwm_get_counter_result(struct pwm_device *pwm,
|
||||
unsigned long *counter_res, bool is_clear)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rockchip_pwm_set_freq_meter(struct pwm_device *pwm, unsigned long delay_ms,
|
||||
unsigned long *freq_hz)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rockchip_pwm_global_ctrl(struct pwm_device *pwm,
|
||||
enum rockchip_pwm_global_ctrl_cmd cmd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int rockchip_pwm_set_wave(struct pwm_device *pwm,
|
||||
struct rockchip_pwm_wave_config *config)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _PWM_ROCKCHIP_H_ */
|
||||
Reference in New Issue
Block a user