1ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/* 2ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Windfarm PowerMac thermal control. MAX6690 sensor. 3ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * 4ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Copyright (C) 2005 Paul Mackerras, IBM Corp. <paulus@samba.org> 5ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * 6ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt * Use and redistribute under the terms of the GNU GPL v2. 7ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt */ 8ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/types.h> 9ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/errno.h> 10ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/kernel.h> 11ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/init.h> 12ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/slab.h> 13ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <linux/i2c.h> 14ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <asm/prom.h> 15ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include <asm/pmac_low_i2c.h> 16ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 17ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#include "windfarm.h" 18ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 19b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt#define VERSION "0.2" 20ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 21ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/* This currently only exports the external temperature sensor, 22ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt since that's all the control loops need. */ 23ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 24ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt/* Some MAX6690 register numbers */ 25ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define MAX6690_INTERNAL_TEMP 0 26ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define MAX6690_EXTERNAL_TEMP 1 27ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 28ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstruct wf_6690_sensor { 29351ca3e31197929535418f5affc761cd9fb07428Jean Delvare struct i2c_client *i2c; 30ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_sensor sens; 31ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt}; 32ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 33ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt#define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens) 34ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 35ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic int wf_max6690_get(struct wf_sensor *sr, s32 *value) 36ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 37ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_6690_sensor *max = wf_to_6690(sr); 38ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt s32 data; 39ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 40351ca3e31197929535418f5affc761cd9fb07428Jean Delvare if (max->i2c == NULL) 41ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return -ENODEV; 42ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 43ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt /* chip gets initialized by firmware */ 44351ca3e31197929535418f5affc761cd9fb07428Jean Delvare data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP); 45ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (data < 0) 46ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return data; 47ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt *value = data << 16; 48ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return 0; 49ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 50ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 51ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic void wf_max6690_release(struct wf_sensor *sr) 52ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 53ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_6690_sensor *max = wf_to_6690(sr); 54ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 55ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt kfree(max); 56ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 57ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 58ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic struct wf_sensor_ops wf_max6690_ops = { 59ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt .get_value = wf_max6690_get, 60ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt .release = wf_max6690_release, 61ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt .owner = THIS_MODULE, 62ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt}; 63ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 64351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic int wf_max6690_probe(struct i2c_client *client, 65351ca3e31197929535418f5affc761cd9fb07428Jean Delvare const struct i2c_device_id *id) 66ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 67ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct wf_6690_sensor *max; 68351ca3e31197929535418f5affc761cd9fb07428Jean Delvare int rc; 69ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 70ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); 71ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (max == NULL) { 72351ca3e31197929535418f5affc761cd9fb07428Jean Delvare printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " 73351ca3e31197929535418f5affc761cd9fb07428Jean Delvare "no memory\n"); 74351ca3e31197929535418f5affc761cd9fb07428Jean Delvare return -ENOMEM; 75351ca3e31197929535418f5affc761cd9fb07428Jean Delvare } 76351ca3e31197929535418f5affc761cd9fb07428Jean Delvare 77351ca3e31197929535418f5affc761cd9fb07428Jean Delvare max->i2c = client; 78351ca3e31197929535418f5affc761cd9fb07428Jean Delvare max->sens.name = client->dev.platform_data; 79351ca3e31197929535418f5affc761cd9fb07428Jean Delvare max->sens.ops = &wf_max6690_ops; 80351ca3e31197929535418f5affc761cd9fb07428Jean Delvare i2c_set_clientdata(client, max); 81351ca3e31197929535418f5affc761cd9fb07428Jean Delvare 82351ca3e31197929535418f5affc761cd9fb07428Jean Delvare rc = wf_register_sensor(&max->sens); 83351ca3e31197929535418f5affc761cd9fb07428Jean Delvare if (rc) { 84351ca3e31197929535418f5affc761cd9fb07428Jean Delvare kfree(max); 85ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 86ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 87351ca3e31197929535418f5affc761cd9fb07428Jean Delvare return rc; 88351ca3e31197929535418f5affc761cd9fb07428Jean Delvare} 89351ca3e31197929535418f5affc761cd9fb07428Jean Delvare 906f6b35e133fe4313277b30fc1a7ea313875ea6c9Jean Delvarestatic struct i2c_driver wf_max6690_driver; 916f6b35e133fe4313277b30fc1a7ea313875ea6c9Jean Delvare 92351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter, 93351ca3e31197929535418f5affc761cd9fb07428Jean Delvare u8 addr, const char *loc) 94351ca3e31197929535418f5affc761cd9fb07428Jean Delvare{ 95351ca3e31197929535418f5affc761cd9fb07428Jean Delvare struct i2c_board_info info; 96351ca3e31197929535418f5affc761cd9fb07428Jean Delvare struct i2c_client *client; 97351ca3e31197929535418f5affc761cd9fb07428Jean Delvare char *name; 98351ca3e31197929535418f5affc761cd9fb07428Jean Delvare 9980ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac if (!strcmp(loc, "BACKSIDE")) 10080ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac name = "backside-temp"; 10180ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac else if (!strcmp(loc, "NB Ambient")) 10280ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac name = "north-bridge-temp"; 10380ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac else if (!strcmp(loc, "GPU Ambient")) 10480ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac name = "gpu-temp"; 10580ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac else 10680ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac goto fail; 10780ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac 108351ca3e31197929535418f5affc761cd9fb07428Jean Delvare memset(&info, 0, sizeof(struct i2c_board_info)); 109351ca3e31197929535418f5affc761cd9fb07428Jean Delvare info.addr = addr >> 1; 110351ca3e31197929535418f5affc761cd9fb07428Jean Delvare info.platform_data = name; 111351ca3e31197929535418f5affc761cd9fb07428Jean Delvare strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE); 112ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 113351ca3e31197929535418f5affc761cd9fb07428Jean Delvare client = i2c_new_device(adapter, &info); 114351ca3e31197929535418f5affc761cd9fb07428Jean Delvare if (client == NULL) { 115ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n"); 116ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt goto fail; 117ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 118ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 119351ca3e31197929535418f5affc761cd9fb07428Jean Delvare /* 120351ca3e31197929535418f5affc761cd9fb07428Jean Delvare * Let i2c-core delete that device on driver removal. 121351ca3e31197929535418f5affc761cd9fb07428Jean Delvare * This is safe because i2c-core holds the core_lock mutex for us. 122351ca3e31197929535418f5affc761cd9fb07428Jean Delvare */ 1236f6b35e133fe4313277b30fc1a7ea313875ea6c9Jean Delvare list_add_tail(&client->detected, &wf_max6690_driver.clients); 124351ca3e31197929535418f5affc761cd9fb07428Jean Delvare return client; 125ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 126ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt fail: 127351ca3e31197929535418f5affc761cd9fb07428Jean Delvare return NULL; 128ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 129ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 130ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic int wf_max6690_attach(struct i2c_adapter *adapter) 131ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 132ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct device_node *busnode, *dev = NULL; 133ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt struct pmac_i2c_bus *bus; 134ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt const char *loc; 135ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 136ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt bus = pmac_i2c_adapter_to_bus(adapter); 137ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt if (bus == NULL) 138ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return -ENODEV; 139ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt busnode = pmac_i2c_get_bus_node(bus); 140ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 141ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt while ((dev = of_get_next_child(busnode, dev)) != NULL) { 142b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt u8 addr; 143b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt 144b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt /* We must re-match the adapter in order to properly check 145b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt * the channel on multibus setups 146b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt */ 147b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt if (!pmac_i2c_match_adapter(dev, adapter)) 148b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt continue; 14955b61fec22caa3e7872caea6c4100fc75cb8f49bStephen Rothwell if (!of_device_is_compatible(dev, "max6690")) 150ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 151b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt addr = pmac_i2c_get_dev_addr(dev); 15201b2726dd11ef198ac6cf8f88974b4427d40ffdbStephen Rothwell loc = of_get_property(dev, "hwsensor-location", NULL); 153b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt if (loc == NULL || addr == 0) 154ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt continue; 155b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt printk("found max6690, loc=%s addr=0x%02x\n", loc, addr); 15680ff974dba8cc432ab81676fc09d3c357cb11276Étienne Bersac wf_max6690_create(adapter, addr, loc); 157ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt } 158ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 159ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return 0; 160ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 161ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 162351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic int wf_max6690_remove(struct i2c_client *client) 163ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 164351ca3e31197929535418f5affc761cd9fb07428Jean Delvare struct wf_6690_sensor *max = i2c_get_clientdata(client); 165ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 166351ca3e31197929535418f5affc761cd9fb07428Jean Delvare max->i2c = NULL; 167ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt wf_unregister_sensor(&max->sens); 168ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 169ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return 0; 170ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 171ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 172351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic const struct i2c_device_id wf_max6690_id[] = { 173351ca3e31197929535418f5affc761cd9fb07428Jean Delvare { "wf_max6690", 0 }, 174351ca3e31197929535418f5affc761cd9fb07428Jean Delvare { } 175351ca3e31197929535418f5affc761cd9fb07428Jean Delvare}; 176351ca3e31197929535418f5affc761cd9fb07428Jean Delvare 177351ca3e31197929535418f5affc761cd9fb07428Jean Delvarestatic struct i2c_driver wf_max6690_driver = { 178351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .driver = { 179351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .name = "wf_max6690", 180351ca3e31197929535418f5affc761cd9fb07428Jean Delvare }, 181351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .attach_adapter = wf_max6690_attach, 182351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .probe = wf_max6690_probe, 183351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .remove = wf_max6690_remove, 184351ca3e31197929535418f5affc761cd9fb07428Jean Delvare .id_table = wf_max6690_id, 185351ca3e31197929535418f5affc761cd9fb07428Jean Delvare}; 186351ca3e31197929535418f5affc761cd9fb07428Jean Delvare 187ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic int __init wf_max6690_sensor_init(void) 188ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 189b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt /* Don't register on old machines that use therm_pm72 for now */ 19071a157e8edca55198e808f8561dd49017a54ee34Grant Likely if (of_machine_is_compatible("PowerMac7,2") || 19171a157e8edca55198e808f8561dd49017a54ee34Grant Likely of_machine_is_compatible("PowerMac7,3") || 19271a157e8edca55198e808f8561dd49017a54ee34Grant Likely of_machine_is_compatible("RackMac3,1")) 193b55fafc5a800f27beedfdcf8bd1b6baa47e769a9Benjamin Herrenschmidt return -ENODEV; 194ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt return i2c_add_driver(&wf_max6690_driver); 195ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 196ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 197ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtstatic void __exit wf_max6690_sensor_exit(void) 198ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt{ 199ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt i2c_del_driver(&wf_max6690_driver); 200ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt} 201ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 202ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtmodule_init(wf_max6690_sensor_init); 203ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidtmodule_exit(wf_max6690_sensor_exit); 204ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin Herrenschmidt 205ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_AUTHOR("Paul Mackerras <paulus@samba.org>"); 206ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control"); 207ac171c46667c1cb2ee9e22312291df6ed78e1b6eBenjamin HerrenschmidtMODULE_LICENSE("GPL"); 208