linux/drivers/hwmon/g762.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * g762 - Driver for the Global Mixed-mode Technology Inc. fan speed
 *        PWM controller chips from G762 family, i.e. G762 and G763
 *
 * Copyright (C) 2013, Arnaud EBALARD <[email protected]>
 *
 * This work is based on a basic version for 2.6.31 kernel developed
 * by Olivier Mouchet for LaCie. Updates and correction have been
 * performed to run on recent kernels. Additional features, like the
 * ability to configure various characteristics via .dts file or
 * board init file have been added. Detailed datasheet on which this
 * development is based is available here:
 *
 *  http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf
 *
 * Headers from previous developments have been kept below:
 *
 * Copyright (c) 2009 LaCie
 *
 * Author: Olivier Mouchet <[email protected]>
 *
 * based on g760a code written by Herbert Valerio Riedel <[email protected]>
 * Copyright (C) 2007  Herbert Valerio Riedel <[email protected]>
 *
 * g762: minimal datasheet available at:
 *       http://www.gmt.com.tw/product/datasheet/EDS-762_3.pdf
 */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/platform_data/g762.h>

#define DRVNAME

static const struct i2c_device_id g762_id[] =;
MODULE_DEVICE_TABLE(i2c, g762_id);

enum g762_regs {};

/* Config register bits */
#define G762_REG_FAN_CMD1_DET_FAN_FAIL
#define G762_REG_FAN_CMD1_DET_FAN_OOC
#define G762_REG_FAN_CMD1_OUT_MODE
#define G762_REG_FAN_CMD1_FAN_MODE
#define G762_REG_FAN_CMD1_CLK_DIV_ID1
#define G762_REG_FAN_CMD1_CLK_DIV_ID0
#define G762_REG_FAN_CMD1_PWM_POLARITY
#define G762_REG_FAN_CMD1_PULSE_PER_REV

#define G761_REG_FAN_CMD2_FAN_CLOCK
#define G762_REG_FAN_CMD2_GEAR_MODE_1
#define G762_REG_FAN_CMD2_GEAR_MODE_0
#define G762_REG_FAN_CMD2_FAN_STARTV_1
#define G762_REG_FAN_CMD2_FAN_STARTV_0

#define G762_REG_FAN_STA_FAIL
#define G762_REG_FAN_STA_OOC

/* Config register values */
#define G762_OUT_MODE_PWM
#define G762_OUT_MODE_DC

#define G762_FAN_MODE_CLOSED_LOOP
#define G762_FAN_MODE_OPEN_LOOP

#define G762_PWM_POLARITY_NEGATIVE
#define G762_PWM_POLARITY_POSITIVE

/* Register data is read (and cached) at most once per second. */
#define G762_UPDATE_INTERVAL

/*
 * Extract pulse count per fan revolution value (2 or 4) from given
 * FAN_CMD1 register value.
 */
#define G762_PULSE_FROM_REG(reg)

/*
 * Extract fan clock divisor (1, 2, 4 or 8) from given FAN_CMD1
 * register value.
 */
#define G762_CLKDIV_FROM_REG(reg)

/*
 * Extract fan gear mode multiplier value (0, 2 or 4) from given
 * FAN_CMD2 register value.
 */
#define G762_GEARMULT_FROM_REG(reg)

struct g762_data {};

/*
 * Convert count value from fan controller register (FAN_SET_CNT) into fan
 * speed RPM value. Note that the datasheet documents a basic formula;
 * influence of additional parameters (fan clock divisor, fan gear mode)
 * have been infered from examples in the datasheet and tests.
 */
static inline unsigned int rpm_from_cnt(u8 cnt, u32 clk_freq, u16 p,
					u8 clk_div, u8 gear_mult)
{}

/*
 * Convert fan RPM value from sysfs into count value for fan controller
 * register (FAN_SET_CNT).
 */
static inline unsigned char cnt_from_rpm(unsigned long rpm, u32 clk_freq, u16 p,
					 u8 clk_div, u8 gear_mult)
{}

/* helper to grab and cache data, at most one time per second */
static struct g762_data *g762_update_client(struct device *dev)
{}

/* helpers for writing hardware parameters */

/*
 * Set input clock frequency received on CLK pin of the chip. Accepted values
 * are between 0 and 0xffffff. If zero is given, then default frequency
 * (32,768Hz) is used. Note that clock frequency is a characteristic of the
 * system but an internal parameter, i.e. value is not passed to the device.
 */
static int do_set_clk_freq(struct device *dev, unsigned long val)
{}

/* Set pwm mode. Accepts either 0 (PWM mode) or 1 (DC mode) */
static int do_set_pwm_mode(struct device *dev, unsigned long val)
{}

/* Set fan clock divisor. Accepts either 1, 2, 4 or 8. */
static int do_set_fan_div(struct device *dev, unsigned long val)
{}

/* Set fan gear mode. Accepts either 0, 1 or 2. */
static int do_set_fan_gear_mode(struct device *dev, unsigned long val)
{}

/* Set number of fan pulses per revolution. Accepts either 2 or 4. */
static int do_set_fan_pulses(struct device *dev, unsigned long val)
{}

/* Set fan mode. Accepts either 1 (open-loop) or 2 (closed-loop). */
static int do_set_pwm_enable(struct device *dev, unsigned long val)
{}

/* Set PWM polarity. Accepts either 0 (positive duty) or 1 (negative duty) */
static int do_set_pwm_polarity(struct device *dev, unsigned long val)
{}

/*
 * Set pwm value. Accepts values between 0 (stops the fan) and
 * 255 (full speed). This only makes sense in open-loop mode.
 */
static int do_set_pwm(struct device *dev, unsigned long val)
{}

/*
 * Set fan RPM value. Can be called both in closed and open-loop mode
 * but effect will only be seen after closed-loop mode is configured.
 */
static int do_set_fan_target(struct device *dev, unsigned long val)
{}

/* Set fan startup voltage. Accepted values are either 0, 1, 2 or 3. */
static int do_set_fan_startv(struct device *dev, unsigned long val)
{}

/*
 * Helper to import hardware characteristics from .dts file and push
 * those to the chip.
 */

#ifdef CONFIG_OF
static const struct of_device_id g762_dt_match[] =;
MODULE_DEVICE_TABLE(of, g762_dt_match);

/*
 * Grab clock (a required property), enable it, get (fixed) clock frequency
 * and store it. Note: upon success, clock has been prepared and enabled; it
 * must later be unprepared and disabled (e.g. during module unloading) by a
 * call to g762_of_clock_disable(). Note that a reference to clock is kept
 * in our private data structure to be used in this function.
 */
static void g762_of_clock_disable(void *data)
{}

static int g762_of_clock_enable(struct i2c_client *client)
{}

static int g762_of_prop_import_one(struct i2c_client *client,
				   const char *pname,
				   int (*psetter)(struct device *dev,
						  unsigned long val))
{}

static int g762_of_prop_import(struct i2c_client *client)
{}

#else
static int g762_of_prop_import(struct i2c_client *client)
{
	return 0;
}

static int g762_of_clock_enable(struct i2c_client *client)
{
	return 0;
}
#endif

/*
 * Helper to import hardware characteristics from .dts file and push
 * those to the chip.
 */

static int g762_pdata_prop_import(struct i2c_client *client)
{}

/*
 * sysfs attributes
 */

/*
 * Read function for fan1_input sysfs file. Return current fan RPM value, or
 * 0 if fan is out of control.
 */
static ssize_t fan1_input_show(struct device *dev,
			       struct device_attribute *da, char *buf)
{}

/*
 * Read and write functions for pwm1_mode sysfs file. Get and set fan speed
 * control mode i.e. PWM (1) or DC (0).
 */
static ssize_t pwm1_mode_show(struct device *dev, struct device_attribute *da,
			      char *buf)
{}

static ssize_t pwm1_mode_store(struct device *dev,
			       struct device_attribute *da, const char *buf,
			       size_t count)
{}

/*
 * Read and write functions for fan1_div sysfs file. Get and set fan
 * controller prescaler value
 */
static ssize_t fan1_div_show(struct device *dev, struct device_attribute *da,
			     char *buf)
{}

static ssize_t fan1_div_store(struct device *dev, struct device_attribute *da,
			      const char *buf, size_t count)
{}

/*
 * Read and write functions for fan1_pulses sysfs file. Get and set number
 * of tachometer pulses per fan revolution.
 */
static ssize_t fan1_pulses_show(struct device *dev,
				struct device_attribute *da, char *buf)
{}

static ssize_t fan1_pulses_store(struct device *dev,
				 struct device_attribute *da, const char *buf,
				 size_t count)
{}

/*
 * Read and write functions for pwm1_enable. Get and set fan speed control mode
 * (i.e. closed or open-loop).
 *
 * Following documentation about hwmon's sysfs interface, a pwm1_enable node
 * should accept the following:
 *
 *  0 : no fan speed control (i.e. fan at full speed)
 *  1 : manual fan speed control enabled (use pwm[1-*]) (open-loop)
 *  2+: automatic fan speed control enabled (use fan[1-*]_target) (closed-loop)
 *
 * but we do not accept 0 as this mode is not natively supported by the chip
 * and it is not emulated by g762 driver. -EINVAL is returned in this case.
 */
static ssize_t pwm1_enable_show(struct device *dev,
				struct device_attribute *da, char *buf)
{}

static ssize_t pwm1_enable_store(struct device *dev,
				 struct device_attribute *da, const char *buf,
				 size_t count)
{}

/*
 * Read and write functions for pwm1 sysfs file. Get and set pwm value
 * (which affects fan speed) in open-loop mode. 0 stops the fan and 255
 * makes it run at full speed.
 */
static ssize_t pwm1_show(struct device *dev, struct device_attribute *da,
			 char *buf)
{}

static ssize_t pwm1_store(struct device *dev, struct device_attribute *da,
			  const char *buf, size_t count)
{}

/*
 * Read and write function for fan1_target sysfs file. Get/set the fan speed in
 * closed-loop mode. Speed is given as a RPM value; then the chip will regulate
 * the fan speed using pulses from fan tachometer.
 *
 * Refer to rpm_from_cnt() implementation above to get info about count number
 * calculation.
 *
 * Also note that due to rounding errors it is possible that you don't read
 * back exactly the value you have set.
 */
static ssize_t fan1_target_show(struct device *dev,
				struct device_attribute *da, char *buf)
{}

static ssize_t fan1_target_store(struct device *dev,
				 struct device_attribute *da, const char *buf,
				 size_t count)
{}

/* read function for fan1_fault sysfs file. */
static ssize_t fan1_fault_show(struct device *dev, struct device_attribute *da,
			       char *buf)
{}

/*
 * read function for fan1_alarm sysfs file. Note that OOC condition is
 * enabled low
 */
static ssize_t fan1_alarm_show(struct device *dev,
			       struct device_attribute *da, char *buf)
{}

static DEVICE_ATTR_RW(pwm1);
static DEVICE_ATTR_RW(pwm1_mode);
static DEVICE_ATTR_RW(pwm1_enable);
static DEVICE_ATTR_RO(fan1_input);
static DEVICE_ATTR_RO(fan1_alarm);
static DEVICE_ATTR_RO(fan1_fault);
static DEVICE_ATTR_RW(fan1_target);
static DEVICE_ATTR_RW(fan1_div);
static DEVICE_ATTR_RW(fan1_pulses);

/* Driver data */
static struct attribute *g762_attrs[] =;

ATTRIBUTE_GROUPS();

/*
 * Enable both fan failure detection and fan out of control protection. The
 * function does not protect change/access to data structure; it must thus
 * only be called during initialization.
 */
static inline int g762_fan_init(struct device *dev)
{}

static int g762_probe(struct i2c_client *client)
{}

static struct i2c_driver g762_driver =;

module_i2c_driver();

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