mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 09:13:55 +08:00
6cd3209967
This replaces the old therm_pm72 using the same windfarm infrastructure that was used for other PowerMac G5 models. The fan speeds and sensors should now be visible in the same location in sysfs. The driver is split into separate core modules for PowerMac7,2 (and 7,3) and RackMac3,1, with a lot of the shared code now in the separate sensor and control modules. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
162 lines
4.3 KiB
C
162 lines
4.3 KiB
C
/*
|
|
* Windfarm PowerMac thermal control.
|
|
*
|
|
* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
|
|
* <benh@kernel.crashing.org>
|
|
*
|
|
* Released under the term of the GNU GPL v2.
|
|
*/
|
|
|
|
#ifndef __WINDFARM_H__
|
|
#define __WINDFARM_H__
|
|
|
|
#include <linux/kref.h>
|
|
#include <linux/list.h>
|
|
#include <linux/module.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/device.h>
|
|
|
|
/* Display a 16.16 fixed point value */
|
|
#define FIX32TOPRINT(f) (((s32)(f)) >> 16),(((((s32)(f)) & 0xffff) * 1000) >> 16)
|
|
|
|
/*
|
|
* Control objects
|
|
*/
|
|
|
|
struct wf_control;
|
|
|
|
struct wf_control_ops {
|
|
int (*set_value)(struct wf_control *ct, s32 val);
|
|
int (*get_value)(struct wf_control *ct, s32 *val);
|
|
s32 (*get_min)(struct wf_control *ct);
|
|
s32 (*get_max)(struct wf_control *ct);
|
|
void (*release)(struct wf_control *ct);
|
|
struct module *owner;
|
|
};
|
|
|
|
struct wf_control {
|
|
struct list_head link;
|
|
const struct wf_control_ops *ops;
|
|
const char *name;
|
|
int type;
|
|
struct kref ref;
|
|
struct device_attribute attr;
|
|
void *priv;
|
|
};
|
|
|
|
#define WF_CONTROL_TYPE_GENERIC 0
|
|
#define WF_CONTROL_RPM_FAN 1
|
|
#define WF_CONTROL_PWM_FAN 2
|
|
|
|
|
|
/* Note about lifetime rules: wf_register_control() will initialize
|
|
* the kref and wf_unregister_control will decrement it, thus the
|
|
* object creating/disposing a given control shouldn't assume it
|
|
* still exists after wf_unregister_control has been called.
|
|
* wf_find_control will inc the refcount for you
|
|
*/
|
|
extern int wf_register_control(struct wf_control *ct);
|
|
extern void wf_unregister_control(struct wf_control *ct);
|
|
extern struct wf_control * wf_find_control(const char *name);
|
|
extern int wf_get_control(struct wf_control *ct);
|
|
extern void wf_put_control(struct wf_control *ct);
|
|
|
|
static inline int wf_control_set_max(struct wf_control *ct)
|
|
{
|
|
s32 vmax = ct->ops->get_max(ct);
|
|
return ct->ops->set_value(ct, vmax);
|
|
}
|
|
|
|
static inline int wf_control_set_min(struct wf_control *ct)
|
|
{
|
|
s32 vmin = ct->ops->get_min(ct);
|
|
return ct->ops->set_value(ct, vmin);
|
|
}
|
|
|
|
static inline int wf_control_set(struct wf_control *ct, s32 val)
|
|
{
|
|
return ct->ops->set_value(ct, val);
|
|
}
|
|
|
|
static inline int wf_control_get(struct wf_control *ct, s32 *val)
|
|
{
|
|
return ct->ops->get_value(ct, val);
|
|
}
|
|
|
|
static inline s32 wf_control_get_min(struct wf_control *ct)
|
|
{
|
|
return ct->ops->get_min(ct);
|
|
}
|
|
|
|
static inline s32 wf_control_get_max(struct wf_control *ct)
|
|
{
|
|
return ct->ops->get_max(ct);
|
|
}
|
|
|
|
/*
|
|
* Sensor objects
|
|
*/
|
|
|
|
struct wf_sensor;
|
|
|
|
struct wf_sensor_ops {
|
|
int (*get_value)(struct wf_sensor *sr, s32 *val);
|
|
void (*release)(struct wf_sensor *sr);
|
|
struct module *owner;
|
|
};
|
|
|
|
struct wf_sensor {
|
|
struct list_head link;
|
|
const struct wf_sensor_ops *ops;
|
|
const char *name;
|
|
struct kref ref;
|
|
struct device_attribute attr;
|
|
void *priv;
|
|
};
|
|
|
|
/* Same lifetime rules as controls */
|
|
extern int wf_register_sensor(struct wf_sensor *sr);
|
|
extern void wf_unregister_sensor(struct wf_sensor *sr);
|
|
extern struct wf_sensor * wf_find_sensor(const char *name);
|
|
extern int wf_get_sensor(struct wf_sensor *sr);
|
|
extern void wf_put_sensor(struct wf_sensor *sr);
|
|
|
|
static inline int wf_sensor_get(struct wf_sensor *sr, s32 *val)
|
|
{
|
|
return sr->ops->get_value(sr, val);
|
|
}
|
|
|
|
/* For use by clients. Note that we are a bit racy here since
|
|
* notifier_block doesn't have a module owner field. I may fix
|
|
* it one day ...
|
|
*
|
|
* LOCKING NOTE !
|
|
*
|
|
* All "events" except WF_EVENT_TICK are called with an internal mutex
|
|
* held which will deadlock if you call basically any core routine.
|
|
* So don't ! Just take note of the event and do your actual operations
|
|
* from the ticker.
|
|
*
|
|
*/
|
|
extern int wf_register_client(struct notifier_block *nb);
|
|
extern int wf_unregister_client(struct notifier_block *nb);
|
|
|
|
/* Overtemp conditions. Those are refcounted */
|
|
extern void wf_set_overtemp(void);
|
|
extern void wf_clear_overtemp(void);
|
|
extern int wf_is_overtemp(void);
|
|
|
|
#define WF_EVENT_NEW_CONTROL 0 /* param is wf_control * */
|
|
#define WF_EVENT_NEW_SENSOR 1 /* param is wf_sensor * */
|
|
#define WF_EVENT_OVERTEMP 2 /* no param */
|
|
#define WF_EVENT_NORMALTEMP 3 /* overtemp condition cleared */
|
|
#define WF_EVENT_TICK 4 /* 1 second tick */
|
|
|
|
/* Note: If that driver gets more broad use, we could replace the
|
|
* simplistic overtemp bits with "environmental conditions". That
|
|
* could then be used to also notify of things like fan failure,
|
|
* case open, battery conditions, ...
|
|
*/
|
|
|
|
#endif /* __WINDFARM_H__ */
|