--- /dev/null
+/****************************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ ****************************************************************************/
+/****************************************************************************
+ * arch/arm/src/s5j/chip/s5j200_pwm.h
+ *
+ * Copyright (C) 2009-2010, 2014-2015 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_S5J_CHIP_S5JT200_PWM_H
+#define __ARCH_ARM_SRC_S5J_CHIP_S5JT200_PWM_H
+
+/****************************************************************************
+ * Include
+ ****************************************************************************/
+#include "s5j_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* PWM Register Offsets *****************************************************/
+#define S5J_PWM_TCFG0_OFFSET 0x00
+#define S5J_PWM_TCFG1_OFFSET 0x04
+#define S5J_PWM_TCON_OFFSET 0x08
+#define S5J_PWM_TCNTB0_OFFSET 0x0C
+#define S5J_PWM_TCMPB0_OFFSET 0x10
+#define S5J_PWM_TCNTO0_OFFSET 0x14
+#define S5J_PWM_TCNTB1_OFFSET 0x1C
+#define S5J_PWM_TCMPB1_OFFSET 0x20
+#define S5J_PWM_TCNTO1_OFFSET 0x24
+#define S5J_PWM_TCNTB2_OFFSET 0x1C
+#define S5J_PWM_TCMPB2_OFFSET 0x20
+#define S5J_PWM_TCNTO2_OFFSET 0x24
+#define S5J_PWM_TCNTB3_OFFSET 0x2C
+#define S5J_PWM_TCMPB3_OFFSET 0x30
+#define S5J_PWM_TCNTO3_OFFSET 0x34
+#define S5J_PWM_TINT_CSTAT_OFFSET 0x44
+
+#define S5J_PWM_TCNTB_OFFSET(c) (S5J_PWM_TCNTB0_OFFSET + 0xc * (c))
+#define S5J_PWM_TCMPB_OFFSET(c) (S5J_PWM_TCMPB0_OFFSET + 0xc * (c))
+#define S5J_PWM_TCNTO_OFFSET(c) (S5J_PWM_TCNTO0_OFFSET + 0xc * (c))
+
+/* PWM0 Register Address ****************************************************/
+#define S5J_PWM0_TCFG0 (S5J_PWM0_BASE + S5J_PWM_TCFG0_OFFSET)
+#define S5J_PWM0_TCFG1 (S5J_PWM0_BASE + S5J_PWM_TCFG1_OFFSET)
+#define S5J_PWM0_TCON (S5J_PWM0_BASE + S5J_PWM_TCON_OFFSET)
+#define S5J_PWM0_TCNTB0 (S5J_PWM0_BASE + S5J_PWM_TCNTB0_OFFSET)
+#define S5J_PWM0_TCMPB0 (S5J_PWM0_BASE + S5J_PWM_TCMPB0_OFFSET)
+#define S5J_PWM0_TCNTO0 (S5J_PWM0_BASE + S5J_PWM_TCNTO0_OFFSET)
+#define S5J_PWM0_TCNTB1 (S5J_PWM0_BASE + S5J_PWM_TCNTB1_OFFSET)
+#define S5J_PWM0_TCMPB1 (S5J_PWM0_BASE + S5J_PWM_TCMPB1_OFFSET)
+#define S5J_PWM0_TCNTO1 (S5J_PWM0_BASE + S5J_PWM_TCNTO1_OFFSET)
+#define S5J_PWM0_TCNTB2 (S5J_PWM0_BASE + S5J_PWM_TCNTB2_OFFSET)
+#define S5J_PWM0_TCMPB2 (S5J_PWM0_BASE + S5J_PWM_TCMPB2_OFFSET)
+#define S5J_PWM0_TCNTO2 (S5J_PWM0_BASE + S5J_PWM_TCNTO2_OFFSET)
+#define S5J_PWM0_TCNTB3 (S5J_PWM0_BASE + S5J_PWM_TCNTB3_OFFSET)
+#define S5J_PWM0_TCMPB3 (S5J_PWM0_BASE + S5J_PWM_TCMPB3_OFFSET)
+#define S5J_PWM0_TCNTO3 (S5J_PWM0_BASE + S5J_PWM_TCNTO3_OFFSET)
+#define S5J_PWM0_TINT_CSTAT (S5J_PWM0_BASE + S5J_PWM_TINT_CSTAT_OFFSET)
+
+/* PWM1 Register Address ****************************************************/
+#define S5J_PWM1_TCFG0 (S5J_PWM1_BASE + S5J_PWM_TCFG0_OFFSET)
+#define S5J_PWM1_TCFG1 (S5J_PWM1_BASE + S5J_PWM_TCFG1_OFFSET)
+#define S5J_PWM1_TCON (S5J_PWM1_BASE + S5J_PWM_TCON_OFFSET)
+#define S5J_PWM1_TCNTB0 (S5J_PWM1_BASE + S5J_PWM_TCNTB0_OFFSET)
+#define S5J_PWM1_TCMPB0 (S5J_PWM1_BASE + S5J_PWM_TCMPB0_OFFSET)
+#define S5J_PWM1_TCNTO0 (S5J_PWM1_BASE + S5J_PWM_TCNTO0_OFFSET)
+#define S5J_PWM1_TCNTB1 (S5J_PWM1_BASE + S5J_PWM_TCNTB1_OFFSET)
+#define S5J_PWM1_TCMPB1 (S5J_PWM1_BASE + S5J_PWM_TCMPB1_OFFSET)
+#define S5J_PWM1_TCNTO1 (S5J_PWM1_BASE + S5J_PWM_TCNTO1_OFFSET)
+#define S5J_PWM1_TCNTB2 (S5J_PWM1_BASE + S5J_PWM_TCNTB2_OFFSET)
+#define S5J_PWM1_TCMPB2 (S5J_PWM1_BASE + S5J_PWM_TCMPB2_OFFSET)
+#define S5J_PWM1_TCNTO2 (S5J_PWM1_BASE + S5J_PWM_TCNTO2_OFFSET)
+#define S5J_PWM1_TCNTB3 (S5J_PWM1_BASE + S5J_PWM_TCNTB3_OFFSET)
+#define S5J_PWM1_TCMPB3 (S5J_PWM1_BASE + S5J_PWM_TCMPB3_OFFSET)
+#define S5J_PWM1_TCNTO3 (S5J_PWM1_BASE + S5J_PWM_TCNTO3_OFFSET)
+#define S5J_PWM1_TINT_CSTAT (S5J_PWM1_BASE + S5J_PWM_TINT_CSTAT_OFFSET)
+
+/* Register Bitfield Definitions ********************************************/
+/* TCFG0 ********************************************************************/
+#define PWM_TCFG0_DEADZONE_LENGTH_SHIFT 16
+#define PWM_TCFG0_DEADZONE_LENGTH_MASK (0xff << PWM_TCFG0_DEADZONE_LENGTH_SHIFT)
+
+#define PWM_TCFG0_PRESCALER0_SHIFT 0
+#define PWM_TCFG0_PRESCALER0_MASK (0xff << PWM_TCFG0_PRESCALER0_SHIFT)
+
+#define PWM_TCFG0_PRESCALER1_SHIFT 8
+#define PWM_TCFG0_PRESCALER1_MASK (0xff << PWM_TCFG0_PRESCALER1_SHIFT)
+
+/* TCFG1 ********************************************************************/
+#define PWM_TCFG1_DIVIDER_MUX_SHIFT(c) (4 * c)
+#define PWM_TCFG1_DIVIDER_MUX_MASK(c) (0x7 << PWM_TCFG1_DIVIDER_MUX_SHIFT(c))
+#define PWM_TCFG1_DIVIDER_MUX_DIV1(c) (0x0 << PWM_TCFG1_DIVIDER_MUX_SHIFT(c))
+#define PWM_TCFG1_DIVIDER_MUX_DIV2(c) (0x1 << PWM_TCFG1_DIVIDER_MUX_SHIFT(c))
+#define PWM_TCFG1_DIVIDER_MUX_DIV4(c) (0x2 << PWM_TCFG1_DIVIDER_MUX_SHIFT(c))
+#define PWM_TCFG1_DIVIDER_MUX_DIV8(c) (0x3 << PWM_TCFG1_DIVIDER_MUX_SHIFT(c))
+#define PWM_TCFG1_DIVIDER_MUX_DIV16(c) (0x4 << PWM_TCFG1_DIVIDER_MUX_SHIFT(c))
+
+#define PWM_TCFG1_DIVIDER_MUX3_SHIFT PWM_TCFG1_DIVIDER_MUX_SHIFT(3)
+#define PWM_TCFG1_DIVIDER_MUX3_MASK PWM_TCFG1_DIVIDER_MUX_MASK(3)
+#define PWM_TCFG1_DIVIDER_MUX3_DIV1 PWM_TCFG1_DIVIDER_MUX_DIV1(3)
+#define PWM_TCFG1_DIVIDER_MUX3_DIV2 PWM_TCFG1_DIVIDER_MUX_DIV2(3)
+#define PWM_TCFG1_DIVIDER_MUX3_DIV4 PWM_TCFG1_DIVIDER_MUX_DIV4(3)
+#define PWM_TCFG1_DIVIDER_MUX3_DIV8 PWM_TCFG1_DIVIDER_MUX_DIV8(3)
+#define PWM_TCFG1_DIVIDER_MUX3_DIV16 PWM_TCFG1_DIVIDER_MUX_DIV16(3)
+
+#define PWM_TCFG1_DIVIDER_MUX2_SHIFT PWM_TCFG1_DIVIDER_MUX_SHIFT(2)
+#define PWM_TCFG1_DIVIDER_MUX2_MASK PWM_TCFG1_DIVIDER_MUX_MASK(2)
+#define PWM_TCFG1_DIVIDER_MUX2_DIV1 PWM_TCFG1_DIVIDER_MUX_DIV1(2)
+#define PWM_TCFG1_DIVIDER_MUX2_DIV2 PWM_TCFG1_DIVIDER_MUX_DIV2(2)
+#define PWM_TCFG1_DIVIDER_MUX2_DIV4 PWM_TCFG1_DIVIDER_MUX_DIV4(2)
+#define PWM_TCFG1_DIVIDER_MUX2_DIV8 PWM_TCFG1_DIVIDER_MUX_DIV8(2)
+#define PWM_TCFG1_DIVIDER_MUX2_DIV16 PWM_TCFG1_DIVIDER_MUX_DIV16(2)
+
+#define PWM_TCFG1_DIVIDER_MUX1_SHIFT PWM_TCFG1_DIVIDER_MUX_SHIFT(1)
+#define PWM_TCFG1_DIVIDER_MUX1_MASK PWM_TCFG1_DIVIDER_MUX_MASK(1)
+#define PWM_TCFG1_DIVIDER_MUX1_DIV1 PWM_TCFG1_DIVIDER_MUX_DIV1(1)
+#define PWM_TCFG1_DIVIDER_MUX1_DIV2 PWM_TCFG1_DIVIDER_MUX_DIV2(1)
+#define PWM_TCFG1_DIVIDER_MUX1_DIV4 PWM_TCFG1_DIVIDER_MUX_DIV4(1)
+#define PWM_TCFG1_DIVIDER_MUX1_DIV8 PWM_TCFG1_DIVIDER_MUX_DIV8(1)
+#define PWM_TCFG1_DIVIDER_MUX1_DIV16 PWM_TCFG1_DIVIDER_MUX_DIV16(1)
+
+#define PWM_TCFG1_DIVIDER_MUX0_SHIFT PWM_TCFG1_DIVIDER_MUX_SHIFT(0)
+#define PWM_TCFG1_DIVIDER_MUX0_MASK PWM_TCFG1_DIVIDER_MUX_MASK(0)
+#define PWM_TCFG1_DIVIDER_MUX0_DIV1 PWM_TCFG1_DIVIDER_MUX_DIV1(0)
+#define PWM_TCFG1_DIVIDER_MUX0_DIV2 PWM_TCFG1_DIVIDER_MUX_DIV2(0)
+#define PWM_TCFG1_DIVIDER_MUX0_DIV4 PWM_TCFG1_DIVIDER_MUX_DIV4(0)
+#define PWM_TCFG1_DIVIDER_MUX0_DIV8 PWM_TCFG1_DIVIDER_MUX_DIV8(0)
+#define PWM_TCFG1_DIVIDER_MUX0_DIV16 PWM_TCFG1_DIVIDER_MUX_DIV16(0)
+
+/* TCON *********************************************************************/
+#define PWM_TCON_TIM_BIT_OFFSET(c) (((c) == 0 ? 0 : ((c) + 1)) * 4)
+
+#define PWM_TCON_TIM_STARTSTOP_SHIFT(c) PWM_TCON_TIM_BIT_OFFSET(c)
+#define PWM_TCON_TIM_STARTSTOP_MASK(c) (0x1 << PWM_TCON_TIM_STARTSTOP_SHIFT(c))
+#define PWM_TCON_TIM_STARTSTOP_STOP(c) (0x0 << PWM_TCON_TIM_STARTSTOP_SHIFT(c))
+#define PWM_TCON_TIM_STARTSTOP_START(c) (0x1 << PWM_TCON_TIM_STARTSTOP_SHIFT(c))
+
+#define PWM_TCON_TIM_MAN_UPDATE_SHIFT(c) (PWM_TCON_TIM_BIT_OFFSET(c) + 1)
+#define PWM_TCON_TIM_MAN_UPDATE_MASK(c) (0x1 << PWM_TCON_TIM_MAN_UPDATE_SHIFT(c))
+#define PWM_TCON_TIM_MAN_UPDATE_NOP(c) (0x0 << PWM_TCON_TIM_MAN_UPDATE_SHIFT(c))
+#define PWM_TCON_TIM_MAN_UPDATE_UPDATE(c) (0x1 << PWM_TCON_TIM_MAN_UPDATE_SHIFT(c))
+
+#define PWM_TCON_TIM_OUTPUT_INV_SHIFT(c) (PWM_TCON_TIM_BIT_OFFSET(c) + 2)
+#define PWM_TCON_TIM_OUTPUT_INV_MASK(c) (0x1 << PWM_TCON_TIM_OUTPUT_INV_SHIFT(c))
+#define PWM_TCON_TIM_OUTPUT_INV_OFF(c) (0x0 << PWM_TCON_TIM_OUTPUT_INV_SHIFT(c))
+#define PWM_TCON_TIM_OUTPUT_INV_ON(c) (0x1 << PWM_TCON_TIM_OUTPUT_INV_SHIFT(c))
+
+#define PWM_TCON_TIM_AUTO_RELOAD_SHIFT(c) (PWM_TCON_TIM_BIT_OFFSET(c) + 3)
+#define PWM_TCON_TIM_AUTO_RELOAD_MASK(c) (0x1 << PWM_TCON_TIM_AUTO_RELOAD_SHIFT(c))
+#define PWM_TCON_TIM_AUTO_RELOAD_OFF(c) (0x0 << PWM_TCON_TIM_AUTO_RELOAD_SHIFT(c))
+#define PWM_TCON_TIM_AUTO_RELOAD_ON(c) (0x1 << PWM_TCON_TIM_AUTO_RELOAD_SHIFT(c))
+
+#define PWM_TCON_TIM0_STARTSTOP_SHIFT PWM_TCON_TIM_BIT_OFFSET(0)
+#define PWM_TCON_TIM0_STARTSTOP_MASK (0x1 << PWM_TCON_TIM_STARTSTOP_SHIFT(0))
+#define PWM_TCON_TIM0_STARTSTOP_STOP (0x0 << PWM_TCON_TIM_STARTSTOP_SHIFT(0))
+#define PWM_TCON_TIM0_STARTSTOP_START (0x1 << PWM_TCON_TIM_STARTSTOP_SHIFT(0))
+
+#define PWM_TCON_TIM0_MAN_UPDATE_SHIFT (PWM_TCON_TIM_BIT_OFFSET(0) + 1)
+#define PWM_TCON_TIM0_MAN_UPDATE_MASK (0x1 << PWM_TCON_TIM_MAN_UPDATE_SHIFT(0))
+#define PWM_TCON_TIM0_MAN_UPDATE_NOP (0x0 << PWM_TCON_TIM_MAN_UPDATE_SHIFT(0))
+#define PWM_TCON_TIM0_MAN_UPDATE_UPDATE (0x1 << PWM_TCON_TIM_MAN_UPDATE_SHIFT(0))
+
+#define PWM_TCON_TIM0_OUTPUT_INV_SHIFT (PWM_TCON_TIM_BIT_OFFSET(0) + 2)
+#define PWM_TCON_TIM0_OUTPUT_INV_MASK (0x1 << PWM_TCON_TIM_OUTPUT_INV_SHIFT(0))
+#define PWM_TCON_TIM0_OUTPUT_INV_OFF (0x0 << PWM_TCON_TIM_OUTPUT_INV_SHIFT(0))
+#define PWM_TCON_TIM0_OUTPUT_INV_ON (0x1 << PWM_TCON_TIM_OUTPUT_INV_SHIFT(0))
+
+#define PWM_TCON_TIM0_AUTO_RELOAD_SHIFT (PWM_TCON_TIM_BIT_OFFSET(0) + 3)
+#define PWM_TCON_TIM0_AUTO_RELOAD_MASK (0x1 << PWM_TCON_TIM_AUTO_RELOAD_SHIFT(0))
+#define PWM_TCON_TIM0_AUTO_RELOAD_OFF (0x0 << PWM_TCON_TIM_AUTO_RELOAD_SHIFT(0))
+#define PWM_TCON_TIM0_AUTO_RELOAD_ON (0x1 << PWM_TCON_TIM_AUTO_RELOAD_SHIFT(0))
+
+#define PWM_TCON_TIM0_DEADZONE_SHIFT (PWM_TCON_TIM_BIT_OFFSET(0) + 4)
+#define PWM_TCON_TIM0_DEADZONE_MASK (0x1 << PWM_TCON_TIM0_DEADZONE_SHIFT)
+#define PWM_TCON_TIM0_DEADZONE_DISABLE (0x0 << PWM_TCON_TIM0_DEADZONE_SHIFT)
+#define PWM_TCON_TIM0_DEADZONE_ENABLE (0x1 << PWM_TCON_TIM0_DEADZONE_SHIFT)
+
+#define PWM_TCON_TIM1_STARTSTOP_SHIFT PWM_TCON_TIM_BIT_OFFSET(1)
+#define PWM_TCON_TIM1_STARTSTOP_MASK (0x1 << PWM_TCON_TIM1_STARTSTOP_SHIFT)
+#define PWM_TCON_TIM1_STARTSTOP_STOP (0x0 << PWM_TCON_TIM1_STARTSTOP_SHIFT)
+#define PWM_TCON_TIM1_STARTSTOP_START (0x1 << PWM_TCON_TIM1_STARTSTOP_SHIFT)
+
+#define PWM_TCON_TIM1_MAN_UPDATE_SHIFT (PWM_TCON_TIM_BIT_OFFSET(1) + 1)
+#define PWM_TCON_TIM1_MAN_UPDATE_MASK (0x1 << PWM_TCON_TIM1_MAN_UPDATE_SHIFT)
+#define PWM_TCON_TIM1_MAN_UPDATE_NOP (0x0 << PWM_TCON_TIM1_MAN_UPDATE_SHIFT)
+#define PWM_TCON_TIM1_MAN_UPDATE_UPDATE (0x1 << PWM_TCON_TIM1_MAN_UPDATE_SHIFT)
+
+#define PWM_TCON_TIM1_OUTPUT_INV_SHIFT (PWM_TCON_TIM_BIT_OFFSET(1) + 2)
+#define PWM_TCON_TIM1_OUTPUT_INV_MASK (0x1 << PWM_TCON_TIM1_OUTPUT_INV_SHIFT)
+#define PWM_TCON_TIM1_OUTPUT_INV_OFF (0x0 << PWM_TCON_TIM1_OUTPUT_INV_SHIFT)
+#define PWM_TCON_TIM1_OUTPUT_INV_ON (0x1 << PWM_TCON_TIM1_OUTPUT_INV_SHIFT)
+
+#define PWM_TCON_TIM1_AUTO_RELOAD_SHIFT (PWM_TCON_TIM_BIT_OFFSET(1) + 3)
+#define PWM_TCON_TIM1_AUTO_RELOAD_MASK (0x1 << PWM_TCON_TIM1_AUTO_RELOAD_SHIFT)
+#define PWM_TCON_TIM1_AUTO_RELOAD_OFF (0x0 << PWM_TCON_TIM1_AUTO_RELOAD_SHIFT)
+#define PWM_TCON_TIM1_AUTO_RELOAD_ON (0x1 << PWM_TCON_TIM1_AUTO_RELOAD_SHIFT)
+
+#define PWM_TCON_TIM2_STARTSTOP_SHIFT PWM_TCON_TIM_BIT_OFFSET(2)
+#define PWM_TCON_TIM2_STARTSTOP_MASK (0x1 << PWM_TCON_TIM2_STARTSTOP_SHIFT)
+#define PWM_TCON_TIM2_STARTSTOP_STOP (0x0 << PWM_TCON_TIM2_STARTSTOP_SHIFT)
+#define PWM_TCON_TIM2_STARTSTOP_START (0x1 << PWM_TCON_TIM2_STARTSTOP_SHIFT)
+
+#define PWM_TCON_TIM2_MAN_UPDATE_SHIFT (PWM_TCON_TIM_BIT_OFFSET(2) + 1)
+#define PWM_TCON_TIM2_MAN_UPDATE_MASK (0x1 << PWM_TCON_TIM2_MAN_UPDATE_SHIFT)
+#define PWM_TCON_TIM2_MAN_UPDATE_NOP (0x0 << PWM_TCON_TIM2_MAN_UPDATE_SHIFT)
+#define PWM_TCON_TIM2_MAN_UPDATE_UPDATE (0x1 << PWM_TCON_TIM2_MAN_UPDATE_SHIFT)
+
+#define PWM_TCON_TIM2_OUTPUT_INV_SHIFT (PWM_TCON_TIM_BIT_OFFSET(2) + 2)
+#define PWM_TCON_TIM2_OUTPUT_INV_MASK (0x1 << PWM_TCON_TIM2_OUTPUT_INV_SHIFT)
+#define PWM_TCON_TIM2_OUTPUT_INV_OFF (0x0 << PWM_TCON_TIM2_OUTPUT_INV_SHIFT)
+#define PWM_TCON_TIM2_OUTPUT_INV_ON (0x1 << PWM_TCON_TIM2_OUTPUT_INV_SHIFT)
+
+#define PWM_TCON_TIM2_AUTO_RELOAD_SHIFT (PWM_TCON_TIM_BIT_OFFSET(2) + 3)
+#define PWM_TCON_TIM2_AUTO_RELOAD_MASK (0x1 << PWM_TCON_TIM2_AUTO_RELOAD_SHIFT)
+#define PWM_TCON_TIM2_AUTO_RELOAD_OFF (0x0 << PWM_TCON_TIM2_AUTO_RELOAD_SHIFT)
+#define PWM_TCON_TIM2_AUTO_RELOAD_ON (0x1 << PWM_TCON_TIM2_AUTO_RELOAD_SHIFT)
+
+#define PWM_TCON_TIM3_STARTSTOP_SHIFT PWM_TCON_TIM_BIT_OFFSET(3)
+#define PWM_TCON_TIM3_STARTSTOP_MASK (0x1 << PWM_TCON_TIM3_STARTSTOP_SHIFT)
+#define PWM_TCON_TIM3_STARTSTOP_STOP (0x0 << PWM_TCON_TIM3_STARTSTOP_SHIFT)
+#define PWM_TCON_TIM3_STARTSTOP_START (0x1 << PWM_TCON_TIM3_STARTSTOP_SHIFT)
+
+#define PWM_TCON_TIM3_MAN_UPDATE_SHIFT (PWM_TCON_TIM_BIT_OFFSET(3) + 1)
+#define PWM_TCON_TIM3_MAN_UPDATE_MASK (0x1 << PWM_TCON_TIM3_MAN_UPDATE_SHIFT)
+#define PWM_TCON_TIM3_MAN_UPDATE_NOP (0x0 << PWM_TCON_TIM3_MAN_UPDATE_SHIFT)
+#define PWM_TCON_TIM3_MAN_UPDATE_UPDATE (0x1 << PWM_TCON_TIM3_MAN_UPDATE_SHIFT)
+
+#define PWM_TCON_TIM3_OUTPUT_INV_SHIFT (PWM_TCON_TIM_BIT_OFFSET(3) + 2)
+#define PWM_TCON_TIM3_OUTPUT_INV_MASK (0x1 << PWM_TCON_TIM3_OUTPUT_INV_SHIFT)
+#define PWM_TCON_TIM3_OUTPUT_INV_OFF (0x0 << PWM_TCON_TIM3_OUTPUT_INV_SHIFT)
+#define PWM_TCON_TIM3_OUTPUT_INV_ON (0x1 << PWM_TCON_TIM3_OUTPUT_INV_SHIFT)
+
+#define PWM_TCON_TIM3_AUTO_RELOAD_SHIFT (PWM_TCON_TIM_BIT_OFFSET(3) + 3)
+#define PWM_TCON_TIM3_AUTO_RELOAD_MASK (0x1 << PWM_TCON_TIM3_AUTO_RELOAD_SHIFT)
+#define PWM_TCON_TIM3_AUTO_RELOAD_OFF (0x0 << PWM_TCON_TIM3_AUTO_RELOAD_SHIFT)
+#define PWM_TCON_TIM3_AUTO_RELOAD_ON (0x1 << PWM_TCON_TIM3_AUTO_RELOAD_SHIFT)
+
+/* TINT_CSTAT ***************************************************************/
+#define PWM_TINT_CSTAT_TIM0_INTMASK_SHIFT 0
+#define PWM_TINT_CSTAT_TIM0_INTMASK_MASK (0x1 << PWM_TINT_CSTAT_TIM0_INTMASk_SHIFT)
+
+#define PWM_TINT_CSTAT_TIM1_INTMASK_SHIFT 1
+#define PWM_TINT_CSTAT_TIM1_INTMASK_MASK (0x1 << PWM_TINT_CSTAT_TIM1_INTMASK_SHIFT)
+
+#define PWM_TINT_CSTAT_TIM2_INTMASK_SHIFT 2
+#define PWM_TINT_CSTAT_TIM2_INTMASK_MASK (0x1 << PWM_TINT_CSTAT_TIM2_INTMASK_SHIFT)
+
+#define PWM_TINT_CSTAT_TIM3_INTMASK_SHIFT 3
+#define PWM_TINT_CSTAT_TIM3_INTMASK_MASK (0x1 << PWM_TINT_CSTAT_TIM3_INTMASK_SHIFT)
+
+#define PWM_TINT_CSTAT_TIM0_INTPND_SHIFT 5
+#define PWM_TINT_CSTAT_TIM0_INTPND_MASK (0x1 << PWM_TINT_CSTAT_TIM0_INTPND_SHIFT)
+
+#define PWM_TINT_CSTAT_TIM1_INTPND_SHIFT 6
+#define PWM_TINT_CSTAT_TIM1_INTPND_MASK (0x1 << PWM_TINT_CSTAT_TIM1_INTPND_SHIFT)
+
+#define PWM_TINT_CSTAT_TIM2_INTPND_SHIFT 7
+#define PWM_TINT_CSTAT_TIM2_INTPND_MASK (0x1 << PWM_TINT_CSTAT_TIM2_INTPND_SHIFT)
+
+#define PWM_TINT_CSTAT_TIM3_INTPND_SHIFT 8
+#define PWM_TINT_CSTAT_TIM3_INTPND_MASK (0x1 << PWM_TINT_CSTAT_TIM3_INTPND_SHIFT)
+
+#endif /* __ARCH_ARM_SRC_S5J_CHIP_S5JT200_PWM_H */
/****************************************************************************
* arch/arm/src/s5j/s5j_pwm.c
*
- * Copyright (C) 2013-2014 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * The Samsung sample code has a BSD compatible license that requires this
- * copyright notice:
- *
- * Copyright (c) 2016 Samsung Electronics, Inc.
- * All rights reserved.
+ * Copyright (C) 2011-2012, 2014 Gregory Nutt. All rights reserved.
+ * Authors: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* POSSIBILITY OF SUCH DAMAGE.
*
*/
+
/****************************************************************************
* Included Files
****************************************************************************/
#include <tinyara/config.h>
#include <sys/types.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <poll.h>
-#include <errno.h>
+#include <assert.h>
#include <debug.h>
-#include <tinyara/pwm.h>
+#include <errno.h>
-#include <arch/chip/irq.h>
+#include <tinyara/pwm.h>
-#include "chip.h"
#include "up_arch.h"
-
#include "s5j_pwm.h"
#include "s5j_gpio.h"
/****************************************************************************
- * Static Function Prototypes
+ * Pre-processor definitions
****************************************************************************/
/****************************************************************************
- * Private Data
+ * Private Types
****************************************************************************/
-/* This is the list of lower half PWM driver methods used by the upper half driver */
-
-static bool pwm_initialized[2] = { false, false };
-
-static const struct pwm_ops_s g_pwmops = {
- .setup = s5j_pwm_setup,
- .shutdown = s5j_pwm_shutdown,
- .start = s5j_pwm_start,
- .stop = s5j_pwm_stop,
- .ioctl = s5j_pwm_ioctl,
-};
-
-static struct s5j_pwmtimer_s g_pwmdev[TOTAL_NUMBER_OF_TIMER];
-
-/* PWM/Timer Definitions ****************************************************/
-/* The following definitions are used to identify the various time types */
+struct s5j_pwmtimer_s {
+ FAR const struct pwm_ops_s *ops;
-struct s5j_pwm_intdata intdata[MAX_NO_PWM] = {
- {
- .pwm_no = 0,
- .int_count = 0,
- .reload = (1 << 3),
- .manual_update = (1 << 1),
- .start = (1 << 0),
- .invert = (1 << 2),
- .prescaler = 0,
- .div_mux = 0,
- },
- {
- .pwm_no = 1,
- .int_count = 0,
- .reload = (1 << 11),
- .manual_update = (1 << 9),
- .start = (1 << 8),
- .invert = (1 << 10),
- .prescaler = 0,
- .div_mux = 4,
- },
- {
- .pwm_no = 2,
- .int_count = 0,
- .reload = (1 << 15),
- .manual_update = (1 << 13),
- .start = (1 << 12),
- .invert = (1 << 14),
- .prescaler = 8,
- .div_mux = 8,
- },
- {
- .pwm_no = 3,
- .int_count = 0,
- .reload = (1 << 19),
- .manual_update = (1 << 17),
- .start = (1 << 16),
- .invert = (1 << 18),
- .prescaler = 8,
- .div_mux = 12,
- },
+ unsigned int base;
+ uint8_t id;
+ uint16_t pincfg;
};
/****************************************************************************
* Private Functions
****************************************************************************/
+static unsigned int s5j_get_oscclk(void)
+{
+ return 26000000;
+}
-/****************************************************************************
- * Name: s5j_pwm_interrupt
- *
- * Description:
- * Handle timer interrupts.
- *
- * Input parameters:
- * priv - A reference to the lower half PWM driver state structure
- *
- * Returned Value:
- * Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-static int s5j_pwm_interrupt(struct s5j_pwmtimer_s *priv)
+static uint32_t pwm_getreg32(struct s5j_pwmtimer_s *priv, int offset)
{
- return 0;
+ return getreg32(priv->base + offset);
}
-/****************************************************************************
- * Name: s5j_pwm_timer_interrupt
- *
- * Description:
- * Handle pwm 0..4 interrupts.
- *
- * Input parameters:
- * Standard NuttX interrupt inputs
- *
- * Returned Value:
- * Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-static int s5j_pwm_timer_interrupt(int irq, void *context, void *arg)
+static void pwm_putreg32(struct s5j_pwmtimer_s *priv, int offset, uint32_t value)
{
- signed int pwm_no;
- signed int irq_no;
- signed int int_stat;
- FAR struct s5j_pwmtimer_s *priv;
+ putreg32(value, priv->base + offset);
+}
- irq_no = irq - IRQ_PWM0_0;
+static void pwm_modifyreg32(struct s5j_pwmtimer_s *priv, int offset,
+ uint32_t clearbits, uint32_t setbits)
+{
+ modifyreg32(priv->base + offset, clearbits, setbits);
+}
+
+static unsigned int pwm_get_prescaler(struct s5j_pwmtimer_s *priv)
+{
+ unsigned int tcfg0 = pwm_getreg32(priv, S5J_PWM_TCFG0_OFFSET);
- if (irq_no > 4) {
- pwm_no = irq_no - 1;
- } else {
- pwm_no = irq_no;
+ if (priv->id == 0 || priv->id == 1) {
+ return (tcfg0 & PWM_TCFG0_PRESCALER0_MASK) >> PWM_TCFG0_PRESCALER0_SHIFT;
}
- priv = &g_pwmdev[pwm_no];
+ return (tcfg0 & PWM_TCFG0_PRESCALER1_MASK) >> PWM_TCFG0_PRESCALER1_SHIFT;
+}
- /* Clear interrupt pending register */
- int_stat = getreg32(priv->base + TINT_CSTAT) & 0x1F;
- int_stat |= (1 << (5 + irq_no));
- putreg32(int_stat, priv->base + TINT_CSTAT);
+static unsigned int pwm_get_divider(struct s5j_pwmtimer_s *priv)
+{
+ unsigned int tcfg1 = pwm_getreg32(priv, S5J_PWM_TCFG1_OFFSET);
- return s5j_pwm_interrupt(priv);
+ return (tcfg1 & PWM_TCFG1_DIVIDER_MUX_MASK(priv->id)) >> PWM_TCFG1_DIVIDER_MUX_SHIFT(priv->id);
+}
+
+static unsigned int pwm_clk_freq(struct s5j_pwmtimer_s *priv)
+{
+ return (s5j_get_oscclk() / (pwm_get_prescaler(priv) + 1)) >> pwm_get_divider(priv);
}
/****************************************************************************
* logic at power up.
*
****************************************************************************/
-
static int s5j_pwm_setup(FAR struct pwm_lowerhalf_s *dev)
{
FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- int channel;
-
- channel = priv->id;
-
- /* skip channel4 */
- if (channel >= 4) {
- channel += 1;
- }
-
- if (channel == 0) {
- s5j_configgpio(GPIO_PWM_TOUT0);
- } else if (channel == 1) {
- s5j_configgpio(GPIO_PWM_TOUT1);
- } else if (channel == 2) {
- s5j_configgpio(GPIO_PWM_TOUT2);
- } else if (channel == 3) {
- s5j_configgpio(GPIO_PWM_TOUT3);
- } else if (channel == 5) {
- s5j_configgpio(GPIO_PWM_TOUT5);
- } else if (channel == 6) {
- s5j_configgpio(GPIO_PWM_TOUT6);
- }
-
- return OK;
+ return s5j_configgpio(priv->pincfg);
}
/****************************************************************************
- * Name: s5j_pwm_shutdown
+ * Name: s5j_pwm_start
*
* Description:
- * This method is called when the driver is closed. The lower half driver
- * stop pulsed output, free any resources, disable the timer hardware, and
- * put the system into the lowest possible power usage state
+ * (Re-)initialize the timer resources and start the pulsed output
*
* Input parameters:
* dev - A reference to the lower half PWM driver state structure
+ * info - A reference to the characteristics of the pulsed output
*
* Returned Value:
* Zero on success; a negated errno value on failure
*
****************************************************************************/
-
-static int s5j_pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
+static int s5j_pwm_start(FAR struct pwm_lowerhalf_s *dev,
+ FAR const struct pwm_info_s *info)
{
+ uint32_t tcntb;
+ uint32_t tcmpb;
FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- int channel;
- channel = priv->id;
+ tcntb = pwm_clk_freq(priv) / info->frequency - 1;
+ tcmpb = (((tcntb + 1) * info->duty) / 65536) - 1;
- /* skip channel4 */
- if (channel >= 4) {
- channel += 1;
- }
+ pwm_putreg32(priv, S5J_PWM_TCNTB_OFFSET(priv->id), tcntb);
+ pwm_putreg32(priv, S5J_PWM_TCMPB_OFFSET(priv->id), tcmpb);
- if (channel == 0) {
- s5j_unconfiggpio(GPIO_PWM_TOUT0);
- } else if (channel == 1) {
- s5j_unconfiggpio(GPIO_PWM_TOUT1);
- } else if (channel == 2) {
- s5j_unconfiggpio(GPIO_PWM_TOUT2);
- } else if (channel == 3) {
- s5j_unconfiggpio(GPIO_PWM_TOUT3);
- } else if (channel == 5) {
- s5j_unconfiggpio(GPIO_PWM_TOUT5);
- } else if (channel == 6) {
- s5j_unconfiggpio(GPIO_PWM_TOUT6);
- }
+ pwm_modifyreg32(priv, S5J_PWM_TCON_OFFSET,
+ PWM_TCON_TIM_MAN_UPDATE_MASK(priv->id),
+ PWM_TCON_TIM_MAN_UPDATE_UPDATE(priv->id));
- /* Make sure that the output has been stopped */
- s5j_pwm_stop(dev);
+ /* Trigger to start */
+ pwm_modifyreg32(priv, S5J_PWM_TCON_OFFSET,
+ PWM_TCON_TIM_STARTSTOP_MASK(priv->id) |
+ PWM_TCON_TIM_MAN_UPDATE_MASK(priv->id) |
+ PWM_TCON_TIM_AUTO_RELOAD_MASK(priv->id),
+ PWM_TCON_TIM_STARTSTOP_START(priv->id) |
+ PWM_TCON_TIM_MAN_UPDATE_NOP(priv->id) |
+ PWM_TCON_TIM_AUTO_RELOAD_ON(priv->id));
return OK;
}
/****************************************************************************
- * Name: s5j_pwm_start
+ * Name: s5j_pwm_stop
*
* Description:
- * (Re-)initialize the timer resources and start the pulsed output
+ * Stop the pulsed output and reset the timer resources
*
* Input parameters:
* dev - A reference to the lower half PWM driver state structure
- * info - A reference to the characteristics of the pulsed output
*
* Returned Value:
* Zero on success; a negated errno value on failure
*
+ * Assumptions:
+ * This function is called to stop the pulsed output at anytime. This
+ * method is also called from the timer interrupt handler when a repetition
+ * count expires... automatically stopping the timer.
+ *
****************************************************************************/
-#ifdef CONFIG_PWM_PULSECOUNT
-static int s5j_pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_s *info, FAR void *handle)
-#else
-static int s5j_pwm_start(FAR struct pwm_lowerhalf_s *dev, FAR const struct pwm_info_s *info)
-#endif
+static int s5j_pwm_stop(FAR struct pwm_lowerhalf_s *dev)
{
FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- struct s5j_pwm_intdata *pwm_data = priv->intdata;
-
- signed int tcon, int_stat;
-#ifdef CONFIG_PWM_PULSECOUNT
- priv->callback = handle;
-#endif
-
- s5j_pwm_set_frequency_dutycycle(dev, info->frequency, info->duty);
-
- /* Enable interrupt */
- int_stat = getreg32(priv->base + TINT_CSTAT) & 0x1F;
- int_stat |= (1 << priv->id);
- putreg32(int_stat, priv->base + TINT_CSTAT);
-
- tcon = getreg32(priv->base + TCON);
-
- /* interrupt enable */
- //up_enable_irq(priv->irq);
- /* Manual update */
- putreg32(tcon | pwm_data->manual_update, priv->base + TCON);
+ pwm_modifyreg32(priv, S5J_PWM_TCON_OFFSET,
+ PWM_TCON_TIM_STARTSTOP_MASK(priv->id),
+ PWM_TCON_TIM_STARTSTOP_STOP(priv->id));
-#if 0
- if (type == TIMER_TYPE_ONE_SHOT) { /* ONESHOT */
- tcon &= ~(pwm_data->reload);
- } else /* INTERVAL */
-#endif
-
- tcon |= pwm_data->reload;
-
- tcon |= pwm_data->start;
-
- putreg32(tcon, priv->base + TCON);
-
- return 0;
+ return OK;
}
/****************************************************************************
- * Name: s5j_pwm_stop
+ * Name: s5j_pwm_shutdown
*
* Description:
- * Stop the pulsed output and reset the timer resources
+ * This method is called when the driver is closed. The lower half driver
+ * stop pulsed output, free any resources, disable the timer hardware, and
+ * put the system into the lowest possible power usage state
*
* Input parameters:
* dev - A reference to the lower half PWM driver state structure
* Returned Value:
* Zero on success; a negated errno value on failure
*
- * Assumptions:
- * This function is called to stop the pulsed output at anytime. This
- * method is also called from the timer interrupt handler when a repetition
- * count expires... automatically stopping the timer.
- *
****************************************************************************/
-
-static int s5j_pwm_stop(FAR struct pwm_lowerhalf_s *dev)
-{
- FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- struct s5j_pwm_intdata *pwm_data = priv->intdata;
-
- signed int tcon, int_stat;
-
- /* Disable interrupt */
- int_stat = getreg32(priv->base + TINT_CSTAT) & 0x1F;
- int_stat &= ~(1 << pwm_data->pwm_no);
- putreg32(int_stat, priv->base + TINT_CSTAT);
-
- tcon = getreg32(priv->base + TCON);
- tcon &= ~pwm_data->start;
- tcon &= ~pwm_data->reload;
- tcon &= ~pwm_data->invert;
- putreg32(tcon, priv->base + TCON);
-
- /* interrupt disable */
- up_disable_irq(priv->irq);
-
- priv->callback = NULL;
-
- return 0;
-}
-
-static int s5j_pwm_set_dutycycle(FAR struct pwm_lowerhalf_s *dev, signed int duty)
-{
- FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- struct s5j_pwm_intdata *pwm_data = priv->intdata;
- signed int tcntb;
- signed int tcmpb;
- signed int id;
- int64_t tmp;
-
- if (duty > 100) {
- duty = 100;
- }
-
- priv->dutycycle = duty;
- id = pwm_data->pwm_no;
-
- tcntb = getreg32(priv->base + TCNTB(id));
-
- tmp = ((tcntb + 1) * duty) / 100 - 1; // duty range :0 ~ 100
- tcmpb = (signed int)tmp;
-
- putreg32(tcmpb, priv->base + TCMPB(id));
-
- return 0;
-}
-
-static int s5j_pwm_set_pulsewidth(FAR struct pwm_lowerhalf_s *dev, signed int frequency)
-{
- FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- struct s5j_pwm_intdata *pwm_data = priv->intdata;
- signed int tcntb;
- signed int id;
-
- signed int timerclockfreq;
-
- timerclockfreq = PWM_PCLK / priv->pre_scaler / priv->divider;
- if ((timerclockfreq / 2) < frequency) {
- //PWM can't be generate the freq
- frequency = timerclockfreq / 2;
- }
-
- priv->freq = frequency;
- id = pwm_data->pwm_no;
-
- tcntb = (priv->timer_pclk / priv->pre_scaler / priv->divider / frequency) - 1;
- putreg32(tcntb, priv->base + TCNTB(id));
-
- return 0;
-}
-
-static int s5j_pwm_set_frequency_dutycycle(FAR struct pwm_lowerhalf_s *dev, signed int frequency, signed int duty)
-{
- s5j_pwm_set_pulsewidth(dev, frequency);
- s5j_pwm_set_dutycycle(dev, duty);
-
- return 0;
-}
-
-/* scaler_val : 1 ~ 256 */
-static int s5j_pwm_set_prescaler(FAR struct pwm_lowerhalf_s *dev, signed int scaler_val)
-{
- FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- struct s5j_pwm_intdata *pwm_data = priv->intdata;
-
- int i;
- signed int id;
- signed int tcntb;
- signed int val;
- signed int nPWM;
- //unsigned long flag;
-
- if (priv->id < 4) {
- nPWM = 0;
- } else {
- nPWM = 4;
- }
-
- if (pwm_data->pwm_no < 2) {
- for (i = 0; i < 2; i++) {
- g_pwmdev[nPWM + i].pre_scaler = scaler_val;
-
- pwm_data = priv->intdata;
-
- if ((getreg32(priv->base + TCON) & (g_pwmdev[nPWM + i].intdata->start)) != 0) {
- id = g_pwmdev[nPWM + i].intdata->pwm_no;
-
- tcntb = (g_pwmdev[nPWM + i].timer_pclk / g_pwmdev[nPWM + i].pre_scaler / g_pwmdev[nPWM + i].divider / g_pwmdev[nPWM + i].freq) - 1;
- putreg32(tcntb, g_pwmdev[nPWM + i].base + TCNTB(id));
- }
- }
- } else {
- for (i = 2; i < 4; i++) {
- g_pwmdev[nPWM + i].pre_scaler = scaler_val;
-
- if ((getreg32(priv->base + TCON) & (g_pwmdev[nPWM + i].intdata->start)) != 0) {
- id = g_pwmdev[nPWM + i].intdata->pwm_no;
-
- tcntb = (g_pwmdev[nPWM + i].timer_pclk / g_pwmdev[nPWM + i].pre_scaler / g_pwmdev[nPWM + i].divider / g_pwmdev[nPWM + i].freq) - 1;
- putreg32(tcntb, g_pwmdev[nPWM + i].base + TCNTB(id));
- }
- }
- }
-
- val = getreg32(priv->base + TCFG0);
- val &= ~(0xFF << pwm_data->prescaler);
- val |= ((scaler_val - 1) << pwm_data->prescaler);
- putreg32(val, priv->base + TCFG0);
-
- return 0;
-}
-
-/* scaler_val : 0 ~ 4 */
-static int s5j_pwm_set_divider(FAR struct pwm_lowerhalf_s *dev, signed int div_val)
+static int s5j_pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
{
FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- struct s5j_pwm_intdata *pwm_data = priv->intdata;
- signed int val;
-
- switch (div_val) {
- case 0: {
- priv->divider = 1;
- }
- break;
- case 1: {
- priv->divider = 2;
- }
- break;
- case 2: {
- priv->divider = 4;
- }
- break;
- case 3: {
- priv->divider = 8;
- }
- break;
- case 4: {
- priv->divider = 16;
- }
- break;
- default:
- return -EINVAL;
- }
-
- val = getreg32(priv->base + TCFG1);
- val &= ~(0xF << pwm_data->div_mux);
- val |= (div_val << pwm_data->div_mux);
- putreg32(val, priv->base + TCFG1);
- s5j_pwm_set_pulsewidth(dev, priv->freq);
- s5j_pwm_set_dutycycle(dev, priv->dutycycle);
+ /* Make sure that the output has been stopped */
+ s5j_pwm_stop(dev);
- return 0;
+ /* Then put the GPIO pins back to the default state */
+ return s5j_unconfiggpio(priv->pincfg);
}
/****************************************************************************
* Zero on success; a negated errno value on failure
*
****************************************************************************/
-
-static int s5j_pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg)
+static int s5j_pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd,
+ unsigned long arg)
{
- FAR struct s5j_pwmtimer_s *priv = (FAR struct s5j_pwmtimer_s *)dev;
- signed int val, tcfg0;
-
- val = (signed int)arg;
+ return -ENOTTY;
+}
- switch (cmd) {
- case PWM_SET_PRESCALER: {
- return s5j_pwm_set_prescaler(dev, val);
- }
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+static const struct pwm_ops_s g_pwm_ops = {
+ .setup = s5j_pwm_setup,
+ .shutdown = s5j_pwm_shutdown,
+ .start = s5j_pwm_start,
+ .stop = s5j_pwm_stop,
+ .ioctl = s5j_pwm_ioctl,
+};
- case PWM_SET_DIVIDER: {
- return s5j_pwm_set_divider(dev, val);
- }
+#ifdef CONFIG_S5J_PWM0
+static struct s5j_pwmtimer_s g_pwm0_0 = {
+ .ops = &g_pwm_ops,
+ .id = 0,
+ .pincfg = GPIO_PWM_TOUT0,
+ .base = S5J_PWM0_BASE,
+};
+#endif
- case PWM_SET_DEADZONE: {
- if (val >= 256) {
- val = 255;
- }
- tcfg0 = getreg32(priv->base + TCFG0);
- tcfg0 &= ~(0xFF << 16);
- tcfg0 |= (val << 16);
- putreg32(tcfg0, priv->base + TCFG0);
- }
- break;
+#ifdef CONFIG_S5J_PWM1
+static struct s5j_pwmtimer_s g_pwm0_1 = {
+ .ops = &g_pwm_ops,
+ .id = 1,
+ .pincfg = GPIO_PWM_TOUT1,
+ .base = S5J_PWM0_BASE,
+};
+#endif
- case PWM_SET_TCMP: {
- if (TCMPB(priv->id) != TREG_INVAL) {
- putreg32(val, priv->base + TCMPB(priv->id));
- }
- }
- break;
+#ifdef CONFIG_S5J_PWM2
+static struct s5j_pwmtimer_s g_pwm0_2 = {
+ .ops = &g_pwm_ops,
+ .id = 2,
+ .pincfg = GPIO_PWM_TOUT2,
+ .base = S5J_PWM0_BASE,
+};
+#endif
- case PWM_SET_DUTY_CYCLE: {
- s5j_pwm_set_dutycycle(dev, val);
- }
- break;
+#ifdef CONFIG_S5J_PWM3
+static struct s5j_pwmtimer_s g_pwm0_3 = {
+ .ops = &g_pwm_ops,
+ .id = 3,
+ .pincfg = GPIO_PWM_TOUT3,
+ .base = S5J_PWM0_BASE,
+};
+#endif
- default:
- break;
- }
+#ifdef CONFIG_S5J_PWM4
+static struct s5j_pwmtimer_s g_pwm1_0 = {
+ .ops = &g_pwm_ops,
+ .id = 0,
+ .pincfg = GPIO_PWM_TOUT5,
+ .base = S5J_PWM1_BASE,
+};
+#endif
- lldbg("TIMER%d\n", priv->id);
+#ifdef CONFIG_S5J_PWM5
+static struct s5j_pwmtimer_s g_pwm1_1 = {
+ .ops = &g_pwm_ops,
+ .id = 1,
+ .pincfg = GPIO_PWM_TOUT6,
+ .base = S5J_PWM1_BASE,
+};
+#endif
- return 0;
-}
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
/****************************************************************************
* Name: s5j_pwminitialize
* Initialize one timer for use with the upper_level PWM driver.
*
* Input Parameters:
- * timer - A number identifying the timer use. The number of valid timer
- * IDs varies with the S5J MCU and MCU family but is somewhere in
- * the range of {1,..,14}.
+ * timer - A number identifying the timer use. The number of valid timer
+ * IDs varies with the S5J family but is somewhere in the range of
+ * {0,...,5}.
*
* Returned Value:
- * On success, a pointer to the S5J lower half PWM driver is returned.
+ * On success, a pointer to the lower-half PWM driver is returned.
* NULL is returned on any failure.
*
****************************************************************************/
FAR struct pwm_lowerhalf_s *s5j_pwminitialize(int timer)
{
- struct s5j_pwmtimer_s *lower, *tmp;
-
- unsigned int i;
- unsigned int nPWM;
- unsigned int nTimer;
- unsigned int PWM_BASE_ADDR;
-
- if (timer < 4) {
- nPWM = 0;
- nTimer = timer;
- PWM_BASE_ADDR = PWM0_BASE;
- } else {
- nPWM = 1;
- nTimer = timer - 4;
- PWM_BASE_ADDR = PWM1_BASE;
- }
-
- /* Timer info initialization */
-
- /* Have we already initialized? */
- if (!pwm_initialized[nPWM]) {
- /* set prescaler to 1/16, set divider MUX to 1/16 */
- putreg32(0x0101, PWM_BASE_ADDR + TCFG0);
- putreg32(0x0000, PWM_BASE_ADDR + TCFG1);
- putreg32(0, PWM_BASE_ADDR + TCON);
-
- lower = &g_pwmdev[timer];
-
- for (i = 0; i < 4; i++) {
- tmp = &g_pwmdev[nPWM * 4 + i];
- tmp->intdata = &intdata[i];
- tmp->id = nPWM * 4 + i;
- tmp->irq = (IRQ_PWM0_0) + nPWM * 4 + i;
-
- tmp->base = (void *)PWM_BASE_ADDR;
-
- tmp->ops = &g_pwmops;
-
- /* clock setting or clock information */
- /* it should be replaced with cal code. */
- tmp->timer_pclk = PWM_PCLK;
+ struct pwm_lowerhalf_s *lower = NULL;
- tmp->pre_scaler = 2;
- tmp->divider = 1;
-
- /* set default frenquency : 100hz */
- tmp->freq = 100;
-
- /* set default duty cycle: 50% */
- tmp->dutycycle = 50;
- }
-
- /* Now we are initialized */
- pwm_initialized[nPWM] = true;
- } else {
- lower = &g_pwmdev[timer];
- //frequency
- lower->freq = lower->timer_pclk / (lower->pre_scaler) / lower->divider;
- }
-
- /* There is only 6 IRQ ID (PWM0_0 ~ PWM1_1 */
- if (timer < TOTAL_NUMBER_OF_PWMOUT) {
- /* IRQ register */
- irq_attach(lower->irq, s5j_pwm_timer_interrupt, NULL);
- up_disable_irq(lower->irq);
-
- /* IRQ trigger = level */
- putreg32(0x1, 0x800A0000 + 0x044c);
+#ifdef CONFIG_S5J_PWM0
+ if (timer == 0) {
+ lower = (struct pwm_lowerhalf_s *)&g_pwm0_0;
+ } else
+#endif
+#ifdef CONFIG_S5J_PWM1
+ if (timer == 1) {
+ lower = (struct pwm_lowerhalf_s *)&g_pwm0_1;
+ } else
+#endif
+#ifdef CONFIG_S5J_PWM2
+ if (timer == 2) {
+ lower = (struct pwm_lowerhalf_s *)&g_pwm0_2;
+ } else
+#endif
+#ifdef CONFIG_S5J_PWM3
+ if (timer == 3) {
+ lower = (struct pwm_lowerhalf_s *)&g_pwm0_3;
+ } else
+#endif
+#ifdef CONFIG_S5J_PWM4
+ if (timer == 4) {
+ lower = (struct pwm_lowerhalf_s *)&g_pwm1_0;
+ } else
+#endif
+#ifdef CONFIG_S5J_PWM5
+ if (timer == 5) {
+ lower = (struct pwm_lowerhalf_s *)&g_pwm1_1;
+ } else
+#endif
+ {
+ lldbg("ERROR: invalid PWM is requested\n");
}
- return (FAR struct pwm_lowerhalf_s *)lower;
+ return lower;
}