/* * drivers/pwm/pwm-sunxi.c * * Allwinnertech pulse-width-modulation controller driver * * Copyright (C) 2015 AllWinner * * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pwm-sunxi-group.h" #define PWM_DEBUG 0 #define PWM_NUM_MAX 4 #define PWM_BIND_NUM 2 #define PWM_PIN_STATE_ACTIVE "active" #define PWM_PIN_STATE_SLEEP "sleep" #define SETMASK(width, shift) ((width?((-1U) >> (32-width)):0) << (shift)) #define CLRMASK(width, shift) (~(SETMASK(width, shift))) #define GET_BITS(shift, width, reg) \ (((reg) & SETMASK(width, shift)) >> (shift)) #define SET_BITS(shift, width, reg, val) \ (((reg) & CLRMASK(width, shift)) | (val << (shift))) #if PWM_DEBUG #define pwm_debug(fmt, arg...) pr_info("%s()%d - "fmt, __func__, __LINE__, ##arg) #else #define pwm_debug(msg...) #endif struct sunxi_pwm_config { unsigned int dead_time; unsigned int bind_pwm; }; struct group_pwm_config { unsigned int group_channel; unsigned int group_run_count; unsigned int pwm_polarity; int pwm_period; }; struct sunxi_pwm_chip { struct pwm_chip chip; void __iomem *base; struct sunxi_pwm_config *config; struct clk *pwm_clk; uint32_t irq; int index; unsigned long cap_time[3]; wait_queue_head_t wait; unsigned int g_channel; unsigned int g_polarity; unsigned int start_count; unsigned int g_period; unsigned int ephy_channel; }; static inline struct sunxi_pwm_chip *to_sunxi_pwm_chip(struct pwm_chip *chip) { return container_of(chip, struct sunxi_pwm_chip, chip); } static inline u32 sunxi_pwm_readl(struct pwm_chip *chip, u32 offset) { struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); u32 value = 0; value = readl(pc->base + offset); return value; } static inline u32 sunxi_pwm_writel(struct pwm_chip *chip, u32 offset, u32 value) { struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); writel(value, pc->base + offset); return 0; } static int sunxi_pwm_pin_set_state(struct device *dev, char *name) { struct pinctrl *pctl; struct pinctrl_state *state; int ret = -1; pctl = pinctrl_get(dev); if (IS_ERR(pctl)) { dev_err(dev, "pinctrl_get failed!\n"); ret = PTR_ERR(pctl); goto exit; } state = pinctrl_lookup_state(pctl, name); if (IS_ERR(state)) { dev_err(dev, "pinctrl_lookup_state(%s) failed!\n", name); ret = PTR_ERR(state); goto exit; } ret = pinctrl_select_state(pctl, state); if (ret < 0) { dev_err(dev, "pinctrl_select_state(%s) failed!\n", name); goto exit; } ret = 0; exit: return ret; } static int sunxi_pwm_get_config(struct platform_device *pdev, struct sunxi_pwm_config *config) { struct device_node *np = pdev->dev.of_node; int ret = 0; ret = of_property_read_u32(np, "bind_pwm", &config->bind_pwm); if (ret < 0) { /*if there is no bind pwm,set 255, dual pwm invalid!*/ config->bind_pwm = 255; ret = 0; } ret = of_property_read_u32(np, "dead_time", &config->dead_time); if (ret < 0) { /*if there is bind pwm, but not set dead time,set bind pwm 255,dual pwm invalid!*/ config->bind_pwm = 255; ret = 0; } of_node_put(np); return ret; } static int sunxi_pwm_get_polarity(struct pwm_chip *chip, int offset) { unsigned int reg_offset; u32 val = 0; reg_offset = PWM_PCR_BASE + offset * PWM_PCR_REG_OFFSET; val = sunxi_pwm_readl(chip, reg_offset); if (val & BIT_MASK(8)) return PWM_POLARITY_NORMAL; else return PWM_POLARITY_INVERSED; } static int sunxi_pwm_set_polarity_single(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity) { u32 temp; unsigned int reg_offset, reg_shift, reg_width; u32 sel = 0; sel = pwm->pwm - chip->base; reg_offset = PWM_PCR_BASE + sel * 0x20; reg_shift = PWM_ACT_STA_SHIFT; reg_width = PWM_ACT_STA_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset); if (polarity == PWM_POLARITY_NORMAL) /* set single polarity*/ temp = SET_BITS(reg_shift, reg_width, temp, 1); else temp = SET_BITS(reg_shift, reg_width, temp, 0); sunxi_pwm_writel(chip, reg_offset, temp); return 0; } static int sunxi_pwm_set_polarity_dual(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity, int bind_num) { u32 temp[2]; unsigned int reg_offset[2], reg_shift[2], reg_width[2]; u32 sel[2] = {0}; sel[0] = pwm->pwm - chip->base; sel[1] = bind_num - chip->base; /* config current pwm*/ reg_offset[0] = PWM_PCR_BASE + sel[0] * 0x20; reg_shift[0] = PWM_ACT_STA_SHIFT; reg_width[0] = PWM_ACT_STA_WIDTH; temp[0] = sunxi_pwm_readl(chip, reg_offset[0]); if (polarity == PWM_POLARITY_NORMAL) temp[0] = SET_BITS(reg_shift[0], 1, temp[0], 1); else temp[0] = SET_BITS(reg_shift[0], 1, temp[0], 0); /* config bind pwm*/ reg_offset[1] = PWM_PCR_BASE + sel[1] * 0x20; reg_shift[1] = PWM_ACT_STA_SHIFT; reg_width[1] = PWM_ACT_STA_WIDTH; temp[1] = sunxi_pwm_readl(chip, reg_offset[1]); /*bind pwm's polarity is reverse compare with the current pwm*/ if (polarity == PWM_POLARITY_NORMAL) temp[1] = SET_BITS(reg_shift[0], 1, temp[1], 1); else temp[1] = SET_BITS(reg_shift[0], 1, temp[1], 0); /*config register at the same time*/ sunxi_pwm_writel(chip, reg_offset[0], temp[0]); sunxi_pwm_writel(chip, reg_offset[1], temp[1]); return 0; } static int sunxi_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity) { int bind_num; struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); bind_num = pc->config[pwm->pwm - chip->base].bind_pwm; if (bind_num == 255) sunxi_pwm_set_polarity_single(chip, pwm, polarity); else sunxi_pwm_set_polarity_dual(chip, pwm, polarity, bind_num); return 0; } static u32 get_pccr_reg_offset(u32 sel, u32 *reg_offset) { switch (sel) { case 0: case 1: *reg_offset = PWM_PCCR01; break; case 2: case 3: *reg_offset = PWM_PCCR23; break; case 4: case 5: *reg_offset = PWM_PCCR45; break; case 6: case 7: *reg_offset = PWM_PCCR67; break; case 8: case 9: *reg_offset = PWM_PCCR89; break; case 10: case 11: *reg_offset = PWM_PCCRAB; break; case 12: case 13: *reg_offset = PWM_PCCRCD; break; case 14: case 15: *reg_offset = PWM_PCCREF; break; default: pr_err("%s:Not supported!\n", __func__); break; } return 0; } static u32 get_pdzcr_reg_offset(u32 sel, u32 *reg_offset) { switch (sel) { case 0: case 1: *reg_offset = PWM_PDZCR01; break; case 2: case 3: *reg_offset = PWM_PDZCR23; break; case 4: case 5: *reg_offset = PWM_PDZCR45; break; case 6: case 7: *reg_offset = PWM_PDZCR67; break; case 8: case 9: *reg_offset = PWM_PDZCR89; break; case 10: case 11: *reg_offset = PWM_PDZCRAB; break; case 12: case 13: *reg_offset = PWM_PDZCRCD; break; case 14: case 15: *reg_offset = PWM_PDZCREF; break; default: pr_err("%s:Not supported!\n", __func__); break; } return 0; } #define PRESCALE_MAX 256 static int sunxi_pwm_config_single(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { unsigned int temp; unsigned long long c = 0; unsigned long entire_cycles = 256, active_cycles = 192; unsigned int reg_offset, reg_shift, reg_width; unsigned int reg_bypass_shift/*, group_reg_offset*/; unsigned int reg_clk_src_shift, reg_clk_src_width; unsigned int reg_div_m_shift, reg_div_m_width, value; unsigned int pre_scal_id = 0, div_m = 0, prescale = 0; u32 sel = 0; u32 pre_scal[][2] = { /* reg_value clk_pre_div */ {0, 1}, {1, 2}, {2, 4}, {3, 8}, {4, 16}, {5, 32}, {6, 64}, {7, 128}, {8, 256}, }; struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); unsigned int pwm_run_count = 0; if (pwm->chip_data) { pwm_run_count = ((struct group_pwm_config *)pwm->chip_data)->group_run_count; pc->g_channel = ((struct group_pwm_config *)pwm->chip_data)->group_channel; pc->g_polarity = ((struct group_pwm_config *)pwm->chip_data)->pwm_polarity; pc->g_period = ((struct group_pwm_config *) pwm->chip_data)->pwm_period; } if (pc->g_channel) { value = sunxi_pwm_readl(chip, PWM_PER); value &= ~((0xf) << 4*(pc->g_channel - 1)); sunxi_pwm_writel(chip, PWM_PER, value); // group_reg_offset = PGR0 + 0x04 * (pc->g_channel - 1); // reg_shift = PWMG_START_SHIFT; // value = sunxi_pwm_readl(chip, group_reg_offset); // sunxi_pwm_writel(chip, group_reg_offset, value); } sel = pwm->pwm - chip->base; get_pccr_reg_offset(sel, ®_offset); /*src clk reg*/ reg_clk_src_shift = PWM_CLK_SRC_SHIFT; reg_clk_src_width = PWM_CLK_SRC_WIDTH; if (pc->g_channel) { /* group_mode used the apb1 clk*/ temp = sunxi_pwm_readl(chip, reg_offset); temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 0); sunxi_pwm_writel(chip, reg_offset, temp); } else { if (period_ns > 0 && period_ns <= 10) { /* if freq lt 100M, then direct output 100M clock,set by pass. */ c = 100000000; reg_bypass_shift = sel; temp = sunxi_pwm_readl(chip, PCGR); temp = SET_BITS(reg_bypass_shift, 1, temp, 1); /* bypass set */ sunxi_pwm_writel(chip, PCGR, temp); /*clk_src_reg*/ temp = sunxi_pwm_readl(chip, reg_offset); temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 1);/*clock source*/ sunxi_pwm_writel(chip, reg_offset, temp); return 0; } else if (period_ns > 10 && period_ns <= 334) { /* if freq between 3M~100M, then select 100M as clock */ c = 100000000; /*clk_src_reg*/ temp = sunxi_pwm_readl(chip, reg_offset); temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 1); sunxi_pwm_writel(chip, reg_offset, temp); } else if (period_ns > 334) { /* if freq < 3M, then select 24M clock */ c = 24000000; /*clk_src_reg*/ temp = sunxi_pwm_readl(chip, reg_offset); temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 0); sunxi_pwm_writel(chip, reg_offset, temp); } pwm_debug("duty_ns=%d period_ns=%d c =%llu.\n", duty_ns, period_ns, c); c = c * period_ns; do_div(c, 1000000000); entire_cycles = (unsigned long)c; for (pre_scal_id = 0; pre_scal_id < 9; pre_scal_id++) { if (entire_cycles <= 65536) break; for (prescale = 0; prescale < PRESCALE_MAX+1; prescale++) { entire_cycles = ((unsigned long)c/ pre_scal[pre_scal_id][1])/ (prescale + 1); if (entire_cycles <= 65536) { div_m = pre_scal[pre_scal_id][0]; break; } } } c = (unsigned long long)entire_cycles * duty_ns; do_div(c, period_ns); active_cycles = c; if (entire_cycles == 0) entire_cycles++; } /* config clk div_m*/ reg_div_m_shift = PWM_DIV_M_SHIFT; reg_div_m_width = PWM_DIV_M_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset); if (pc->g_channel) temp = SET_BITS(reg_div_m_shift, reg_div_m_width, temp, 0); else temp = SET_BITS(reg_div_m_shift, reg_div_m_width, temp, div_m); sunxi_pwm_writel(chip, reg_offset, temp); if (pc->ephy_channel > 0) { /* * Init pwm channel as ephy clk * Open pwm channel bit bypass and bit gate */ value = sunxi_pwm_readl(chip, PCGR); value |= BIT(pc->ephy_channel) << 16 | BIT(pc->ephy_channel); sunxi_pwm_writel(chip, PCGR, value); } /* config prescal */ reg_offset = PWM_PCR_BASE + 0x20 * sel; reg_shift = PWM_PRESCAL_SHIFT; reg_width = PWM_PRESCAL_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset); if (pc->g_channel) temp = SET_BITS(reg_shift, reg_width, temp, 0xef); else temp = SET_BITS(reg_shift, reg_width, temp, prescale); sunxi_pwm_writel(chip, reg_offset, temp); if (pc->g_channel) { /* group set */ reg_offset = PGR0 + 0x04 * (pc->g_channel - 1); reg_shift = sel; reg_width = 1; temp = sunxi_pwm_readl(chip, reg_offset); temp = SET_BITS(reg_shift, reg_width, temp, 1); /* set group0_cs */ sunxi_pwm_writel(chip, reg_offset, temp); /* pwm pulse mode */ reg_offset = PWM_PCR_BASE + sel * 0x20; reg_shift = PWM_MODE_ACTS_SHIFT; reg_width = PWM_MODE_ACTS_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset); temp = SET_BITS(reg_shift, reg_width, temp, 0x3); /* pwm pulse mode and active */ /* pwm output pulse num */ reg_shift = PWM_PUL_NUM_SHIFT; reg_width = PWM_PUL_NUM_WIDTH; temp = SET_BITS(reg_shift, reg_width, temp, pwm_run_count); /* pwm output pulse num */ sunxi_pwm_writel(chip, reg_offset, temp); } /* config active cycles */ reg_offset = PWM_PPR_BASE + 0x20 * sel; reg_shift = PWM_ACT_CYCLES_SHIFT; reg_width = PWM_ACT_CYCLES_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset); if (pc->g_channel) temp = SET_BITS(reg_shift, reg_width, temp, (unsigned int)(pc->g_period*3/8)); else temp = SET_BITS(reg_shift, reg_width, temp, active_cycles); sunxi_pwm_writel(chip, reg_offset, temp); /* config period cycles */ reg_offset = PWM_PPR_BASE + 0x20 * sel; reg_shift = PWM_PERIOD_CYCLES_SHIFT; reg_width = PWM_PERIOD_CYCLES_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset); if (pc->g_channel) { temp = SET_BITS(reg_shift, reg_width, temp, pc->g_period); pc->g_channel = 0; } else temp = SET_BITS(reg_shift, reg_width, temp, (entire_cycles - 1)); sunxi_pwm_writel(chip, reg_offset, temp); pwm_debug("active_cycles=%lu entire_cycles=%lu prescale=%u div_m=%u\n", active_cycles, entire_cycles, prescale, div_m); return 0; } static int sunxi_pwm_config_dual(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns, int bind_num) { u32 value[2] = {0}; unsigned int temp; unsigned long long c = 0, clk = 0, clk_temp = 0; unsigned long entire_cycles = 256, active_cycles = 192; unsigned int reg_offset[2], reg_shift[2], reg_width[2]; unsigned int reg_bypass_shift; unsigned int reg_dz_en_offset[2], reg_dz_en_shift[2], reg_dz_en_width[2]; unsigned int pre_scal_id = 0, div_m = 0, prescale = 0; int src_clk_sel = 0; int i = 0; unsigned int dead_time = 0, duty = 0; u32 pre_scal[][2] = { /* reg_value clk_pre_div */ {0, 1}, {1, 2}, {2, 4}, {3, 8}, {4, 16}, {5, 32}, {6, 64}, {7, 128}, {8, 256}, }; unsigned int pwm_index[2] = {0}; struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); pwm_index[0] = pwm->pwm - chip->base; pwm_index[1] = bind_num - chip->base; /* if duty time < dead time,it is wrong. */ dead_time = pc->config[pwm_index[0]].dead_time; duty = (unsigned int)duty_ns; /* judge if the pwm eanble dead zone */ get_pdzcr_reg_offset(pwm_index[0], ®_dz_en_offset[0]); reg_dz_en_shift[0] = PWM_DZ_EN_SHIFT; reg_dz_en_width[0] = PWM_DZ_EN_WIDTH; value[0] = sunxi_pwm_readl(chip, reg_dz_en_offset[0]); value[0] = SET_BITS(reg_dz_en_shift[0], reg_dz_en_width[0], value[0], 1); sunxi_pwm_writel(chip, reg_dz_en_offset[0], value[0]); temp = sunxi_pwm_readl(chip, reg_dz_en_offset[0]); temp &= (1u << reg_dz_en_shift[0]); if (duty < dead_time || temp == 0) { pr_err("[PWM]duty time or dead zone error.\n"); return -EINVAL; } for (i = 0; i < PWM_BIND_NUM; i++) { if ((i % 2) == 0) reg_bypass_shift = 0x5; else reg_bypass_shift = 0x6; get_pccr_reg_offset(pwm_index[i], ®_offset[i]); reg_shift[i] = reg_bypass_shift; reg_width[i] = PWM_BYPASS_WIDTH; } if (period_ns > 0 && period_ns <= 10) { /* if freq lt 100M, then direct output 100M clock,set by pass */ clk = 100000000; src_clk_sel = 1; /* config the two pwm bypass */ for (i = 0; i < PWM_BIND_NUM; i++) { temp = sunxi_pwm_readl(chip, reg_offset[i]); temp = SET_BITS(reg_shift[i], reg_width[i], temp, 1); sunxi_pwm_writel(chip, reg_offset[i], temp); reg_shift[i] = PWM_CLK_SRC_SHIFT; reg_width[i] = PWM_CLK_SRC_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset[i]); temp = SET_BITS(reg_shift[i], reg_width[i], temp, 1); sunxi_pwm_writel(chip, reg_offset[i], temp); } return 0; } else if (period_ns > 10 && period_ns <= 334) { clk = 100000000; src_clk_sel = 1; } else if (period_ns > 334) { /* if freq < 3M, then select 24M clock */ clk = 24000000; src_clk_sel = 0; } for (i = 0; i < PWM_BIND_NUM; i++) { reg_shift[i] = PWM_CLK_SRC_SHIFT; reg_width[i] = PWM_CLK_SRC_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset[i]); temp = SET_BITS(reg_shift[i], reg_width[i], temp, src_clk_sel); sunxi_pwm_writel(chip, reg_offset[i], temp); } c = clk; c *= period_ns; do_div(c, 1000000000); entire_cycles = (unsigned long)c; /* get div_m and prescale,which satisfy: deat_val <= 256, entire <= 65536 */ for (pre_scal_id = 0; pre_scal_id < 9; pre_scal_id++) { for (prescale = 0; prescale < PRESCALE_MAX+1; prescale++) { entire_cycles = ((unsigned long)c/ pre_scal[pre_scal_id][1])/(prescale + 1); clk_temp = clk; do_div(clk_temp, pre_scal[pre_scal_id][1] * (prescale + 1)); clk_temp *= dead_time; do_div(clk_temp, 1000000000); if (entire_cycles <= 65536 && clk_temp <= 256) { div_m = pre_scal[pre_scal_id][0]; break; } } if (entire_cycles <= 65536 && clk_temp <= 256) break; else { pr_err("%s:config dual err.entire_cycles=%lu, dead_zone_val=%llu", __func__, entire_cycles, clk_temp); return -EINVAL; } } c = (unsigned long long)entire_cycles * duty_ns; do_div(c, period_ns); active_cycles = c; if (entire_cycles == 0) entire_cycles++; /* config clk div_m*/ for (i = 0; i < PWM_BIND_NUM; i++) { reg_shift[i] = PWM_DIV_M_SHIFT; reg_width[i] = PWM_DIV_M_SHIFT; temp = sunxi_pwm_readl(chip, reg_offset[i]); temp = SET_BITS(reg_shift[i], reg_width[i], temp, div_m); sunxi_pwm_writel(chip, reg_offset[i], temp); } /* config prescal */ for (i = 0; i < PWM_BIND_NUM; i++) { reg_offset[i] = PWM_PCR_BASE + 0x20 * pwm_index[i]; reg_shift[i] = PWM_PRESCAL_SHIFT; reg_width[i] = PWM_PRESCAL_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset[i]); temp = SET_BITS(reg_shift[i], reg_width[i], temp, prescale); sunxi_pwm_writel(chip, reg_offset[i], temp); } /* config active cycles */ for (i = 0; i < PWM_BIND_NUM; i++) { reg_offset[i] = PWM_PPR_BASE + 0x20 * pwm_index[i]; reg_shift[i] = PWM_ACT_CYCLES_SHIFT; reg_width[i] = PWM_ACT_CYCLES_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset[i]); temp = SET_BITS(reg_shift[i], reg_width[i], temp, active_cycles); sunxi_pwm_writel(chip, reg_offset[i], temp); } /* config period cycles */ for (i = 0; i < PWM_BIND_NUM; i++) { reg_offset[i] = PWM_PPR_BASE + 0x20 * pwm_index[i]; reg_shift[i] = PWM_PERIOD_CYCLES_SHIFT; reg_width[i] = PWM_PERIOD_CYCLES_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset[i]); temp = SET_BITS(reg_shift[i], reg_width[i], temp, (entire_cycles - 1)); sunxi_pwm_writel(chip, reg_offset[i], temp); } pwm_debug("active_cycles=%lu entire_cycles=%lu prescale=%u div_m=%u\n", active_cycles, entire_cycles, prescale, div_m); /* config dead zone, one config for two pwm */ reg_offset[0] = reg_dz_en_offset[0]; reg_shift[0] = PWM_PDZINTV_SHIFT; reg_width[0] = PWM_PDZINTV_WIDTH; temp = sunxi_pwm_readl(chip, reg_offset[0]); temp = SET_BITS(reg_shift[0], reg_width[0], temp, (unsigned int)clk_temp); sunxi_pwm_writel(chip, reg_offset[0], temp); return 0; } static int sunxi_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { int bind_num; struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); bind_num = pc->config[pwm->pwm - chip->base].bind_pwm; if (bind_num == 255) sunxi_pwm_config_single(chip, pwm, duty_ns, period_ns); else sunxi_pwm_config_dual(chip, pwm, duty_ns, period_ns, bind_num); return 0; } static int sunxi_pwm_enable_single(struct pwm_chip *chip, struct pwm_device *pwm) { unsigned int value = 0, index = 0; unsigned int reg_offset, reg_shift, reg_width, group_reg_offset; unsigned int temp; struct device_node *sub_np; struct platform_device *pwm_pdevice; static unsigned int enable_num; unsigned int pwm_start_count, i; int pwm_period = 0; int ret = 0; struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); index = pwm->pwm - chip->base; sub_np = of_parse_phandle(chip->dev->of_node, "pwms", index); if (IS_ERR_OR_NULL(sub_np)) { pr_err("%s: can't parse \"pwms\" property\n", __func__); return -ENODEV; } pwm_pdevice = of_find_device_by_node(sub_np); if (IS_ERR_OR_NULL(pwm_pdevice)) { pr_err("%s: can't parse pwm device\n", __func__); return -ENODEV; } ret = sunxi_pwm_pin_set_state(&pwm_pdevice->dev, PWM_PIN_STATE_ACTIVE); if (ret != 0) return ret; if (pwm->chip_data) { pc->g_channel = ((struct group_pwm_config *)pwm->chip_data)->group_channel; pwm_period = ((struct group_pwm_config *) pwm->chip_data)->pwm_period; } #if 0 else { pr_err("%s: can't get chip data\n", __func__); return -ENODATA; } #endif if (pc->g_channel) enable_num++; /* enable pwm controller pwm can be used */ if (!pc->g_channel) { reg_offset = PWM_PER; reg_shift = index; value = sunxi_pwm_readl(chip, reg_offset); value = SET_BITS(reg_shift, 1, value, 1); sunxi_pwm_writel(chip, reg_offset, value); reg_offset = PCGR; reg_shift = index; reg_width = 0x1; value = sunxi_pwm_readl(chip, reg_offset); value = SET_BITS(reg_shift, reg_width, value, 1); sunxi_pwm_writel(chip, reg_offset, value); } if (pc->g_channel && enable_num == 4) { if (pc->g_polarity) pwm_start_count = (unsigned int)pwm_period*6/8; else pwm_start_count = 0; for (i = 4*(pc->g_channel - 1); i < 4*pc->g_channel; i++) { /* start count set */ reg_offset = PWM_PCNTR_BASE + 0x20 * i; reg_shift = PWM_COUNTER_START_SHIFT; reg_width = PWM_COUNTER_START_WIDTH; temp = pwm_start_count << reg_shift; sunxi_pwm_writel(chip, reg_offset, temp); if (pc->g_polarity) pwm_start_count = pwm_start_count - ((unsigned int)pwm_period*2/8); else pwm_start_count = pwm_start_count + ((unsigned int)pwm_period*2/8); } reg_offset = PWM_PER; reg_shift = index; value = sunxi_pwm_readl(chip, reg_offset); value |= ((0xf) << 4*(pc->g_channel - 1)); sunxi_pwm_writel(chip, reg_offset, value); group_reg_offset = PGR0 + 0x04 * (pc->g_channel - 1); enable_num = 0; pwm_start_count = 0; /* group en and start */ reg_shift = PWMG_EN_SHIFT; value = sunxi_pwm_readl(chip, group_reg_offset); value = SET_BITS(reg_shift, 1, value, 1);/* enable group0 enable */ sunxi_pwm_writel(chip, group_reg_offset, value); reg_shift = PWMG_START_SHIFT; value = sunxi_pwm_readl(chip, group_reg_offset); value = SET_BITS(reg_shift, 1, value, 1);/* group0 start */ sunxi_pwm_writel(chip, group_reg_offset, value); pc->g_channel = 0; } return 0; } static int sunxi_pwm_enable_dual(struct pwm_chip *chip, struct pwm_device *pwm, int bind_num) { u32 value[2] = {0}; unsigned int reg_offset[2], reg_shift[2], reg_width[2]; struct device_node *sub_np[2]; struct platform_device *pwm_pdevice[2]; int i = 0, ret = 0; unsigned int pwm_index[2] = {0}; pwm_index[0] = pwm->pwm - chip->base; pwm_index[1] = bind_num - chip->base; /*set current pwm pin state*/ sub_np[0] = of_parse_phandle(chip->dev->of_node, "pwms", pwm_index[0]); if (IS_ERR_OR_NULL(sub_np[0])) { pr_err("%s: can't parse \"pwms\" property\n", __func__); return -ENODEV; } pwm_pdevice[0] = of_find_device_by_node(sub_np[0]); if (IS_ERR_OR_NULL(pwm_pdevice[0])) { pr_err("%s: can't parse pwm device\n", __func__); return -ENODEV; } /*set bind pwm pin state*/ sub_np[1] = of_parse_phandle(chip->dev->of_node, "pwms", pwm_index[1]); if (IS_ERR_OR_NULL(sub_np[1])) { pr_err("%s: can't parse \"pwms\" property\n", __func__); return -ENODEV; } pwm_pdevice[1] = of_find_device_by_node(sub_np[1]); if (IS_ERR_OR_NULL(pwm_pdevice[1])) { pr_err("%s: can't parse pwm device\n", __func__); return -ENODEV; } ret = sunxi_pwm_pin_set_state(&pwm_pdevice[0]->dev, PWM_PIN_STATE_ACTIVE); if (ret != 0) return ret; ret = sunxi_pwm_pin_set_state(&pwm_pdevice[1]->dev, PWM_PIN_STATE_ACTIVE); if (ret != 0) return ret; /* enable clk for pwm controller */ for (i = 0; i < PWM_BIND_NUM; i++) { get_pccr_reg_offset(pwm_index[i], ®_offset[i]); reg_shift[i] = PWM_CLK_GATING_SHIFT; reg_width[i] = PWM_CLK_GATING_WIDTH; value[i] = sunxi_pwm_readl(chip, reg_offset[i]); value[i] = SET_BITS(reg_shift[i], reg_width[i], value[i], 1); sunxi_pwm_writel(chip, reg_offset[i], value[i]); } /* enable pwm controller */ for (i = 0; i < PWM_BIND_NUM; i++) { reg_offset[i] = PWM_PER; reg_shift[i] = pwm_index[i]; reg_width[i] = 0x1; value[i] = sunxi_pwm_readl(chip, reg_offset[i]); value[i] = SET_BITS(reg_shift[i], reg_width[i], value[i], 1); sunxi_pwm_writel(chip, reg_offset[i], value[i]); } return 0; } static int sunxi_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { int bind_num; int ret = 0; struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); bind_num = pc->config[pwm->pwm - chip->base].bind_pwm; if (bind_num == 255) ret = sunxi_pwm_enable_single(chip, pwm); else ret = sunxi_pwm_enable_dual(chip, pwm, bind_num); return ret; } static void sunxi_pwm_disable_single(struct pwm_chip *chip, struct pwm_device *pwm) { u32 value = 0, index = 0; unsigned int reg_offset, reg_shift, reg_width, group_reg_offset; struct device_node *sub_np; struct platform_device *pwm_pdevice; static int disable_num; struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); index = pwm->pwm - chip->base; if (pwm->chip_data) { pc->g_channel = ((struct group_pwm_config *)pwm->chip_data)->group_channel; } /* disable pwm controller */ if (pc->g_channel) { if (disable_num == 0) { reg_offset = PWM_PER; reg_width = 0x4; value = sunxi_pwm_readl(chip, reg_offset); value &= ~((0xf) << 4*(pc->g_channel - 1)); sunxi_pwm_writel(chip, reg_offset, value); reg_offset = PCGR; reg_shift = index; reg_width = 0x1; value = sunxi_pwm_readl(chip, reg_offset); value &= ~((0xf) << 4*(pc->g_channel - 1)); // value = SET_BITS(reg_shift, reg_width, value, 0); sunxi_pwm_writel(chip, reg_offset, value); } } else { reg_offset = PWM_PER; reg_shift = index; reg_width = 0x1; value = sunxi_pwm_readl(chip, reg_offset); value = SET_BITS(reg_shift, reg_width, value, 0); sunxi_pwm_writel(chip, reg_offset, value); reg_offset = PCGR; reg_shift = index; reg_width = 0x1; value = sunxi_pwm_readl(chip, reg_offset); value = SET_BITS(reg_shift, reg_width, value, 0); sunxi_pwm_writel(chip, reg_offset, value); } if (pc->g_channel) disable_num++; // if (disable_num >= 4) // disable_num == 0; /* disable clk gating for pwm controller. */ /* reg_offset = PCGR; reg_shift = index; reg_width = 0x1; value = sunxi_pwm_readl(chip, reg_offset); value = SET_BITS(reg_shift, reg_width, value, 0); sunxi_pwm_writel(chip, reg_offset, value);*/ sub_np = of_parse_phandle(chip->dev->of_node, "pwms", index); if (IS_ERR_OR_NULL(sub_np)) { pr_err("%s: can't parse \"pwms\" property\n", __func__); return; } pwm_pdevice = of_find_device_by_node(sub_np); if (IS_ERR_OR_NULL(pwm_pdevice)) { pr_err("%s: can't parse pwm device\n", __func__); return; } sunxi_pwm_pin_set_state(&pwm_pdevice->dev, PWM_PIN_STATE_SLEEP); if (pc->g_channel) { group_reg_offset = PGR0 + 0x04 * (pc->g_channel - 1); /* group end */ reg_shift = PWMG_START_SHIFT; value = sunxi_pwm_readl(chip, group_reg_offset); value = SET_BITS(reg_shift, 1, value, 0);/* group end */ sunxi_pwm_writel(chip, group_reg_offset, value); /* group disable */ reg_shift = PWMG_EN_SHIFT; value = sunxi_pwm_readl(chip, group_reg_offset); value = SET_BITS(reg_shift, 1, value, 0);/* group disable */ sunxi_pwm_writel(chip, group_reg_offset, value); pc->g_channel = 0; } } static void sunxi_pwm_disable_dual(struct pwm_chip *chip, struct pwm_device *pwm, int bind_num) { u32 value[2] = {0}; unsigned int reg_offset[2], reg_shift[2], reg_width[2]; struct device_node *sub_np[2]; struct platform_device *pwm_pdevice[2]; int i = 0; unsigned int pwm_index[2] = {0}; pwm_index[0] = pwm->pwm - chip->base; pwm_index[1] = bind_num - chip->base; /* get current index pwm device */ sub_np[0] = of_parse_phandle(chip->dev->of_node, "pwms", pwm_index[0]); if (IS_ERR_OR_NULL(sub_np[0])) { pr_err("%s: can't parse \"pwms\" property\n", __func__); return; } pwm_pdevice[0] = of_find_device_by_node(sub_np[0]); if (IS_ERR_OR_NULL(pwm_pdevice[0])) { pr_err("%s: can't parse pwm device\n", __func__); return; } /* get bind pwm device */ sub_np[1] = of_parse_phandle(chip->dev->of_node, "pwms", pwm_index[1]); if (IS_ERR_OR_NULL(sub_np[1])) { pr_err("%s: can't parse \"pwms\" property\n", __func__); return; } pwm_pdevice[1] = of_find_device_by_node(sub_np[1]); if (IS_ERR_OR_NULL(pwm_pdevice[1])) { pr_err("%s: can't parse pwm device\n", __func__); return; } /* disable pwm controller */ for (i = 0; i < PWM_BIND_NUM; i++) { reg_offset[i] = PWM_PER; reg_shift[i] = pwm_index[i]; reg_width[i] = 0x1; value[i] = sunxi_pwm_readl(chip, reg_offset[i]); value[i] = SET_BITS(reg_shift[i], reg_width[i], value[i], 0); sunxi_pwm_writel(chip, reg_offset[i], value[i]); } /* disable pwm clk gating */ for (i = 0; i < PWM_BIND_NUM; i++) { get_pccr_reg_offset(pwm_index[i], ®_offset[i]); reg_shift[i] = PWM_CLK_GATING_SHIFT; reg_width[i] = 0x1; value[i] = sunxi_pwm_readl(chip, reg_offset[i]); value[i] = SET_BITS(reg_shift[i], reg_width[i], value[i], 0); sunxi_pwm_writel(chip, reg_offset[i], value[i]); } /* disable pwm dead zone,one for the two pwm */ get_pdzcr_reg_offset(pwm_index[0], ®_offset[0]); reg_shift[0] = PWM_DZ_EN_SHIFT; reg_width[0] = PWM_DZ_EN_WIDTH; value[0] = sunxi_pwm_readl(chip, reg_offset[0]); value[0] = SET_BITS(reg_shift[0], reg_width[0], value[0], 0); sunxi_pwm_writel(chip, reg_offset[0], value[0]); /* config pin sleep */ sunxi_pwm_pin_set_state(&pwm_pdevice[0]->dev, PWM_PIN_STATE_SLEEP); sunxi_pwm_pin_set_state(&pwm_pdevice[1]->dev, PWM_PIN_STATE_SLEEP); } static void sunxi_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { int bind_num; struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); bind_num = pc->config[pwm->pwm - chip->base].bind_pwm; if (bind_num == 255) sunxi_pwm_disable_single(chip, pwm); else sunxi_pwm_disable_dual(chip, pwm, bind_num); } /* default: 24MHz * max input pwm: high_time and low_time < 2.7ms. * becase of 1/24M * 65535 = 2.7ms */ static int sunxi_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_capture *result, unsigned long timeout) { struct sunxi_pwm_chip *pc = to_sunxi_pwm_chip(chip); unsigned long long pwm_clk = 0, temp_clk; struct device_node *sub_np; unsigned int reg_offset, pwm_div, temp; struct platform_device *pwm_pdevice; int ret, index = pwm->pwm - chip->base; u32 pre_scal[][2] = { /* reg_value clk_pre_div */ {0, 1}, {1, 2}, {2, 4}, {3, 8}, {4, 16}, {5, 32}, {6, 64}, {7, 128}, {8, 256}, }; pc->index = 0; sub_np = of_parse_phandle(chip->dev->of_node, "pwms", index); if (IS_ERR_OR_NULL(sub_np)) { pr_err("%s: can't parse \"pwms\" property\n", __func__); return -ENODEV; } pwm_pdevice = of_find_device_by_node(sub_np); if (IS_ERR_OR_NULL(pwm_pdevice)) { pr_err("%s: can't parse pwm device\n", __func__); return -ENODEV; } sunxi_pwm_pin_set_state(&pwm_pdevice->dev, PWM_PIN_STATE_ACTIVE); /* enable clk for pwm controller */ temp = sunxi_pwm_readl(chip, PCGR); temp = SET_BITS(index, 1, temp, 1);/* set gating */ sunxi_pwm_writel(chip, PCGR, temp); /* enable rise&fail interrupt */ temp = sunxi_pwm_readl(chip, PWM_CIER); temp = SET_BITS(index * 0x2, 0x2, temp, 0x3); sunxi_pwm_writel(chip, PWM_CIER, temp); /* Enable capture */ temp = sunxi_pwm_readl(chip, PWM_CER); temp = SET_BITS(index, 0x1, temp, 0x1); sunxi_pwm_writel(chip, PWM_CER, temp); /* enabled rising edge trigger */ sunxi_pwm_writel(chip, PWM_CCR_BASE + index * 0x20, PWM_CAPTURE_CRTE | PWM_CAPTURE_CRLF); ret = wait_event_interruptible_timeout(pc->wait, (pc->index >= 0x2) ? 1:0, msecs_to_jiffies(timeout)); if (ret == 0) { pr_err("%s: capture pwm timeout!\n", __func__); return -1; } get_pccr_reg_offset(index, ®_offset); temp = sunxi_pwm_readl(chip, reg_offset); pwm_div = pre_scal[temp & (0x000f)][1]; if (temp & (0x01 << PWM_CLK_SRC_SHIFT)) pwm_clk = 100;//100M else pwm_clk = 24;//24M temp_clk = (pc->cap_time[1] + pc->cap_time[2]) * 1000 * pwm_div; do_div(temp_clk, pwm_clk); result->period = (unsigned int)temp_clk; temp_clk = pc->cap_time[1] * 1000 * pwm_div; do_div(temp_clk, pwm_clk); result->duty_cycle = (unsigned int)temp_clk; /* disable rise&fail interrupt */ temp = sunxi_pwm_readl(chip, PWM_CIER); temp = SET_BITS(index * 0x2, 0x2, temp, 0x0); sunxi_pwm_writel(chip, PWM_CIER, temp); temp = sunxi_pwm_readl(chip, PCGR); temp = SET_BITS(index, 1, temp, 0);/* set gating */ sunxi_pwm_writel(chip, PCGR, temp); sunxi_pwm_pin_set_state(&pwm_pdevice->dev, PWM_PIN_STATE_SLEEP); return 0; } static void sunxi_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { unsigned int reg_offset; u32 val, sel; sel = pwm->pwm - chip->base; reg_offset = PWM_PCR_BASE + sel * PWM_PCR_REG_OFFSET; val = sunxi_pwm_readl(chip, reg_offset); if (val & BIT_MASK(8)) state->polarity = PWM_POLARITY_NORMAL; else state->polarity = PWM_POLARITY_INVERSED; } static struct pwm_ops sunxi_pwm_ops = { .config = sunxi_pwm_config, .enable = sunxi_pwm_enable, .disable = sunxi_pwm_disable, .set_polarity = sunxi_pwm_set_polarity, .capture = sunxi_pwm_capture, .get_state = sunxi_pwm_get_state, .owner = THIS_MODULE, }; static irqreturn_t sunxi_pwm_interrupt(int irq, void *dev_id) { struct sunxi_pwm_chip *pwm = (struct sunxi_pwm_chip *)dev_id; struct pwm_chip *chip = &(pwm->chip); unsigned int device_num; unsigned int temp = 0; /* Clean capture rise status*/ temp = sunxi_pwm_readl(chip, PWM_CISR); sunxi_pwm_writel(chip, PWM_CISR, temp); /* * 0 , 1 --> 0/2 * 2 , 3 --> 2/2 * 4 , 5 --> 4/2 * 6 , 7 --> 6/2 */ device_num = ((ffs(temp) - 1) & (~(0x01)))/2; /* * Capture input: * _______ _______ * | | | | * ________| |_____________| |________ * index ^0 ^1 ^2 * * Capture start by the first available rising edge. * */ switch (pwm->index) { case 0: pwm->cap_time[pwm->index] = sunxi_pwm_readl(chip, PWM_CRLR_BASE + device_num * 0x20); /* clean capture CRLF and enabled fail interrupt */ sunxi_pwm_writel(chip, PWM_CCR_BASE + device_num * 0x20, 0x1E); break; case 1: pwm->cap_time[pwm->index] = sunxi_pwm_readl(chip, PWM_CFLR_BASE + device_num * 0x20); /* clean capture CFLF and disabled fail interrupt */ sunxi_pwm_writel(chip, PWM_CCR_BASE + device_num * 0x20, 0x1C); break; case 2: pwm->cap_time[pwm->index] = sunxi_pwm_readl(chip, PWM_CRLR_BASE + device_num * 0x20); /* clean capture CRLF and disabled rise interrupt */ sunxi_pwm_writel(chip, PWM_CCR_BASE + device_num * 0x20, 0x18); wake_up(&pwm->wait); break; default: break; } pwm->index++; return IRQ_HANDLED; } static int sunxi_pwm_probe(struct platform_device *pdev) { int ret; struct sunxi_pwm_chip *pwm; struct device_node *np = pdev->dev.of_node; int i; struct platform_device *pwm_pdevice; struct device_node *sub_np; pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); if (!pwm) { dev_err(&pdev->dev, "failed to allocate memory!\n"); return -ENOMEM; } /* io map pwm base */ pwm->base = (void __iomem *)of_iomap(pdev->dev.of_node, 0); if (!pwm->base) { dev_err(&pdev->dev, "unable to map pwm registers\n"); ret = -EINVAL; goto err_iomap; } /* read property pwm-number */ ret = of_property_read_u32(np, "pwm-number", &pwm->chip.npwm); if (ret < 0) { dev_err(&pdev->dev, "failed to get pwm number: %d, force to one!\n", ret); /* force to one pwm if read property fail */ pwm->chip.npwm = 1; goto err_iomap; } /* read property ephy-channel */ ret = of_property_read_u32(np, "ephy-channel", &pwm->ephy_channel); if (ret < 0) { dev_dbg(&pdev->dev, "failed to get ephy-channel: %d, force to -1 !\n", ret); /* force to one pwm if read property fail */ pwm->ephy_channel = -1; } /* read property pwm-base */ ret = of_property_read_u32(np, "pwm-base", &pwm->chip.base); if (ret < 0) { dev_err(&pdev->dev, "failed to get pwm-base: %d, force to -1 !\n", ret); /* force to one pwm if read property fail */ pwm->chip.base = -1; } pwm->chip.dev = &pdev->dev; pwm->chip.ops = &sunxi_pwm_ops; pwm->chip.of_xlate = of_pwm_xlate_with_flags; pwm->chip.of_pwm_n_cells = 3; /* add pwm chip to pwm-core */ ret = pwmchip_add(&pwm->chip); if (ret < 0) { dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); goto err_add; } platform_set_drvdata(pdev, pwm); pwm->config = devm_kzalloc(&pdev->dev, sizeof(*pwm->config) * pwm->chip.npwm, GFP_KERNEL); if (!pwm->config) { dev_err(&pdev->dev, "failed to allocate memory!\n"); goto err_alloc; } for (i = 0; i < pwm->chip.npwm; i++) { sub_np = of_parse_phandle(np, "pwms", i); if (IS_ERR_OR_NULL(sub_np)) { pr_err("%s: can't parse \"pwms\" property\n", __func__); return -EINVAL; } pwm_pdevice = of_find_device_by_node(sub_np); /* it may be the program is error or the status of pwm%d is disabled */ if (!pwm_pdevice) { pr_debug("%s:fail to find device for pwm%d, continue!\n", __func__, i); continue; } ret = sunxi_pwm_get_config(pwm_pdevice, &pwm->config[i]); if (ret) { pr_err("Get config failed,exit!\n"); goto err_get_config; } } pwm->pwm_clk = of_clk_get(pdev->dev.of_node, 0); if (IS_ERR_OR_NULL(pwm->pwm_clk)) { pr_err("%s: can't get pwm clk\n", __func__); return -EINVAL; } clk_prepare_enable(pwm->pwm_clk); pwm->irq = platform_get_irq(pdev, 0); if (pwm->irq > 0) { init_waitqueue_head(&pwm->wait); ret = request_irq(pwm->irq, sunxi_pwm_interrupt, IRQF_TRIGGER_NONE, "pwm", pwm); } return 0; err_get_config: err_alloc: pwmchip_remove(&pwm->chip); err_add: iounmap(pwm->base); err_iomap: return ret; } static int sunxi_pwm_remove(struct platform_device *pdev) { struct sunxi_pwm_chip *pwm = platform_get_drvdata(pdev); clk_disable(pwm->pwm_clk); return pwmchip_remove(&pwm->chip); } #ifdef CONFIG_PM static int sunxi_pwm_suspend(struct device *dev) { int i = 0; bool pwm_state; struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct sunxi_pwm_chip *pwm = platform_get_drvdata(pdev); for (i = 0; i < pwm->chip.npwm; i++) { pwm_state = pwm->chip.pwms[i].state.enabled; pwm_disable(&pwm->chip.pwms[i]); pwm->chip.pwms[i].state.enabled = pwm_state; } clk_disable_unprepare(pwm->pwm_clk); return 0; } static int sunxi_pwm_resume(struct device *dev) { int i = 0; int period, duty_cycle, polarity; struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct sunxi_pwm_chip *pwm = platform_get_drvdata(pdev); pwm->pwm_clk = of_clk_get(pdev->dev.of_node, 0); if (IS_ERR_OR_NULL(pwm->pwm_clk)) { pr_err("%s: can't get pwm clk\n", __func__); return -EINVAL; } clk_prepare_enable(pwm->pwm_clk); for (i = 0; i < pwm->chip.npwm; i++) { period = pwm->chip.pwms[i].state.period; pwm->chip.pwms[i].state.period = 0; duty_cycle = pwm->chip.pwms[i].state.duty_cycle; pwm->chip.pwms[i].state.duty_cycle = 0; pwm_config(&pwm->chip.pwms[i], duty_cycle, period); polarity = pwm->chip.pwms[i].state.polarity; pwm->chip.pwms[i].state.polarity = sunxi_pwm_get_polarity(&pwm->chip, i); pwm_set_polarity(&pwm->chip.pwms[i], polarity); if (pwm->chip.pwms[i].state.enabled == true) { pwm->chip.pwms[i].state.enabled = false; pwm_enable(&pwm->chip.pwms[i]); } } return 0; } static const struct dev_pm_ops pwm_pm_ops = { .suspend_late = sunxi_pwm_suspend, .resume_early = sunxi_pwm_resume, }; #else static const struct dev_pm_ops pwm_pm_ops; #endif #if !defined(CONFIG_OF) struct platform_device sunxi_pwm_device = { .name = "sunxi_pwm", .id = -1, }; #else static const struct of_device_id sunxi_pwm_match[] = { { .compatible = "allwinner,sunxi-pwm", }, { .compatible = "allwinner,sunxi-s_pwm", }, {}, }; #endif static struct platform_driver sunxi_pwm_driver = { .probe = sunxi_pwm_probe, .remove = sunxi_pwm_remove, .driver = { .name = "sunxi_pwm", .owner = THIS_MODULE, .of_match_table = sunxi_pwm_match, .pm = &pwm_pm_ops, }, }; static int __init pwm_module_init(void) { int ret = 0; pr_info("pwm module init!\n"); #if !defined(CONFIG_OF) ret = platform_device_register(&sunxi_pwm_device); #endif if (ret == 0) { ret = platform_driver_register(&sunxi_pwm_driver); } return ret; } static void __exit pwm_module_exit(void) { pr_info("pwm module exit!\n"); platform_driver_unregister(&sunxi_pwm_driver); #if !defined(CONFIG_OF) platform_device_unregister(&sunxi_pwm_device); #endif } subsys_initcall(pwm_module_init); module_exit(pwm_module_exit); MODULE_AUTHOR("lihuaxing"); MODULE_DESCRIPTION("pwm driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:sunxi-pwm"); MODULE_VERSION("1.0.0");