2c162f9b41722 (Thomas Gleixner 2019-06-03 07:45:02 +0200 1) // SPDX-License-Identifier: GPL-2.0-only
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 2) /*
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 3) * Windfarm PowerMac thermal control. FCU fan control
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 4) *
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 5) * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 6) */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 7) #undef DEBUG
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 8)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 9) #include <linux/types.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 10) #include <linux/errno.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 11) #include <linux/kernel.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 12) #include <linux/delay.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 13) #include <linux/slab.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 14) #include <linux/init.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 15) #include <linux/wait.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 16) #include <linux/i2c.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 17) #include <asm/prom.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 18) #include <asm/machdep.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 19) #include <asm/io.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 20) #include <asm/sections.h>
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 21)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 22) #include "windfarm.h"
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 23) #include "windfarm_mpu.h"
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 24)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 25) #define VERSION "1.0"
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 26)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 27) #ifdef DEBUG
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 28) #define DBG(args...) printk(args)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 29) #else
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 30) #define DBG(args...) do { } while(0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 31) #endif
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 32)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 33) /*
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 34) * This option is "weird" :) Basically, if you define this to 1
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 35) * the control loop for the RPMs fans (not PWMs) will apply the
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 36) * correction factor obtained from the PID to the actual RPM
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 37) * speed read from the FCU.
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 38) *
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 39) * If you define the below constant to 0, then it will be
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 40) * applied to the setpoint RPM speed, that is basically the
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 41) * speed we proviously "asked" for.
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 42) *
6cd3209967469 (Benjamin Herrenschmidt 2012-04-29 15:42:27 +0000 43) * I'm using 0 for now which is what therm_pm72 used to do and
6cd3209967469 (Benjamin Herrenschmidt 2012-04-29 15:42:27 +0000 44) * what Darwin -apparently- does based on observed behaviour.
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 45) */
6cd3209967469 (Benjamin Herrenschmidt 2012-04-29 15:42:27 +0000 46) #define RPM_PID_USE_ACTUAL_SPEED 0
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 47)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 48) /* Default min/max for pumps */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 49) #define CPU_PUMP_OUTPUT_MAX 3200
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 50) #define CPU_PUMP_OUTPUT_MIN 1250
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 51)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 52) #define FCU_FAN_RPM 0
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 53) #define FCU_FAN_PWM 1
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 54)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 55) struct wf_fcu_priv {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 56) struct kref ref;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 57) struct i2c_client *i2c;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 58) struct mutex lock;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 59) struct list_head fan_list;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 60) int rpm_shift;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 61) };
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 62)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 63) struct wf_fcu_fan {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 64) struct list_head link;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 65) int id;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 66) s32 min, max, target;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 67) struct wf_fcu_priv *fcu_priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 68) struct wf_control ctrl;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 69) };
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 70)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 71) static void wf_fcu_release(struct kref *ref)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 72) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 73) struct wf_fcu_priv *pv = container_of(ref, struct wf_fcu_priv, ref);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 74)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 75) kfree(pv);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 76) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 77)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 78) static void wf_fcu_fan_release(struct wf_control *ct)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 79) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 80) struct wf_fcu_fan *fan = ct->priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 81)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 82) kref_put(&fan->fcu_priv->ref, wf_fcu_release);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 83) kfree(fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 84) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 85)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 86) static int wf_fcu_read_reg(struct wf_fcu_priv *pv, int reg,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 87) unsigned char *buf, int nb)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 88) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 89) int tries, nr, nw;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 90)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 91) mutex_lock(&pv->lock);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 92)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 93) buf[0] = reg;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 94) tries = 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 95) for (;;) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 96) nw = i2c_master_send(pv->i2c, buf, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 97) if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 98) break;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 99) msleep(10);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 100) ++tries;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 101) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 102) if (nw <= 0) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 103) pr_err("Failure writing address to FCU: %d", nw);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 104) nr = nw;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 105) goto bail;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 106) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 107) tries = 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 108) for (;;) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 109) nr = i2c_master_recv(pv->i2c, buf, nb);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 110) if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 111) break;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 112) msleep(10);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 113) ++tries;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 114) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 115) if (nr <= 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 116) pr_err("wf_fcu: Failure reading data from FCU: %d", nw);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 117) bail:
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 118) mutex_unlock(&pv->lock);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 119) return nr;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 120) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 121)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 122) static int wf_fcu_write_reg(struct wf_fcu_priv *pv, int reg,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 123) const unsigned char *ptr, int nb)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 124) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 125) int tries, nw;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 126) unsigned char buf[16];
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 127)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 128) buf[0] = reg;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 129) memcpy(buf+1, ptr, nb);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 130) ++nb;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 131) tries = 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 132) for (;;) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 133) nw = i2c_master_send(pv->i2c, buf, nb);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 134) if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 135) break;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 136) msleep(10);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 137) ++tries;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 138) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 139) if (nw < 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 140) pr_err("wf_fcu: Failure writing to FCU: %d", nw);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 141) return nw;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 142) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 143)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 144) static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 145) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 146) struct wf_fcu_fan *fan = ct->priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 147) struct wf_fcu_priv *pv = fan->fcu_priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 148) int rc, shift = pv->rpm_shift;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 149) unsigned char buf[2];
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 150)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 151) if (value < fan->min)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 152) value = fan->min;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 153) if (value > fan->max)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 154) value = fan->max;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 155)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 156) fan->target = value;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 157)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 158) buf[0] = value >> (8 - shift);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 159) buf[1] = value << shift;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 160) rc = wf_fcu_write_reg(pv, 0x10 + (fan->id * 2), buf, 2);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 161) if (rc < 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 162) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 163) return 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 164) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 165)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 166) static int wf_fcu_fan_get_rpm(struct wf_control *ct, s32 *value)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 167) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 168) struct wf_fcu_fan *fan = ct->priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 169) struct wf_fcu_priv *pv = fan->fcu_priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 170) int rc, reg_base, shift = pv->rpm_shift;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 171) unsigned char failure;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 172) unsigned char active;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 173) unsigned char buf[2];
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 174)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 175) rc = wf_fcu_read_reg(pv, 0xb, &failure, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 176) if (rc != 1)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 177) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 178) if ((failure & (1 << fan->id)) != 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 179) return -EFAULT;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 180) rc = wf_fcu_read_reg(pv, 0xd, &active, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 181) if (rc != 1)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 182) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 183) if ((active & (1 << fan->id)) == 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 184) return -ENXIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 185)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 186) /* Programmed value or real current speed */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 187) #if RPM_PID_USE_ACTUAL_SPEED
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 188) reg_base = 0x11;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 189) #else
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 190) reg_base = 0x10;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 191) #endif
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 192) rc = wf_fcu_read_reg(pv, reg_base + (fan->id * 2), buf, 2);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 193) if (rc != 2)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 194) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 195)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 196) *value = (buf[0] << (8 - shift)) | buf[1] >> shift;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 197)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 198) return 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 199) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 200)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 201) static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 202) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 203) struct wf_fcu_fan *fan = ct->priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 204) struct wf_fcu_priv *pv = fan->fcu_priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 205) unsigned char buf[2];
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 206) int rc;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 207)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 208) if (value < fan->min)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 209) value = fan->min;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 210) if (value > fan->max)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 211) value = fan->max;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 212)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 213) fan->target = value;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 214)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 215) value = (value * 2559) / 1000;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 216) buf[0] = value;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 217) rc = wf_fcu_write_reg(pv, 0x30 + (fan->id * 2), buf, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 218) if (rc < 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 219) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 220) return 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 221) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 222)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 223) static int wf_fcu_fan_get_pwm(struct wf_control *ct, s32 *value)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 224) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 225) struct wf_fcu_fan *fan = ct->priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 226) struct wf_fcu_priv *pv = fan->fcu_priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 227) unsigned char failure;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 228) unsigned char active;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 229) unsigned char buf[2];
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 230) int rc;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 231)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 232) rc = wf_fcu_read_reg(pv, 0x2b, &failure, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 233) if (rc != 1)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 234) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 235) if ((failure & (1 << fan->id)) != 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 236) return -EFAULT;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 237) rc = wf_fcu_read_reg(pv, 0x2d, &active, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 238) if (rc != 1)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 239) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 240) if ((active & (1 << fan->id)) == 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 241) return -ENXIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 242)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 243) rc = wf_fcu_read_reg(pv, 0x30 + (fan->id * 2), buf, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 244) if (rc != 1)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 245) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 246)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 247) *value = (((s32)buf[0]) * 1000) / 2559;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 248)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 249) return 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 250) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 251)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 252) static s32 wf_fcu_fan_min(struct wf_control *ct)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 253) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 254) struct wf_fcu_fan *fan = ct->priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 255)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 256) return fan->min;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 257) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 258)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 259) static s32 wf_fcu_fan_max(struct wf_control *ct)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 260) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 261) struct wf_fcu_fan *fan = ct->priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 262)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 263) return fan->max;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 264) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 265)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 266) static const struct wf_control_ops wf_fcu_fan_rpm_ops = {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 267) .set_value = wf_fcu_fan_set_rpm,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 268) .get_value = wf_fcu_fan_get_rpm,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 269) .get_min = wf_fcu_fan_min,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 270) .get_max = wf_fcu_fan_max,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 271) .release = wf_fcu_fan_release,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 272) .owner = THIS_MODULE,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 273) };
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 274)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 275) static const struct wf_control_ops wf_fcu_fan_pwm_ops = {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 276) .set_value = wf_fcu_fan_set_pwm,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 277) .get_value = wf_fcu_fan_get_pwm,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 278) .get_min = wf_fcu_fan_min,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 279) .get_max = wf_fcu_fan_max,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 280) .release = wf_fcu_fan_release,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 281) .owner = THIS_MODULE,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 282) };
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 283)
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 284) static void wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 285) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 286) const struct mpu_data *mpu = wf_get_mpu(0);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 287) u16 pump_min = 0, pump_max = 0xffff;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 288) u16 tmp[4];
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 289)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 290) /* Try to fetch pumps min/max infos from eeprom */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 291) if (mpu) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 292) memcpy(&tmp, mpu->processor_part_num, 8);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 293) if (tmp[0] != 0xffff && tmp[1] != 0xffff) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 294) pump_min = max(pump_min, tmp[0]);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 295) pump_max = min(pump_max, tmp[1]);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 296) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 297) if (tmp[2] != 0xffff && tmp[3] != 0xffff) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 298) pump_min = max(pump_min, tmp[2]);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 299) pump_max = min(pump_max, tmp[3]);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 300) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 301) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 302)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 303) /* Double check the values, this _IS_ needed as the EEPROM on
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 304) * some dual 2.5Ghz G5s seem, at least, to have both min & max
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 305) * same to the same value ... (grrrr)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 306) */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 307) if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 308) pump_min = CPU_PUMP_OUTPUT_MIN;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 309) pump_max = CPU_PUMP_OUTPUT_MAX;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 310) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 311)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 312) fan->min = pump_min;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 313) fan->max = pump_max;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 314)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 315) DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n",
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 316) fan->ctrl.name, pump_min, pump_max);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 317) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 318)
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 319) static void wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 320) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 321) struct wf_fcu_priv *pv = fan->fcu_priv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 322) const struct mpu_data *mpu0 = wf_get_mpu(0);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 323) const struct mpu_data *mpu1 = wf_get_mpu(1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 324)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 325) /* Default */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 326) fan->min = 2400 >> pv->rpm_shift;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 327) fan->max = 56000 >> pv->rpm_shift;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 328)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 329) /* CPU fans have min/max in MPU */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 330) if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 331) fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 332) fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 333) goto bail;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 334) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 335) if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 336) fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 337) fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 338) goto bail;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 339) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 340) if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 341) fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 342) fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 343) goto bail;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 344) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 345) if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 346) fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 347) fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 348) goto bail;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 349) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 350) /* Rackmac variants, we just use mpu0 intake */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 351) if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 352) fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 353) fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 354) goto bail;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 355) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 356) bail:
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 357) DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n",
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 358) fan->ctrl.name, fan->min, fan->max);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 359) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 360)
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 361) static void wf_fcu_add_fan(struct wf_fcu_priv *pv, const char *name,
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 362) int type, int id)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 363) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 364) struct wf_fcu_fan *fan;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 365)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 366) fan = kzalloc(sizeof(*fan), GFP_KERNEL);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 367) if (!fan)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 368) return;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 369) fan->fcu_priv = pv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 370) fan->id = id;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 371) fan->ctrl.name = name;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 372) fan->ctrl.priv = fan;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 373)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 374) /* min/max is oddball but the code comes from
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 375) * therm_pm72 which seems to work so ...
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 376) */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 377) if (type == FCU_FAN_RPM) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 378) if (!strncmp(name, "cpu-pump", strlen("cpu-pump")))
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 379) wf_fcu_get_pump_minmax(fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 380) else
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 381) wf_fcu_get_rpmfan_minmax(fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 382) fan->ctrl.type = WF_CONTROL_RPM_FAN;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 383) fan->ctrl.ops = &wf_fcu_fan_rpm_ops;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 384) } else {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 385) fan->min = 10;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 386) fan->max = 100;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 387) fan->ctrl.type = WF_CONTROL_PWM_FAN;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 388) fan->ctrl.ops = &wf_fcu_fan_pwm_ops;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 389) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 390)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 391) if (wf_register_control(&fan->ctrl)) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 392) pr_err("wf_fcu: Failed to register fan %s\n", name);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 393) kfree(fan);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 394) return;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 395) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 396) list_add(&fan->link, &pv->fan_list);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 397) kref_get(&pv->ref);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 398) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 399)
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 400) static void wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 401) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 402) /* Translation of device-tree location properties to
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 403) * windfarm fan names
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 404) */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 405) static const struct {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 406) const char *dt_name; /* Device-tree name */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 407) const char *ct_name; /* Control name */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 408) } loc_trans[] = {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 409) { "BACKSIDE", "backside-fan", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 410) { "SYS CTRLR FAN", "backside-fan", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 411) { "DRIVE BAY", "drive-bay-fan", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 412) { "SLOT", "slots-fan", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 413) { "PCI FAN", "slots-fan", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 414) { "CPU A INTAKE", "cpu-front-fan-0", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 415) { "CPU A EXHAUST", "cpu-rear-fan-0", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 416) { "CPU B INTAKE", "cpu-front-fan-1", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 417) { "CPU B EXHAUST", "cpu-rear-fan-1", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 418) { "CPU A PUMP", "cpu-pump-0", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 419) { "CPU B PUMP", "cpu-pump-1", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 420) { "CPU A 1", "cpu-fan-a-0", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 421) { "CPU A 2", "cpu-fan-b-0", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 422) { "CPU A 3", "cpu-fan-c-0", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 423) { "CPU B 1", "cpu-fan-a-1", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 424) { "CPU B 2", "cpu-fan-b-1", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 425) { "CPU B 3", "cpu-fan-c-1", },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 426) };
15b680c474afd (Rob Herring 2018-11-16 16:05:39 -0600 427) struct device_node *np, *fcu = pv->i2c->dev.of_node;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 428) int i;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 429)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 430) DBG("Looking up FCU controls in device-tree...\n");
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 431)
15b680c474afd (Rob Herring 2018-11-16 16:05:39 -0600 432) for_each_child_of_node(fcu, np) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 433) int id, type = -1;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 434) const char *loc;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 435) const char *name;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 436) const u32 *reg;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 437)
15b680c474afd (Rob Herring 2018-11-16 16:05:39 -0600 438) DBG(" control: %pOFn, type: %s\n", np, of_node_get_device_type(np));
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 439)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 440) /* Detect control type */
bf82d3758d4a0 (Rob Herring 2018-11-16 16:11:01 -0600 441) if (of_node_is_type(np, "fan-rpm-control") ||
bf82d3758d4a0 (Rob Herring 2018-11-16 16:11:01 -0600 442) of_node_is_type(np, "fan-rpm"))
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 443) type = FCU_FAN_RPM;
bf82d3758d4a0 (Rob Herring 2018-11-16 16:11:01 -0600 444) if (of_node_is_type(np, "fan-pwm-control") ||
bf82d3758d4a0 (Rob Herring 2018-11-16 16:11:01 -0600 445) of_node_is_type(np, "fan-pwm"))
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 446) type = FCU_FAN_PWM;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 447) /* Only care about fans for now */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 448) if (type == -1)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 449) continue;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 450)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 451) /* Lookup for a matching location */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 452) loc = of_get_property(np, "location", NULL);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 453) reg = of_get_property(np, "reg", NULL);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 454) if (loc == NULL || reg == NULL)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 455) continue;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 456) DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 457)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 458) for (i = 0; i < ARRAY_SIZE(loc_trans); i++) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 459) if (strncmp(loc, loc_trans[i].dt_name,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 460) strlen(loc_trans[i].dt_name)))
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 461) continue;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 462) name = loc_trans[i].ct_name;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 463)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 464) DBG(" location match, name: %s\n", name);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 465)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 466) if (type == FCU_FAN_RPM)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 467) id = ((*reg) - 0x10) / 2;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 468) else
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 469) id = ((*reg) - 0x30) / 2;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 470) if (id > 7) {
2ee9a0db924ed (Kefeng Wang 2019-10-18 11:18:32 +0800 471) pr_warn("wf_fcu: Can't parse fan ID in device-tree for %pOF\n", np);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 472) break;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 473) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 474) wf_fcu_add_fan(pv, name, type, id);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 475) break;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 476) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 477) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 478) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 479)
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 480) static void wf_fcu_default_fans(struct wf_fcu_priv *pv)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 481) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 482) /* We only support the default fans for PowerMac7,2 */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 483) if (!of_machine_is_compatible("PowerMac7,2"))
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 484) return;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 485)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 486) wf_fcu_add_fan(pv, "backside-fan", FCU_FAN_PWM, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 487) wf_fcu_add_fan(pv, "drive-bay-fan", FCU_FAN_RPM, 2);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 488) wf_fcu_add_fan(pv, "slots-fan", FCU_FAN_PWM, 2);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 489) wf_fcu_add_fan(pv, "cpu-front-fan-0", FCU_FAN_RPM, 3);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 490) wf_fcu_add_fan(pv, "cpu-rear-fan-0", FCU_FAN_RPM, 4);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 491) wf_fcu_add_fan(pv, "cpu-front-fan-1", FCU_FAN_RPM, 5);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 492) wf_fcu_add_fan(pv, "cpu-rear-fan-1", FCU_FAN_RPM, 6);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 493) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 494)
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 495) static int wf_fcu_init_chip(struct wf_fcu_priv *pv)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 496) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 497) unsigned char buf = 0xff;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 498) int rc;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 499)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 500) rc = wf_fcu_write_reg(pv, 0xe, &buf, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 501) if (rc < 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 502) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 503) rc = wf_fcu_write_reg(pv, 0x2e, &buf, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 504) if (rc < 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 505) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 506) rc = wf_fcu_read_reg(pv, 0, &buf, 1);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 507) if (rc < 0)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 508) return -EIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 509) pv->rpm_shift = (buf == 1) ? 2 : 3;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 510)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 511) pr_debug("wf_fcu: FCU Initialized, RPM fan shift is %d\n",
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 512) pv->rpm_shift);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 513)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 514) return 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 515) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 516)
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 517) static int wf_fcu_probe(struct i2c_client *client,
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 518) const struct i2c_device_id *id)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 519) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 520) struct wf_fcu_priv *pv;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 521)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 522) pv = kzalloc(sizeof(*pv), GFP_KERNEL);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 523) if (!pv)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 524) return -ENOMEM;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 525)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 526) kref_init(&pv->ref);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 527) mutex_init(&pv->lock);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 528) INIT_LIST_HEAD(&pv->fan_list);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 529) pv->i2c = client;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 530)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 531) /*
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 532) * First we must start the FCU which will query the
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 533) * shift value to apply to RPMs
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 534) */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 535) if (wf_fcu_init_chip(pv)) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 536) pr_err("wf_fcu: Initialization failed !\n");
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 537) kfree(pv);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 538) return -ENXIO;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 539) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 540)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 541) /* First lookup fans in the device-tree */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 542) wf_fcu_lookup_fans(pv);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 543)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 544) /*
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 545) * Older machines don't have the device-tree entries
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 546) * we are looking for, just hard code the list
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 547) */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 548) if (list_empty(&pv->fan_list))
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 549) wf_fcu_default_fans(pv);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 550)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 551) /* Still no fans ? FAIL */
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 552) if (list_empty(&pv->fan_list)) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 553) pr_err("wf_fcu: Failed to find fans for your machine\n");
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 554) kfree(pv);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 555) return -ENODEV;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 556) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 557)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 558) dev_set_drvdata(&client->dev, pv);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 559)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 560) return 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 561) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 562)
1da42fb6bf6fc (Greg Kroah-Hartman 2012-12-21 15:03:50 -0800 563) static int wf_fcu_remove(struct i2c_client *client)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 564) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 565) struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 566) struct wf_fcu_fan *fan;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 567)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 568) while (!list_empty(&pv->fan_list)) {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 569) fan = list_first_entry(&pv->fan_list, struct wf_fcu_fan, link);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 570) list_del(&fan->link);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 571) wf_unregister_control(&fan->ctrl);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 572) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 573) kref_put(&pv->ref, wf_fcu_release);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 574) return 0;
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 575) }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 576)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 577) static const struct i2c_device_id wf_fcu_id[] = {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 578) { "MAC,fcu", 0 },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 579) { }
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 580) };
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 581) MODULE_DEVICE_TABLE(i2c, wf_fcu_id);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 582)
bcf3588d8ed35 (Wolfram Sang 2020-03-03 13:50:46 +0100 583) static const struct of_device_id wf_fcu_of_id[] = {
bcf3588d8ed35 (Wolfram Sang 2020-03-03 13:50:46 +0100 584) { .compatible = "fcu", },
bcf3588d8ed35 (Wolfram Sang 2020-03-03 13:50:46 +0100 585) { }
bcf3588d8ed35 (Wolfram Sang 2020-03-03 13:50:46 +0100 586) };
bcf3588d8ed35 (Wolfram Sang 2020-03-03 13:50:46 +0100 587) MODULE_DEVICE_TABLE(of, wf_fcu_of_id);
bcf3588d8ed35 (Wolfram Sang 2020-03-03 13:50:46 +0100 588)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 589) static struct i2c_driver wf_fcu_driver = {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 590) .driver = {
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 591) .name = "wf_fcu",
bcf3588d8ed35 (Wolfram Sang 2020-03-03 13:50:46 +0100 592) .of_match_table = wf_fcu_of_id,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 593) },
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 594) .probe = wf_fcu_probe,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 595) .remove = wf_fcu_remove,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 596) .id_table = wf_fcu_id,
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 597) };
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 598)
f7fb862b84326 (Wei Yongjun 2012-10-08 03:00:04 +0000 599) module_i2c_driver(wf_fcu_driver);
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 600)
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 601) MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 602) MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control");
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 603) MODULE_LICENSE("GPL");
a78a4a03a7546 (Benjamin Herrenschmidt 2012-04-18 22:16:55 +0000 604)