linux/drivers/hwmon/aspeed-g6-pwm-tach.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2021 Aspeed Technology Inc.
 *
 * PWM/TACH controller driver for Aspeed ast2600 SoCs.
 * This drivers doesn't support earlier version of the IP.
 *
 * The hardware operates in time quantities of length
 * Q := (DIV_L + 1) << DIV_H / input-clk
 * The length of a PWM period is (DUTY_CYCLE_PERIOD + 1) * Q.
 * The maximal value for DUTY_CYCLE_PERIOD is used here to provide
 * a fine grained selection for the duty cycle.
 *
 * This driver uses DUTY_CYCLE_RISING_POINT = 0, so from the start of a
 * period the output is active until DUTY_CYCLE_FALLING_POINT * Q. Note
 * that if DUTY_CYCLE_RISING_POINT = DUTY_CYCLE_FALLING_POINT the output is
 * always active.
 *
 * Register usage:
 * PIN_ENABLE: When it is unset the pwm controller will emit inactive level to the external.
 * Use to determine whether the PWM channel is enabled or disabled
 * CLK_ENABLE: When it is unset the pwm controller will assert the duty counter reset and
 * emit inactive level to the PIN_ENABLE mux after that the driver can still change the pwm period
 * and duty and the value will apply when CLK_ENABLE be set again.
 * Use to determine whether duty_cycle bigger than 0.
 * PWM_ASPEED_CTRL_INVERSE: When it is toggled the output value will inverse immediately.
 * PWM_ASPEED_DUTY_CYCLE_FALLING_POINT/PWM_ASPEED_DUTY_CYCLE_RISING_POINT: When these two
 * values are equal it means the duty cycle = 100%.
 *
 * The glitch may generate at:
 * - Enabled changing when the duty_cycle bigger than 0% and less than 100%.
 * - Polarity changing when the duty_cycle bigger than 0% and less than 100%.
 *
 * Limitations:
 * - When changing both duty cycle and period, we cannot prevent in
 *   software that the output might produce a period with mixed
 *   settings.
 * - Disabling the PWM doesn't complete the current period.
 *
 * Improvements:
 * - When only changing one of duty cycle or period, our pwm controller will not
 *   generate the glitch, the configure will change at next cycle of pwm.
 *   This improvement can disable/enable through PWM_ASPEED_CTRL_DUTY_SYNC_DISABLE.
 */

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/hwmon.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/reset.h>
#include <linux/sysfs.h>

/* The channel number of Aspeed pwm controller */
#define PWM_ASPEED_NR_PWMS
/* PWM Control Register */
#define PWM_ASPEED_CTRL(ch)
#define PWM_ASPEED_CTRL_LOAD_SEL_RISING_AS_WDT
#define PWM_ASPEED_CTRL_DUTY_LOAD_AS_WDT_ENABLE
#define PWM_ASPEED_CTRL_DUTY_SYNC_DISABLE
#define PWM_ASPEED_CTRL_CLK_ENABLE
#define PWM_ASPEED_CTRL_LEVEL_OUTPUT
#define PWM_ASPEED_CTRL_INVERSE
#define PWM_ASPEED_CTRL_OPEN_DRAIN_ENABLE
#define PWM_ASPEED_CTRL_PIN_ENABLE
#define PWM_ASPEED_CTRL_CLK_DIV_H
#define PWM_ASPEED_CTRL_CLK_DIV_L

/* PWM Duty Cycle Register */
#define PWM_ASPEED_DUTY_CYCLE(ch)
#define PWM_ASPEED_DUTY_CYCLE_PERIOD
#define PWM_ASPEED_DUTY_CYCLE_POINT_AS_WDT
#define PWM_ASPEED_DUTY_CYCLE_FALLING_POINT
#define PWM_ASPEED_DUTY_CYCLE_RISING_POINT

/* PWM fixed value */
#define PWM_ASPEED_FIXED_PERIOD

/* The channel number of Aspeed tach controller */
#define TACH_ASPEED_NR_TACHS
/* TACH Control Register */
#define TACH_ASPEED_CTRL(ch)
#define TACH_ASPEED_IER
#define TACH_ASPEED_INVERS_LIMIT
#define TACH_ASPEED_LOOPBACK
#define TACH_ASPEED_ENABLE
#define TACH_ASPEED_DEBOUNCE_MASK
#define TACH_ASPEED_DEBOUNCE_BIT
#define TACH_ASPEED_IO_EDGE_MASK
#define TACH_ASPEED_IO_EDGE_BIT
#define TACH_ASPEED_CLK_DIV_T_MASK
#define TACH_ASPEED_CLK_DIV_BIT
#define TACH_ASPEED_THRESHOLD_MASK
/* [27:26] */
#define DEBOUNCE_3_CLK
#define DEBOUNCE_2_CLK
#define DEBOUNCE_1_CLK
#define DEBOUNCE_0_CLK
/* [25:24] */
#define F2F_EDGES
#define R2R_EDGES
#define BOTH_EDGES
/* [23:20] */
/* divisor = 4 to the nth power, n = register value */
#define DEFAULT_TACH_DIV
#define DIV_TO_REG(divisor)

/* TACH Status Register */
#define TACH_ASPEED_STS(ch)

/*PWM_TACH_STS */
#define TACH_ASPEED_ISR
#define TACH_ASPEED_PWM_OUT
#define TACH_ASPEED_PWM_OEN
#define TACH_ASPEED_DEB_INPUT
#define TACH_ASPEED_RAW_INPUT
#define TACH_ASPEED_VALUE_UPDATE
#define TACH_ASPEED_FULL_MEASUREMENT
#define TACH_ASPEED_VALUE_MASK
/**********************************************************
 * Software setting
 *********************************************************/
#define DEFAULT_FAN_PULSE_PR

struct aspeed_pwm_tach_data {};

static inline struct aspeed_pwm_tach_data *
aspeed_pwm_chip_to_data(struct pwm_chip *chip)
{}

static int aspeed_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
				struct pwm_state *state)
{}

static int aspeed_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
			    const struct pwm_state *state)
{}

static const struct pwm_ops aspeed_pwm_ops =;

static void aspeed_tach_ch_enable(struct aspeed_pwm_tach_data *priv, u8 tach_ch,
				  bool enable)
{}

static int aspeed_tach_val_to_rpm(struct aspeed_pwm_tach_data *priv, u32 tach_val)
{}

static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tach_data *priv,
				      u8 fan_tach_ch)
{}

static int aspeed_tach_hwmon_read(struct device *dev,
				  enum hwmon_sensor_types type, u32 attr,
				  int channel, long *val)
{}

static int aspeed_tach_hwmon_write(struct device *dev,
				   enum hwmon_sensor_types type, u32 attr,
				   int channel, long val)
{}

static umode_t aspeed_tach_dev_is_visible(const void *drvdata,
					  enum hwmon_sensor_types type,
					  u32 attr, int channel)
{}

static const struct hwmon_ops aspeed_tach_ops =;

static const struct hwmon_channel_info *aspeed_tach_info[] =;

static const struct hwmon_chip_info aspeed_tach_chip_info =;

static void aspeed_present_fan_tach(struct aspeed_pwm_tach_data *priv, u8 *tach_ch, int count)
{}

static int aspeed_create_fan_monitor(struct device *dev,
				     struct device_node *child,
				     struct aspeed_pwm_tach_data *priv)
{}

static void aspeed_pwm_tach_reset_assert(void *data)
{}

static int aspeed_pwm_tach_probe(struct platform_device *pdev)
{}

static void aspeed_pwm_tach_remove(struct platform_device *pdev)
{}

static const struct of_device_id aspeed_pwm_tach_match[] =;
MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match);

static struct platform_driver aspeed_pwm_tach_driver =;

module_platform_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();