summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDino Li <dino.li@ite.com.tw>2014-10-22 19:08:18 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-10-29 03:29:17 +0000
commitb5bd5ed20d576c9a4cdd64b20698aa8f3c28f6a2 (patch)
treebade8ed7ffe377f2305053fc7455989bab5d2f1e
parent8a1f1b045a2bffc0c3bf3941709acf4ba99d32e7 (diff)
downloadchrome-ec-b5bd5ed20d576c9a4cdd64b20698aa8f3c28f6a2.tar.gz
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: 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>
-rw-r--r--board/it8380dev/board.c16
-rw-r--r--board/it8380dev/board.h14
-rw-r--r--board/it8380dev/gpio.inc42
-rw-r--r--chip/it83xx/build.mk1
-rw-r--r--chip/it83xx/config_chip.h1
-rw-r--r--chip/it83xx/pwm.c144
-rw-r--r--chip/it83xx/pwm_chip.h45
-rw-r--r--chip/it83xx/registers.h53
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