141 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 025#define MAX6690_EXTERNAL_TEMP 126 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{65 const char *name, *loc;66 struct wf_6690_sensor *max;67 int rc;68 69 loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);70 if (!loc) {71 dev_warn(&client->dev, "Missing hwsensor-location property!\n");72 return -ENXIO;73 }74 75 /*76 * We only expose the external temperature register for77 * now as this is all we need for our control loops78 */79 if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT"))80 name = "backside-temp";81 else if (!strcmp(loc, "NB Ambient"))82 name = "north-bridge-temp";83 else if (!strcmp(loc, "GPU Ambient"))84 name = "gpu-temp";85 else86 return -ENXIO;87 88 max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);89 if (max == NULL) {90 printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "91 "no memory\n");92 return -ENOMEM;93 }94 95 max->i2c = client;96 max->sens.name = name;97 max->sens.ops = &wf_max6690_ops;98 i2c_set_clientdata(client, max);99 100 rc = wf_register_sensor(&max->sens);101 if (rc)102 kfree(max);103 return rc;104}105 106static void wf_max6690_remove(struct i2c_client *client)107{108 struct wf_6690_sensor *max = i2c_get_clientdata(client);109 110 max->i2c = NULL;111 wf_unregister_sensor(&max->sens);112}113 114static const struct i2c_device_id wf_max6690_id[] = {115 { "MAC,max6690" },116 { }117};118MODULE_DEVICE_TABLE(i2c, wf_max6690_id);119 120static const struct of_device_id wf_max6690_of_id[] = {121 { .compatible = "max6690", },122 { }123};124MODULE_DEVICE_TABLE(of, wf_max6690_of_id);125 126static struct i2c_driver wf_max6690_driver = {127 .driver = {128 .name = "wf_max6690",129 .of_match_table = wf_max6690_of_id,130 },131 .probe = wf_max6690_probe,132 .remove = wf_max6690_remove,133 .id_table = wf_max6690_id,134};135 136module_i2c_driver(wf_max6690_driver);137 138MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");139MODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control");140MODULE_LICENSE("GPL");141