<commit_before>/*
 * Copyright (c) 2021 ITE Corporation. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT ite_it8xxx2_pwm

#include <device.h>
#include <drivers/pwm.h>
#include <drivers/pinmux.h>
#include <dt-bindings/pwm/it8xxx2_pwm.h>
#include <errno.h>
#include <kernel.h>
#include <soc.h>
#include <soc_dt.h>
#include <stdlib.h>

#include <logging/log.h>
LOG_MODULE_REGISTER(pwm_ite_it8xxx2, CONFIG_PWM_LOG_LEVEL);

#define PWM_CTRX_MIN	100
#define PWM_FREQ	EC_FREQ
#define PCSSG_MASK	0x3

/* Device config */
struct pwm_alt_cfg {
	/* Pinmux control device structure */
	const struct device *pinctrls;
	/* GPIO pin */
	uint8_t pin;
	/* Alternate function */
	uint8_t alt_fun;
};

struct pwm_it8xxx2_cfg {
	/* PWM channel duty cycle register */
	uintptr_t reg_dcr;
	/* PWM channel clock source selection register */
	uintptr_t reg_pcssg;
	/* PWM channel clock source gating register */
	uintptr_t reg_pcsgr;
	/* PWM channel output polarity register */
	uintptr_t reg_pwmpol;
	/* PWM channel */
	int channel;
	/* PWM prescaler control register base */
	struct pwm_it8xxx2_regs *base;
	/* Select PWM prescaler that output to PWM channel */
	int prs_sel;
	/* PWM alternate configuration list */
	const struct pwm_alt_cfg *alt_list;
};

static void pwm_enable(const struct device *dev, int enabled)
{
	const struct pwm_it8xxx2_cfg *config = dev->config;
	volatile uint8_t *reg_pcsgr = (uint8_t *)config->reg_pcsgr;
	int ch = config->channel;

	if (enabled) {
		/* PWM channel clock source not gating */
		*reg_pcsgr &= ~BIT(ch);
	} else {
		/* PWM channel clock source gating */
		*reg_pcsgr |= BIT(ch);
	}
}

static int pwm_it8xxx2_get_cycles_per_sec(const struct device *dev,
					     uint32_t pwm, uint64_t *cycles)
{
	ARG_UNUSED(pwm);

	/*
	 * There are three ways to call pwm_it8xxx2_pin_set() from pwm api:
	 * 1) pwm_pin_set_usec() -> pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set()
	 *    target_freq = pwm_clk_src / period_cycles
	 *                = cycles / (period * cycles / USEC_PER_SEC)
	 *                = USEC_PER_SEC / period
	 * 2) pwm_pin_set_nsec() -> pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set()
	 *    target_freq = pwm_clk_src / period_cycles
	 *                = cycles / (period * cycles / NSEC_PER_SEC)
	 *                = NSEC_PER_SEC / period
	 * 3) pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set()
	 *    target_freq = pwm_clk_src / period_cycles
	 *                = cycles / period
	 *
	 * If we need to pwm output in EC power saving mode, then we will switch
	 * the prescaler clock source (cycles) from 8MHz to 32.768kHz. In order
	 * to get the same target_freq in the 3) case, we always return PWM_FREQ.
	 */
	*cycles = (uint64_t) PWM_FREQ;

	return 0;
}

static int pwm_it8xxx2_pin_set(const struct device *dev,
				uint32_t pwm, uint32_t period_cycles,
				uint32_t pulse_cycles, pwm_flags_t flags)
{
	const struct pwm_it8xxx2_cfg *config = dev->config;
	struct pwm_it8xxx2_regs *const inst = config->base;
	volatile uint8_t *reg_dcr = (uint8_t *)config->reg_dcr;
	volatile uint8_t *reg_pwmpol = (uint8_t *)config->reg_pwmpol;
	int ch = config->channel;
	int prs_sel = config->prs_sel;
	uint32_t actual_freq = 0xffffffff, target_freq, deviation, cxcprs, ctr;
	uint64_t pwm_clk_src;

	ARG_UNUSED(pwm);

	/* PWM channel clock source gating before configuring */
	pwm_enable(dev, 0);

	/* Select PWM inverted polarity (ex. active-low pulse) */
	if (flags & PWM_POLARITY_INVERTED) {
		*reg_pwmpol |= BIT(ch);
	} else {
		*reg_pwmpol &= ~BIT(ch);
	}

	/* If pulse cycles is 0, set duty cycle 0 and enable pwm channel */
	if (pulse_cycles == 0) {
		*reg_dcr = 0;
		pwm_enable(dev, 1);
		return 0;
	}

	pwm_it8xxx2_get_cycles_per_sec(dev, pwm, &pwm_clk_src);
	target_freq = ((uint32_t) pwm_clk_src) / period_cycles;

	/*<commit_msg>drivers: pwm: ite_it8xxx2: remove wrong ARG_UNUSED<commit_after>/*
 * Copyright (c) 2021 ITE Corporation. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT ite_it8xxx2_pwm

#include <device.h>
#include <drivers/pwm.h>
#include <drivers/pinmux.h>
#include <dt-bindings/pwm/it8xxx2_pwm.h>
#include <errno.h>
#include <kernel.h>
#include <soc.h>
#include <soc_dt.h>
#include <stdlib.h>

#include <logging/log.h>
LOG_MODULE_REGISTER(pwm_ite_it8xxx2, CONFIG_PWM_LOG_LEVEL);

#define PWM_CTRX_MIN	100
#define PWM_FREQ	EC_FREQ
#define PCSSG_MASK	0x3

/* Device config */
struct pwm_alt_cfg {
	/* Pinmux control device structure */
	const struct device *pinctrls;
	/* GPIO pin */
	uint8_t pin;
	/* Alternate function */
	uint8_t alt_fun;
};

struct pwm_it8xxx2_cfg {
	/* PWM channel duty cycle register */
	uintptr_t reg_dcr;
	/* PWM channel clock source selection register */
	uintptr_t reg_pcssg;
	/* PWM channel clock source gating register */
	uintptr_t reg_pcsgr;
	/* PWM channel output polarity register */
	uintptr_t reg_pwmpol;
	/* PWM channel */
	int channel;
	/* PWM prescaler control register base */
	struct pwm_it8xxx2_regs *base;
	/* Select PWM prescaler that output to PWM channel */
	int prs_sel;
	/* PWM alternate configuration list */
	const struct pwm_alt_cfg *alt_list;
};

static void pwm_enable(const struct device *dev, int enabled)
{
	const struct pwm_it8xxx2_cfg *config = dev->config;
	volatile uint8_t *reg_pcsgr = (uint8_t *)config->reg_pcsgr;
	int ch = config->channel;

	if (enabled) {
		/* PWM channel clock source not gating */
		*reg_pcsgr &= ~BIT(ch);
	} else {
		/* PWM channel clock source gating */
		*reg_pcsgr |= BIT(ch);
	}
}

static int pwm_it8xxx2_get_cycles_per_sec(const struct device *dev,
					     uint32_t pwm, uint64_t *cycles)
{
	ARG_UNUSED(pwm);

	/*
	 * There are three ways to call pwm_it8xxx2_pin_set() from pwm api:
	 * 1) pwm_pin_set_usec() -> pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set()
	 *    target_freq = pwm_clk_src / period_cycles
	 *                = cycles / (period * cycles / USEC_PER_SEC)
	 *                = USEC_PER_SEC / period
	 * 2) pwm_pin_set_nsec() -> pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set()
	 *    target_freq = pwm_clk_src / period_cycles
	 *                = cycles / (period * cycles / NSEC_PER_SEC)
	 *                = NSEC_PER_SEC / period
	 * 3) pwm_pin_set_cycles() -> pwm_it8xxx2_pin_set()
	 *    target_freq = pwm_clk_src / period_cycles
	 *                = cycles / period
	 *
	 * If we need to pwm output in EC power saving mode, then we will switch
	 * the prescaler clock source (cycles) from 8MHz to 32.768kHz. In order
	 * to get the same target_freq in the 3) case, we always return PWM_FREQ.
	 */
	*cycles = (uint64_t) PWM_FREQ;

	return 0;
}

static int pwm_it8xxx2_pin_set(const struct device *dev,
				uint32_t pwm, uint32_t period_cycles,
				uint32_t pulse_cycles, pwm_flags_t flags)
{
	const struct pwm_it8xxx2_cfg *config = dev->config;
	struct pwm_it8xxx2_regs *const inst = config->base;
	volatile uint8_t *reg_dcr = (uint8_t *)config->reg_dcr;
	volatile uint8_t *reg_pwmpol = (uint8_t *)config->reg_pwmpol;
	int ch = config->channel;
	int prs_sel = config->prs_sel;
	uint32_t actual_freq = 0xffffffff, target_freq, deviation, cxcprs, ctr;
	uint64_t pwm_clk_src;

	/* PWM channel clock source gating before configuring */
	pwm_enable(dev, 0);

	/* Select PWM inverted polarity (ex. active-low pulse) */
	if (flags & PWM_POLARITY_INVERTED) {
		*reg_pwmpol |= BIT(ch);
	} else {
		*reg_pwmpol &= ~BIT(ch);
	}

	/* If pulse cycles is 0, set duty cycle 0 and enable pwm channel */
	if (pulse_cycles == 0) {
		*reg_dcr = 0;
		pwm_enable(dev, 1);
		return 0;
	}

	pwm_it8xxx2_get_cycles_per_sec(dev, pwm, &pwm_clk_src);
	target_freq = ((uint32_t) pwm_clk_src) / period_cycles;

	/*
{'fraction_non_alphanumeric': 0.1086329047494096, 'fraction_numerical': 0.02282865389661506, 'mean_word_length': 3.708462013588635, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4599619', 'n_tokens_mistral': 3177, 'n_tokens_neox': 2954, 'n_words': 740}