diff options
author | Dino Li <dino.li@ite.com.tw> | 2014-10-22 19:08:18 +0800 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-11-11 23:01:32 +0000 |
commit | bff770f73a4a5aef8d26656a59fb24ce96ac9dd9 (patch) | |
tree | 418333ad836fd82937d3838b5bfdc92472319044 | |
parent | 7b8b39d29fe3d185199f025d42c17c63070d8df8 (diff) | |
download | chrome-ec-bff770f73a4a5aef8d26656a59fb24ce96ac9dd9.tar.gz |
CHERRY-PICK: it8380dev: add pwm control module
Add pwm control module for emulation board.
Signed-off-by: Dino Li <dino.li@ite.com.tw>
BRANCH=none
BUG=none
TEST=console manual test, pwm channels output correctly.
Change-Id: Ic5144c07743f859c280dbc08ec6b42eff6e661cc
Original-Change-Id: I6eb1a9e4fdcb9279e9d0cbd67f7a92afed21c889
Reviewed-on: https://chromium-review.googlesource.com/223921
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Commit-Queue: Dino Li <dino.li@ite.com.tw>
Tested-by: Dino Li <dino.li@ite.com.tw>
Reviewed-on: https://chromium-review.googlesource.com/229109
Reviewed-by: Mohammed Habibulla <moch@chromium.org>
Commit-Queue: Mohammed Habibulla <moch@chromium.org>
Tested-by: Mohammed Habibulla <moch@chromium.org>
-rw-r--r-- | board/it8380dev/board.c | 16 | ||||
-rw-r--r-- | board/it8380dev/board.h | 14 | ||||
-rw-r--r-- | board/it8380dev/gpio.inc | 42 | ||||
-rw-r--r-- | chip/it83xx/build.mk | 1 | ||||
-rw-r--r-- | chip/it83xx/config_chip.h | 1 | ||||
-rw-r--r-- | chip/it83xx/pwm.c | 144 | ||||
-rw-r--r-- | chip/it83xx/pwm_chip.h | 45 | ||||
-rw-r--r-- | chip/it83xx/registers.h | 53 |
8 files changed, 294 insertions, 22 deletions
diff --git a/board/it8380dev/board.c b/board/it8380dev/board.c index 401a221c44..588ab4d0d7 100644 --- a/board/it8380dev/board.c +++ b/board/it8380dev/board.c @@ -11,6 +11,8 @@ #include "registers.h" #include "task.h" #include "util.h" +#include "pwm.h" +#include "pwm_chip.h" /* Test GPIO interrupt function that toggles one LED. */ void test_interrupt(enum gpio_signal signal) @@ -24,6 +26,20 @@ void test_interrupt(enum gpio_signal signal) #include "gpio_list.h" +/* PWM channels. Must be in the exactly same order as in enum pwm_channel. */ +const struct pwm_t pwm_channels[] = { + {0, 0}, + {1, PWM_CONFIG_ACTIVE_LOW}, + {2, 0}, + {3, PWM_CONFIG_ACTIVE_LOW}, + {4, 0}, + {5, PWM_CONFIG_ACTIVE_LOW}, + {6, 0}, + {7, PWM_CONFIG_ACTIVE_LOW}, +}; + +BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT); + /* Initialize board. */ static void board_init(void) { diff --git a/board/it8380dev/board.h b/board/it8380dev/board.h index 04d3f1b4c0..1d612d32a2 100644 --- a/board/it8380dev/board.h +++ b/board/it8380dev/board.h @@ -15,5 +15,19 @@ #include "gpio_signal.h" +enum pwm_channel { + PWM_CH_0, + PWM_CH_1, + PWM_CH_2, + PWM_CH_3, + PWM_CH_4, + PWM_CH_5, + PWM_CH_6, + PWM_CH_7, + + /* Number of PWM channels */ + PWM_CH_COUNT +}; + #endif /* !__ASSEMBLER__ */ #endif /* __BOARD_H */ diff --git a/board/it8380dev/gpio.inc b/board/it8380dev/gpio.inc index 5091fdb3ef..444ae4c15d 100644 --- a/board/it8380dev/gpio.inc +++ b/board/it8380dev/gpio.inc @@ -5,27 +5,27 @@ * found in the LICENSE file. */ -GPIO(H_LED0, A, 0, GPIO_ODR_HIGH) -GPIO(H_LED1, A, 1, GPIO_ODR_HIGH) -GPIO(H_LED2, A, 2, GPIO_ODR_HIGH) -GPIO(H_LED3, A, 3, GPIO_ODR_HIGH) -GPIO(H_LED4, A, 4, GPIO_ODR_HIGH) -GPIO(H_LED5, A, 5, GPIO_ODR_HIGH) -GPIO(H_LED6, A, 6, GPIO_ODR_HIGH) -GPIO(L_LED0, I, 0, GPIO_ODR_HIGH) -GPIO(L_LED1, I, 1, GPIO_ODR_HIGH) -GPIO(L_LED2, I, 2, GPIO_ODR_HIGH) -GPIO(L_LED3, I, 3, GPIO_ODR_HIGH) -GPIO(L_LED4, I, 4, GPIO_ODR_HIGH) -GPIO(L_LED5, I, 5, GPIO_ODR_HIGH) -GPIO(L_LED6, I, 6, GPIO_ODR_HIGH) -GPIO(BUSY_LED, J, 0, GPIO_OUT_LOW) -GPIO(GOOD_LED, J, 1, GPIO_OUT_HIGH) -GPIO(FAIL_LED, J, 2, GPIO_OUT_LOW) -GPIO(SW1, E, 0, GPIO_INPUT) -GPIO(SW2, E, 1, GPIO_INPUT | GPIO_PULL_DOWN) -GPIO(SW3, E, 2, GPIO_INPUT | GPIO_PULL_DOWN) -GPIO(SW4, E, 3, GPIO_INPUT | GPIO_PULL_DOWN) +GPIO(H_LED0, A, 0, GPIO_ODR_HIGH, NULL) +GPIO(H_LED1, A, 1, GPIO_ODR_HIGH, NULL) +GPIO(H_LED2, A, 2, GPIO_ODR_HIGH, NULL) +GPIO(H_LED3, A, 3, GPIO_ODR_HIGH, NULL) +GPIO(H_LED4, A, 4, GPIO_ODR_HIGH, NULL) +GPIO(H_LED5, A, 5, GPIO_ODR_HIGH, NULL) +GPIO(H_LED6, A, 6, GPIO_ODR_HIGH, NULL) +GPIO(L_LED0, I, 0, GPIO_ODR_HIGH, NULL) +GPIO(L_LED1, I, 1, GPIO_ODR_HIGH, NULL) +GPIO(L_LED2, I, 2, GPIO_ODR_HIGH, NULL) +GPIO(L_LED3, I, 3, GPIO_ODR_HIGH, NULL) +GPIO(L_LED4, I, 4, GPIO_ODR_HIGH, NULL) +GPIO(L_LED5, I, 5, GPIO_ODR_HIGH, NULL) +GPIO(L_LED6, I, 6, GPIO_ODR_HIGH, NULL) +GPIO(BUSY_LED, J, 0, GPIO_OUT_LOW, NULL) +GPIO(GOOD_LED, J, 1, GPIO_OUT_HIGH, NULL) +GPIO(FAIL_LED, J, 2, GPIO_OUT_LOW, NULL) +GPIO(SW1, E, 0, GPIO_INPUT, NULL) +GPIO(SW2, E, 1, GPIO_INPUT | GPIO_PULL_DOWN, NULL) +GPIO(SW3, E, 2, GPIO_INPUT | GPIO_PULL_DOWN, NULL) +GPIO(SW4, E, 3, GPIO_INPUT | GPIO_PULL_DOWN, NULL) GPIO(START_SW, E, 4, GPIO_INT_FALLING, test_interrupt) /* Unimplemented signals which we need to emulate for now */ diff --git a/chip/it83xx/build.mk b/chip/it83xx/build.mk index 5906cfe6de..e6c9926ff1 100644 --- a/chip/it83xx/build.mk +++ b/chip/it83xx/build.mk @@ -14,3 +14,4 @@ chip-y=hwtimer.o uart.o gpio.o system.o jtag.o clock.o irq.o # Optional chip modules chip-$(CONFIG_WATCHDOG)+=watchdog.o +chip-$(CONFIG_PWM)+=pwm.o diff --git a/chip/it83xx/config_chip.h b/chip/it83xx/config_chip.h index 1ba70fa3aa..0f0e86aa3c 100644 --- a/chip/it83xx/config_chip.h +++ b/chip/it83xx/config_chip.h @@ -103,5 +103,6 @@ #undef CONFIG_I2C #undef CONFIG_FLASH #undef CONFIG_WATCHDOG +#define CONFIG_PWM #endif /* __CROS_EC_CONFIG_CHIP_H */ diff --git a/chip/it83xx/pwm.c b/chip/it83xx/pwm.c new file mode 100644 index 0000000000..6d705f5c46 --- /dev/null +++ b/chip/it83xx/pwm.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* PWM control module for IT83xx. */ + +#include "clock.h" +#include "fan.h" +#include "gpio.h" +#include "hooks.h" +#include "pwm.h" +#include "pwm_chip.h" +#include "registers.h" +#include "util.h" + +const struct pwm_ctrl_t pwm_ctrl_regs[] = { + { &IT83XX_PWM_DCR0, &IT83XX_PWM_PCSSGL, &IT83XX_GPIO_GPCRA0}, + { &IT83XX_PWM_DCR1, &IT83XX_PWM_PCSSGL, &IT83XX_GPIO_GPCRA1}, + { &IT83XX_PWM_DCR2, &IT83XX_PWM_PCSSGL, &IT83XX_GPIO_GPCRA2}, + { &IT83XX_PWM_DCR3, &IT83XX_PWM_PCSSGL, &IT83XX_GPIO_GPCRA3}, + { &IT83XX_PWM_DCR4, &IT83XX_PWM_PCSSGH, &IT83XX_GPIO_GPCRA4}, + { &IT83XX_PWM_DCR5, &IT83XX_PWM_PCSSGH, &IT83XX_GPIO_GPCRA5}, + { &IT83XX_PWM_DCR6, &IT83XX_PWM_PCSSGH, &IT83XX_GPIO_GPCRA6}, + { &IT83XX_PWM_DCR7, &IT83XX_PWM_PCSSGH, &IT83XX_GPIO_GPCRA7}, +}; + +const struct pwm_ctrl_t2 pwm_clock_ctrl_regs[] = { + { &IT83XX_PWM_CTR, &IT83XX_PWM_C0CPRS, &IT83XX_PWM_C0CPRS, + &IT83XX_PWM_PCFSR, 0x01}, + { &IT83XX_PWM_CTR1, &IT83XX_PWM_C4CPRS, &IT83XX_PWM_C4MCPRS, + &IT83XX_PWM_PCFSR, 0x02}, + { &IT83XX_PWM_CTR2, &IT83XX_PWM_C6CPRS, &IT83XX_PWM_C6MCPRS, + &IT83XX_PWM_PCFSR, 0x04}, + { &IT83XX_PWM_CTR3, &IT83XX_PWM_C7CPRS, &IT83XX_PWM_C7MCPRS, + &IT83XX_PWM_PCFSR, 0x08}, +}; + +void pwm_enable(enum pwm_channel ch, int enabled) +{ + /* pwm channel mapping */ + ch = pwm_channels[ch].channel; + + /* + * enabled : pin to PWM function. + * disabled : pin to GPIO input function. + */ + if (enabled) + *pwm_ctrl_regs[ch].pwm_pin = 0x00; + else + *pwm_ctrl_regs[ch].pwm_pin = 0x80; +} + +int pwm_get_enabled(enum pwm_channel ch) +{ + /* pwm channel mapping */ + ch = pwm_channels[ch].channel; + + /* pin is PWM function and PWMs clock counter was enabled */ + return ((*pwm_ctrl_regs[ch].pwm_pin & ~0x04) == 0x00 && + IT83XX_PWM_ZTIER & 0x02) ? 1 : 0; +} + +void pwm_set_duty(enum pwm_channel ch, int percent) +{ + int pcs_shift; + int pcs_mask; + int pcs_reg; + int cycle_time_setting; + + if (percent < 0) + percent = 0; + else if (percent > 100) + percent = 100; + + /* pwm channel mapping */ + ch = pwm_channels[ch].channel; + + /* bit shift for "Prescaler Clock Source Select Group" register. */ + pcs_shift = (ch % 4) * 2; + + /* setting of "Prescaler Clock Source Select Group" register.*/ + pcs_reg = *pwm_ctrl_regs[ch].pwm_clock_source; + + /* only bit0 bit1 information. */ + pcs_mask = (pcs_reg >> pcs_shift) & 0x03; + + /* get cycle time setting of PWM channel x. */ + cycle_time_setting = *pwm_clock_ctrl_regs[pcs_mask].pwm_cycle_time; + + if (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW) + percent = 100 - percent; + + /* to update PWM DCRx depend on CTRx setting. */ + if (percent == 100) { + *pwm_ctrl_regs[ch].pwm_duty = cycle_time_setting; + } else { + *pwm_ctrl_regs[ch].pwm_duty = + ((cycle_time_setting + 1) * percent) / 100; + } +} + +int pwm_get_duty(enum pwm_channel ch) +{ + int pcs_mask; + int pcs_reg; + int cycle_time_setting; + int percent; + + /* pwm channel mapping */ + ch = pwm_channels[ch].channel; + + /* setting of "Prescaler Clock Source Select Group" register.*/ + pcs_reg = *pwm_ctrl_regs[ch].pwm_clock_source; + + /* only bit0 bit1 information. */ + pcs_mask = (pcs_reg >> ((ch % 4) * 2)) & 0x03; + + /* get cycle time setting of PWM channel x. */ + cycle_time_setting = *pwm_clock_ctrl_regs[pcs_mask].pwm_cycle_time; + + percent = *pwm_ctrl_regs[ch].pwm_duty * 100 / cycle_time_setting; + + if (pwm_channels[ch].flags & PWM_CONFIG_ACTIVE_LOW) + percent = 100 - percent; + + /* output signal duty cycle. */ + return percent; +} + +static void pwm_init(void) +{ + /* enable PWMs clock counter. */ + IT83XX_PWM_ZTIER |= 0x02; + + /* 0.5 resolution */ + IT83XX_PWM_CTR = 200; + IT83XX_PWM_CTR1 = 200; + IT83XX_PWM_CTR2 = 200; + IT83XX_PWM_CTR3 = 200; +} + +/* The chip PWM module initialization. */ +DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_DEFAULT); diff --git a/chip/it83xx/pwm_chip.h b/chip/it83xx/pwm_chip.h new file mode 100644 index 0000000000..d3c31a53fb --- /dev/null +++ b/chip/it83xx/pwm_chip.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* PWM control module for IT83xx. */ + +#ifndef __CROS_EC_IT83XX_PWM_H +#define __CROS_EC_IT83XX_PWM_H + +/* Data structure to define PWM channel control registers. */ +struct pwm_ctrl_t { + /* PWM channel output duty register. */ + volatile uint8_t *pwm_duty; + /* PWM channel clock source selection register. */ + volatile uint8_t *pwm_clock_source; + /* PWM channel pin control register. */ + volatile uint8_t *pwm_pin; +}; + +/* Data structure to define PWM channel control registers part 2. */ +struct pwm_ctrl_t2 { + /* PWM cycle time register. */ + volatile uint8_t *pwm_cycle_time; + /* PWM channel clock prescaler register (LSB). */ + volatile uint8_t *pwm_cpr_lsb; + /* PWM channel clock prescaler register (MSB). */ + volatile uint8_t *pwm_cpr_msb; + /* PWM prescaler clock frequency select register. */ + volatile uint8_t *pwm_pcfsr_reg; + /* PWM prescaler clock frequency select register setting. */ + uint8_t pwm_pcfsr_ctrl; +}; + +/* Data structure to define PWM channels. */ +struct pwm_t { + /* PWM channel ID */ + int channel; + /* PWM channel flags. See include/pwm.h */ + uint32_t flags; +}; + +extern const struct pwm_t pwm_channels[]; + +#endif /* __CROS_EC_IT83XX_PWM_H */ diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h index bacdc18d33..feb16bbba9 100644 --- a/chip/it83xx/registers.h +++ b/chip/it83xx/registers.h @@ -420,6 +420,15 @@ #define IT83XX_GPIO_BASE 0x00F01600 +#define IT83XX_GPIO_GPCRA0 REG8(IT83XX_GPIO_BASE+0x10) +#define IT83XX_GPIO_GPCRA1 REG8(IT83XX_GPIO_BASE+0x11) +#define IT83XX_GPIO_GPCRA2 REG8(IT83XX_GPIO_BASE+0x12) +#define IT83XX_GPIO_GPCRA3 REG8(IT83XX_GPIO_BASE+0x13) +#define IT83XX_GPIO_GPCRA4 REG8(IT83XX_GPIO_BASE+0x14) +#define IT83XX_GPIO_GPCRA5 REG8(IT83XX_GPIO_BASE+0x15) +#define IT83XX_GPIO_GPCRA6 REG8(IT83XX_GPIO_BASE+0x16) +#define IT83XX_GPIO_GPCRA7 REG8(IT83XX_GPIO_BASE+0x17) + #define IT83XX_GPIO_GPCRF0 REG8(IT83XX_GPIO_BASE+0x38) #define IT83XX_GPIO_GRC1 REG8(IT83XX_GPIO_BASE+0xF0) @@ -531,6 +540,49 @@ enum clock_gate_offsets { #define IT83XX_GCTRL_WNCKR REG8(IT83XX_GCTRL_BASE+0x0B) #define IT83XX_GCTRL_RSTS REG8(IT83XX_GCTRL_BASE+0x06) +/* --- Pulse Width Modulation (PWM) --- */ +#define IT83XX_PWM_BASE 0x00F01800 + +#define IT83XX_PWM_C0CPRS REG8(IT83XX_PWM_BASE+0x00) +#define IT83XX_PWM_CTR REG8(IT83XX_PWM_BASE+0x01) +#define IT83XX_PWM_DCR0 REG8(IT83XX_PWM_BASE+0x02) +#define IT83XX_PWM_DCR1 REG8(IT83XX_PWM_BASE+0x03) +#define IT83XX_PWM_DCR2 REG8(IT83XX_PWM_BASE+0x04) +#define IT83XX_PWM_DCR3 REG8(IT83XX_PWM_BASE+0x05) +#define IT83XX_PWM_DCR4 REG8(IT83XX_PWM_BASE+0x06) +#define IT83XX_PWM_DCR5 REG8(IT83XX_PWM_BASE+0x07) +#define IT83XX_PWM_DCR6 REG8(IT83XX_PWM_BASE+0x08) +#define IT83XX_PWM_DCR7 REG8(IT83XX_PWM_BASE+0x09) +#define IT83XX_PWM_PWMPOL REG8(IT83XX_PWM_BASE+0x0A) +#define IT83XX_PWM_PCFSR REG8(IT83XX_PWM_BASE+0x0B) +#define IT83XX_PWM_PCSSGL REG8(IT83XX_PWM_BASE+0x0C) +#define IT83XX_PWM_PCSSGH REG8(IT83XX_PWM_BASE+0x0D) +#define IT83XX_PWM_CR256PCSSG REG8(IT83XX_PWM_BASE+0x0E) +#define IT83XX_PWM_PCSGR REG8(IT83XX_PWM_BASE+0x0F) +#define IT83XX_PWM_F1TLRR REG8(IT83XX_PWM_BASE+0x1E) +#define IT83XX_PWM_F1TMRR REG8(IT83XX_PWM_BASE+0x1F) +#define IT83XX_PWM_F2TLRR REG8(IT83XX_PWM_BASE+0x20) +#define IT83XX_PWM_F2TMRR REG8(IT83XX_PWM_BASE+0x21) +#define IT83XX_PWM_ZINTSCR REG8(IT83XX_PWM_BASE+0x22) +#define IT83XX_PWM_ZTIER REG8(IT83XX_PWM_BASE+0x23) +#define IT83XX_PWM_TSWCTLR REG8(IT83XX_PWM_BASE+0x24) +#define IT83XX_PWM_C4CPRS REG8(IT83XX_PWM_BASE+0x27) +#define IT83XX_PWM_C4MCPRS REG8(IT83XX_PWM_BASE+0x28) +#define IT83XX_PWM_C6CPRS REG8(IT83XX_PWM_BASE+0x2B) +#define IT83XX_PWM_C6MCPRS REG8(IT83XX_PWM_BASE+0x2C) +#define IT83XX_PWM_C7CPRS REG8(IT83XX_PWM_BASE+0x2D) +#define IT83XX_PWM_C7MCPRS REG8(IT83XX_PWM_BASE+0x2E) +#define IT83XX_PWM_CLK6MSEL REG8(IT83XX_PWM_BASE+0x40) +#define IT83XX_PWM_CTR1 REG8(IT83XX_PWM_BASE+0x41) +#define IT83XX_PWM_CTR2 REG8(IT83XX_PWM_BASE+0x42) +#define IT83XX_PWM_CTR3 REG8(IT83XX_PWM_BASE+0x43) +#define IT83XX_PWM_PWM5TOCTRL REG8(IT83XX_PWM_BASE+0x44) +#define IT83XX_PWM_CFLRR REG8(IT83XX_PWM_BASE+0x45) +#define IT83XX_PWM_CFMRR REG8(IT83XX_PWM_BASE+0x46) +#define IT83XX_PWM_CFINTCTRL REG8(IT83XX_PWM_BASE+0x47) +#define IT83XX_PWM_TSWCTRL REG8(IT83XX_PWM_BASE+0x48) +#define IT83XX_PWM_PWMODENR REG8(IT83XX_PWM_BASE+0x49) + /* --- MISC (not implemented yet) --- */ #define IT83XX_SMFI_BASE 0x00F01000 @@ -539,7 +591,6 @@ enum clock_gate_offsets { #define IT83XX_SWUC_BASE 0x00F01400 #define IT83XX_PMC_BASE 0x00F01500 #define IT83XX_PS2_BASE 0x00F01700 -#define IT83XX_PWM_BASE 0x00F01800 #define IT83XX_ADC_BASE 0x00F01900 #define IT83XX_DAC_BASE 0x00F01A00 #define IT83XX_WUC_BASE 0x00F01B00 |