windfarm_max6690_sensor.c (3290B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Windfarm PowerMac thermal control. MAX6690 sensor. 4 * 5 * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org> 6 */ 7#include <linux/types.h> 8#include <linux/errno.h> 9#include <linux/kernel.h> 10#include <linux/init.h> 11#include <linux/slab.h> 12#include <linux/i2c.h> 13 14#include <asm/pmac_low_i2c.h> 15 16#include "windfarm.h" 17 18#define VERSION "1.0" 19 20/* This currently only exports the external temperature sensor, 21 since that's all the control loops need. */ 22 23/* Some MAX6690 register numbers */ 24#define MAX6690_INTERNAL_TEMP 0 25#define MAX6690_EXTERNAL_TEMP 1 26 27struct wf_6690_sensor { 28 struct i2c_client *i2c; 29 struct wf_sensor sens; 30}; 31 32#define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens) 33 34static int wf_max6690_get(struct wf_sensor *sr, s32 *value) 35{ 36 struct wf_6690_sensor *max = wf_to_6690(sr); 37 s32 data; 38 39 if (max->i2c == NULL) 40 return -ENODEV; 41 42 /* chip gets initialized by firmware */ 43 data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP); 44 if (data < 0) 45 return data; 46 *value = data << 16; 47 return 0; 48} 49 50static void wf_max6690_release(struct wf_sensor *sr) 51{ 52 struct wf_6690_sensor *max = wf_to_6690(sr); 53 54 kfree(max); 55} 56 57static const struct wf_sensor_ops wf_max6690_ops = { 58 .get_value = wf_max6690_get, 59 .release = wf_max6690_release, 60 .owner = THIS_MODULE, 61}; 62 63static int wf_max6690_probe(struct i2c_client *client, 64 const struct i2c_device_id *id) 65{ 66 const char *name, *loc; 67 struct wf_6690_sensor *max; 68 int rc; 69 70 loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL); 71 if (!loc) { 72 dev_warn(&client->dev, "Missing hwsensor-location property!\n"); 73 return -ENXIO; 74 } 75 76 /* 77 * We only expose the external temperature register for 78 * now as this is all we need for our control loops 79 */ 80 if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT")) 81 name = "backside-temp"; 82 else if (!strcmp(loc, "NB Ambient")) 83 name = "north-bridge-temp"; 84 else if (!strcmp(loc, "GPU Ambient")) 85 name = "gpu-temp"; 86 else 87 return -ENXIO; 88 89 max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); 90 if (max == NULL) { 91 printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " 92 "no memory\n"); 93 return -ENOMEM; 94 } 95 96 max->i2c = client; 97 max->sens.name = name; 98 max->sens.ops = &wf_max6690_ops; 99 i2c_set_clientdata(client, max); 100 101 rc = wf_register_sensor(&max->sens); 102 if (rc) 103 kfree(max); 104 return rc; 105} 106 107static int wf_max6690_remove(struct i2c_client *client) 108{ 109 struct wf_6690_sensor *max = i2c_get_clientdata(client); 110 111 max->i2c = NULL; 112 wf_unregister_sensor(&max->sens); 113 114 return 0; 115} 116 117static const struct i2c_device_id wf_max6690_id[] = { 118 { "MAC,max6690", 0 }, 119 { } 120}; 121MODULE_DEVICE_TABLE(i2c, wf_max6690_id); 122 123static const struct of_device_id wf_max6690_of_id[] = { 124 { .compatible = "max6690", }, 125 { } 126}; 127MODULE_DEVICE_TABLE(of, wf_max6690_of_id); 128 129static struct i2c_driver wf_max6690_driver = { 130 .driver = { 131 .name = "wf_max6690", 132 .of_match_table = wf_max6690_of_id, 133 }, 134 .probe = wf_max6690_probe, 135 .remove = wf_max6690_remove, 136 .id_table = wf_max6690_id, 137}; 138 139module_i2c_driver(wf_max6690_driver); 140 141MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); 142MODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control"); 143MODULE_LICENSE("GPL");