1a28d3af2SBenjamin Herrenschmidt /* 2a28d3af2SBenjamin Herrenschmidt i2c Support for Apple SMU Controller 3a28d3af2SBenjamin Herrenschmidt 4a28d3af2SBenjamin Herrenschmidt Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp. 5a28d3af2SBenjamin Herrenschmidt <benh@kernel.crashing.org> 6a28d3af2SBenjamin Herrenschmidt 7a28d3af2SBenjamin Herrenschmidt This program is free software; you can redistribute it and/or modify 8a28d3af2SBenjamin Herrenschmidt it under the terms of the GNU General Public License as published by 9a28d3af2SBenjamin Herrenschmidt the Free Software Foundation; either version 2 of the License, or 10a28d3af2SBenjamin Herrenschmidt (at your option) any later version. 11a28d3af2SBenjamin Herrenschmidt 12a28d3af2SBenjamin Herrenschmidt This program is distributed in the hope that it will be useful, 13a28d3af2SBenjamin Herrenschmidt but WITHOUT ANY WARRANTY; without even the implied warranty of 14a28d3af2SBenjamin Herrenschmidt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15a28d3af2SBenjamin Herrenschmidt GNU General Public License for more details. 16a28d3af2SBenjamin Herrenschmidt 17a28d3af2SBenjamin Herrenschmidt You should have received a copy of the GNU General Public License 18a28d3af2SBenjamin Herrenschmidt along with this program; if not, write to the Free Software 19a28d3af2SBenjamin Herrenschmidt Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20a28d3af2SBenjamin Herrenschmidt 21a28d3af2SBenjamin Herrenschmidt */ 22a28d3af2SBenjamin Herrenschmidt 23a28d3af2SBenjamin Herrenschmidt #include <linux/module.h> 24a28d3af2SBenjamin Herrenschmidt #include <linux/kernel.h> 25a28d3af2SBenjamin Herrenschmidt #include <linux/types.h> 26a28d3af2SBenjamin Herrenschmidt #include <linux/i2c.h> 27a28d3af2SBenjamin Herrenschmidt #include <linux/init.h> 28a28d3af2SBenjamin Herrenschmidt #include <linux/completion.h> 29a28d3af2SBenjamin Herrenschmidt #include <linux/device.h> 30a28d3af2SBenjamin Herrenschmidt #include <linux/platform_device.h> 31a28d3af2SBenjamin Herrenschmidt #include <asm/prom.h> 32a28d3af2SBenjamin Herrenschmidt #include <asm/pmac_low_i2c.h> 33a28d3af2SBenjamin Herrenschmidt 34a28d3af2SBenjamin Herrenschmidt MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 35a28d3af2SBenjamin Herrenschmidt MODULE_DESCRIPTION("I2C driver for Apple PowerMac"); 36a28d3af2SBenjamin Herrenschmidt MODULE_LICENSE("GPL"); 37a28d3af2SBenjamin Herrenschmidt 38a28d3af2SBenjamin Herrenschmidt /* 39a28d3af2SBenjamin Herrenschmidt * SMBUS-type transfer entrypoint 40a28d3af2SBenjamin Herrenschmidt */ 41a28d3af2SBenjamin Herrenschmidt static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap, 42a28d3af2SBenjamin Herrenschmidt u16 addr, 43a28d3af2SBenjamin Herrenschmidt unsigned short flags, 44a28d3af2SBenjamin Herrenschmidt char read_write, 45a28d3af2SBenjamin Herrenschmidt u8 command, 46a28d3af2SBenjamin Herrenschmidt int size, 47a28d3af2SBenjamin Herrenschmidt union i2c_smbus_data* data) 48a28d3af2SBenjamin Herrenschmidt { 49a28d3af2SBenjamin Herrenschmidt struct pmac_i2c_bus *bus = i2c_get_adapdata(adap); 50a28d3af2SBenjamin Herrenschmidt int rc = 0; 51a28d3af2SBenjamin Herrenschmidt int read = (read_write == I2C_SMBUS_READ); 52a28d3af2SBenjamin Herrenschmidt int addrdir = (addr << 1) | read; 53a28d3af2SBenjamin Herrenschmidt u8 local[2]; 54a28d3af2SBenjamin Herrenschmidt 55a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_open(bus, 0); 56a28d3af2SBenjamin Herrenschmidt if (rc) 57a28d3af2SBenjamin Herrenschmidt return rc; 58a28d3af2SBenjamin Herrenschmidt 59a28d3af2SBenjamin Herrenschmidt switch (size) { 60a28d3af2SBenjamin Herrenschmidt case I2C_SMBUS_QUICK: 61a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); 62a28d3af2SBenjamin Herrenschmidt if (rc) 63a28d3af2SBenjamin Herrenschmidt goto bail; 64a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0); 65a28d3af2SBenjamin Herrenschmidt break; 66a28d3af2SBenjamin Herrenschmidt case I2C_SMBUS_BYTE: 67a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); 68a28d3af2SBenjamin Herrenschmidt if (rc) 69a28d3af2SBenjamin Herrenschmidt goto bail; 70a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1); 71a28d3af2SBenjamin Herrenschmidt break; 72a28d3af2SBenjamin Herrenschmidt case I2C_SMBUS_BYTE_DATA: 73a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_setmode(bus, read ? 74a28d3af2SBenjamin Herrenschmidt pmac_i2c_mode_combined : 75a28d3af2SBenjamin Herrenschmidt pmac_i2c_mode_stdsub); 76a28d3af2SBenjamin Herrenschmidt if (rc) 77a28d3af2SBenjamin Herrenschmidt goto bail; 78a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1); 79a28d3af2SBenjamin Herrenschmidt break; 80a28d3af2SBenjamin Herrenschmidt case I2C_SMBUS_WORD_DATA: 81a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_setmode(bus, read ? 82a28d3af2SBenjamin Herrenschmidt pmac_i2c_mode_combined : 83a28d3af2SBenjamin Herrenschmidt pmac_i2c_mode_stdsub); 84a28d3af2SBenjamin Herrenschmidt if (rc) 85a28d3af2SBenjamin Herrenschmidt goto bail; 86a28d3af2SBenjamin Herrenschmidt if (!read) { 87a28d3af2SBenjamin Herrenschmidt local[0] = data->word & 0xff; 88a28d3af2SBenjamin Herrenschmidt local[1] = (data->word >> 8) & 0xff; 89a28d3af2SBenjamin Herrenschmidt } 90a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2); 91a28d3af2SBenjamin Herrenschmidt if (rc == 0 && read) { 92a28d3af2SBenjamin Herrenschmidt data->word = ((u16)local[1]) << 8; 93a28d3af2SBenjamin Herrenschmidt data->word |= local[0]; 94a28d3af2SBenjamin Herrenschmidt } 95a28d3af2SBenjamin Herrenschmidt break; 96a28d3af2SBenjamin Herrenschmidt 97a28d3af2SBenjamin Herrenschmidt /* Note that these are broken vs. the expected smbus API where 98a28d3af2SBenjamin Herrenschmidt * on reads, the lenght is actually returned from the function, 99a28d3af2SBenjamin Herrenschmidt * but I think the current API makes no sense and I don't want 100a28d3af2SBenjamin Herrenschmidt * any driver that I haven't verified for correctness to go 101a28d3af2SBenjamin Herrenschmidt * anywhere near a pmac i2c bus anyway ... 102a28d3af2SBenjamin Herrenschmidt * 103a28d3af2SBenjamin Herrenschmidt * I'm also not completely sure what kind of phases to do between 104a28d3af2SBenjamin Herrenschmidt * the actual command and the data (what I am _supposed_ to do that 105a28d3af2SBenjamin Herrenschmidt * is). For now, I assume writes are a single stream and reads have 106a28d3af2SBenjamin Herrenschmidt * a repeat start/addr phase (but not stop in between) 107a28d3af2SBenjamin Herrenschmidt */ 108a28d3af2SBenjamin Herrenschmidt case I2C_SMBUS_BLOCK_DATA: 109a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_setmode(bus, read ? 110a28d3af2SBenjamin Herrenschmidt pmac_i2c_mode_combined : 111a28d3af2SBenjamin Herrenschmidt pmac_i2c_mode_stdsub); 112a28d3af2SBenjamin Herrenschmidt if (rc) 113a28d3af2SBenjamin Herrenschmidt goto bail; 114a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block, 115a28d3af2SBenjamin Herrenschmidt data->block[0] + 1); 116a28d3af2SBenjamin Herrenschmidt 117a28d3af2SBenjamin Herrenschmidt break; 118a28d3af2SBenjamin Herrenschmidt case I2C_SMBUS_I2C_BLOCK_DATA: 119a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_setmode(bus, read ? 120a28d3af2SBenjamin Herrenschmidt pmac_i2c_mode_combined : 121a28d3af2SBenjamin Herrenschmidt pmac_i2c_mode_stdsub); 122a28d3af2SBenjamin Herrenschmidt if (rc) 123a28d3af2SBenjamin Herrenschmidt goto bail; 124a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_xfer(bus, addrdir, 1, command, 125a28d3af2SBenjamin Herrenschmidt read ? data->block : &data->block[1], 126a28d3af2SBenjamin Herrenschmidt data->block[0]); 127a28d3af2SBenjamin Herrenschmidt break; 128a28d3af2SBenjamin Herrenschmidt 129a28d3af2SBenjamin Herrenschmidt default: 130a28d3af2SBenjamin Herrenschmidt rc = -EINVAL; 131a28d3af2SBenjamin Herrenschmidt } 132a28d3af2SBenjamin Herrenschmidt bail: 133a28d3af2SBenjamin Herrenschmidt pmac_i2c_close(bus); 134a28d3af2SBenjamin Herrenschmidt return rc; 135a28d3af2SBenjamin Herrenschmidt } 136a28d3af2SBenjamin Herrenschmidt 137a28d3af2SBenjamin Herrenschmidt /* 138a28d3af2SBenjamin Herrenschmidt * Generic i2c master transfer entrypoint. This driver only support single 139a28d3af2SBenjamin Herrenschmidt * messages (for "lame i2c" transfers). Anything else should use the smbus 140a28d3af2SBenjamin Herrenschmidt * entry point 141a28d3af2SBenjamin Herrenschmidt */ 142a28d3af2SBenjamin Herrenschmidt static int i2c_powermac_master_xfer( struct i2c_adapter *adap, 143a28d3af2SBenjamin Herrenschmidt struct i2c_msg *msgs, 144a28d3af2SBenjamin Herrenschmidt int num) 145a28d3af2SBenjamin Herrenschmidt { 146a28d3af2SBenjamin Herrenschmidt struct pmac_i2c_bus *bus = i2c_get_adapdata(adap); 147a28d3af2SBenjamin Herrenschmidt int rc = 0; 148a28d3af2SBenjamin Herrenschmidt int read; 149a28d3af2SBenjamin Herrenschmidt int addrdir; 150a28d3af2SBenjamin Herrenschmidt 151a28d3af2SBenjamin Herrenschmidt if (msgs->flags & I2C_M_TEN) 152a28d3af2SBenjamin Herrenschmidt return -EINVAL; 153a28d3af2SBenjamin Herrenschmidt read = (msgs->flags & I2C_M_RD) != 0; 154a28d3af2SBenjamin Herrenschmidt addrdir = (msgs->addr << 1) | read; 155a28d3af2SBenjamin Herrenschmidt if (msgs->flags & I2C_M_REV_DIR_ADDR) 156a28d3af2SBenjamin Herrenschmidt addrdir ^= 1; 157a28d3af2SBenjamin Herrenschmidt 158a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_open(bus, 0); 159a28d3af2SBenjamin Herrenschmidt if (rc) 160a28d3af2SBenjamin Herrenschmidt return rc; 161a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); 162a28d3af2SBenjamin Herrenschmidt if (rc) 163a28d3af2SBenjamin Herrenschmidt goto bail; 164a28d3af2SBenjamin Herrenschmidt rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len); 165a28d3af2SBenjamin Herrenschmidt bail: 166a28d3af2SBenjamin Herrenschmidt pmac_i2c_close(bus); 1678ced8eeeSJean Delvare return rc < 0 ? rc : 1; 168a28d3af2SBenjamin Herrenschmidt } 169a28d3af2SBenjamin Herrenschmidt 170a28d3af2SBenjamin Herrenschmidt static u32 i2c_powermac_func(struct i2c_adapter * adapter) 171a28d3af2SBenjamin Herrenschmidt { 172a28d3af2SBenjamin Herrenschmidt return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | 173a28d3af2SBenjamin Herrenschmidt I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | 174a28d3af2SBenjamin Herrenschmidt I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C; 175a28d3af2SBenjamin Herrenschmidt } 176a28d3af2SBenjamin Herrenschmidt 177a28d3af2SBenjamin Herrenschmidt /* For now, we only handle smbus */ 178*8f9082c5SJean Delvare static const struct i2c_algorithm i2c_powermac_algorithm = { 179a28d3af2SBenjamin Herrenschmidt .smbus_xfer = i2c_powermac_smbus_xfer, 180a28d3af2SBenjamin Herrenschmidt .master_xfer = i2c_powermac_master_xfer, 181a28d3af2SBenjamin Herrenschmidt .functionality = i2c_powermac_func, 182a28d3af2SBenjamin Herrenschmidt }; 183a28d3af2SBenjamin Herrenschmidt 184a28d3af2SBenjamin Herrenschmidt 185a28d3af2SBenjamin Herrenschmidt static int i2c_powermac_remove(struct device *dev) 186a28d3af2SBenjamin Herrenschmidt { 187a28d3af2SBenjamin Herrenschmidt struct i2c_adapter *adapter = dev_get_drvdata(dev); 188a28d3af2SBenjamin Herrenschmidt struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter); 189a28d3af2SBenjamin Herrenschmidt int rc; 190a28d3af2SBenjamin Herrenschmidt 191a28d3af2SBenjamin Herrenschmidt rc = i2c_del_adapter(adapter); 192a28d3af2SBenjamin Herrenschmidt pmac_i2c_detach_adapter(bus, adapter); 193a28d3af2SBenjamin Herrenschmidt i2c_set_adapdata(adapter, NULL); 194a28d3af2SBenjamin Herrenschmidt /* We aren't that prepared to deal with this... */ 195a28d3af2SBenjamin Herrenschmidt if (rc) 196a28d3af2SBenjamin Herrenschmidt printk("i2c-powermac.c: Failed to remove bus %s !\n", 197a28d3af2SBenjamin Herrenschmidt adapter->name); 198a28d3af2SBenjamin Herrenschmidt dev_set_drvdata(dev, NULL); 199a28d3af2SBenjamin Herrenschmidt kfree(adapter); 200a28d3af2SBenjamin Herrenschmidt 201a28d3af2SBenjamin Herrenschmidt return 0; 202a28d3af2SBenjamin Herrenschmidt } 203a28d3af2SBenjamin Herrenschmidt 204a28d3af2SBenjamin Herrenschmidt 205a28d3af2SBenjamin Herrenschmidt static int i2c_powermac_probe(struct device *dev) 206a28d3af2SBenjamin Herrenschmidt { 207a28d3af2SBenjamin Herrenschmidt struct pmac_i2c_bus *bus = dev->platform_data; 208a28d3af2SBenjamin Herrenschmidt struct device_node *parent = NULL; 209a28d3af2SBenjamin Herrenschmidt struct i2c_adapter *adapter; 210018a3d1dSJeremy Kerr char name[32]; 211018a3d1dSJeremy Kerr const char *basename; 212a28d3af2SBenjamin Herrenschmidt int rc; 213a28d3af2SBenjamin Herrenschmidt 214a28d3af2SBenjamin Herrenschmidt if (bus == NULL) 215a28d3af2SBenjamin Herrenschmidt return -EINVAL; 216a28d3af2SBenjamin Herrenschmidt 217a28d3af2SBenjamin Herrenschmidt /* Ok, now we need to make up a name for the interface that will 218a28d3af2SBenjamin Herrenschmidt * match what we used to do in the past, that is basically the 219a28d3af2SBenjamin Herrenschmidt * controller's parent device node for keywest. PMU didn't have a 220a28d3af2SBenjamin Herrenschmidt * naming convention and SMU has a different one 221a28d3af2SBenjamin Herrenschmidt */ 222a28d3af2SBenjamin Herrenschmidt switch(pmac_i2c_get_type(bus)) { 223a28d3af2SBenjamin Herrenschmidt case pmac_i2c_bus_keywest: 224a28d3af2SBenjamin Herrenschmidt parent = of_get_parent(pmac_i2c_get_controller(bus)); 225a28d3af2SBenjamin Herrenschmidt if (parent == NULL) 226a28d3af2SBenjamin Herrenschmidt return -EINVAL; 227a28d3af2SBenjamin Herrenschmidt basename = parent->name; 228a28d3af2SBenjamin Herrenschmidt break; 229a28d3af2SBenjamin Herrenschmidt case pmac_i2c_bus_pmu: 230a28d3af2SBenjamin Herrenschmidt basename = "pmu"; 231a28d3af2SBenjamin Herrenschmidt break; 232a28d3af2SBenjamin Herrenschmidt case pmac_i2c_bus_smu: 233a28d3af2SBenjamin Herrenschmidt /* This is not what we used to do but I'm fixing drivers at 234a28d3af2SBenjamin Herrenschmidt * the same time as this change 235a28d3af2SBenjamin Herrenschmidt */ 236a28d3af2SBenjamin Herrenschmidt basename = "smu"; 237a28d3af2SBenjamin Herrenschmidt break; 238a28d3af2SBenjamin Herrenschmidt default: 239a28d3af2SBenjamin Herrenschmidt return -EINVAL; 240a28d3af2SBenjamin Herrenschmidt } 241a28d3af2SBenjamin Herrenschmidt snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus)); 242a28d3af2SBenjamin Herrenschmidt of_node_put(parent); 243a28d3af2SBenjamin Herrenschmidt 244a28d3af2SBenjamin Herrenschmidt adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); 245a28d3af2SBenjamin Herrenschmidt if (adapter == NULL) { 246a28d3af2SBenjamin Herrenschmidt printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n"); 247a28d3af2SBenjamin Herrenschmidt return -ENOMEM; 248a28d3af2SBenjamin Herrenschmidt } 249a28d3af2SBenjamin Herrenschmidt dev_set_drvdata(dev, adapter); 250a28d3af2SBenjamin Herrenschmidt strcpy(adapter->name, name); 251a28d3af2SBenjamin Herrenschmidt adapter->algo = &i2c_powermac_algorithm; 252a28d3af2SBenjamin Herrenschmidt i2c_set_adapdata(adapter, bus); 253a28d3af2SBenjamin Herrenschmidt adapter->dev.parent = dev; 254a28d3af2SBenjamin Herrenschmidt pmac_i2c_attach_adapter(bus, adapter); 255a28d3af2SBenjamin Herrenschmidt rc = i2c_add_adapter(adapter); 256a28d3af2SBenjamin Herrenschmidt if (rc) { 257a28d3af2SBenjamin Herrenschmidt printk(KERN_ERR "i2c-powermac: Adapter %s registration " 258a28d3af2SBenjamin Herrenschmidt "failed\n", name); 259a28d3af2SBenjamin Herrenschmidt i2c_set_adapdata(adapter, NULL); 260a28d3af2SBenjamin Herrenschmidt pmac_i2c_detach_adapter(bus, adapter); 261a28d3af2SBenjamin Herrenschmidt } 262a28d3af2SBenjamin Herrenschmidt 263a28d3af2SBenjamin Herrenschmidt printk(KERN_INFO "PowerMac i2c bus %s registered\n", name); 264a28d3af2SBenjamin Herrenschmidt return rc; 265a28d3af2SBenjamin Herrenschmidt } 266a28d3af2SBenjamin Herrenschmidt 267a28d3af2SBenjamin Herrenschmidt 268a28d3af2SBenjamin Herrenschmidt static struct device_driver i2c_powermac_driver = { 269a28d3af2SBenjamin Herrenschmidt .name = "i2c-powermac", 270a28d3af2SBenjamin Herrenschmidt .bus = &platform_bus_type, 271a28d3af2SBenjamin Herrenschmidt .probe = i2c_powermac_probe, 272a28d3af2SBenjamin Herrenschmidt .remove = i2c_powermac_remove, 273a28d3af2SBenjamin Herrenschmidt }; 274a28d3af2SBenjamin Herrenschmidt 275a28d3af2SBenjamin Herrenschmidt static int __init i2c_powermac_init(void) 276a28d3af2SBenjamin Herrenschmidt { 277a28d3af2SBenjamin Herrenschmidt driver_register(&i2c_powermac_driver); 278a28d3af2SBenjamin Herrenschmidt return 0; 279a28d3af2SBenjamin Herrenschmidt } 280a28d3af2SBenjamin Herrenschmidt 281a28d3af2SBenjamin Herrenschmidt 282a28d3af2SBenjamin Herrenschmidt static void __exit i2c_powermac_cleanup(void) 283a28d3af2SBenjamin Herrenschmidt { 284a28d3af2SBenjamin Herrenschmidt driver_unregister(&i2c_powermac_driver); 285a28d3af2SBenjamin Herrenschmidt } 286a28d3af2SBenjamin Herrenschmidt 287a28d3af2SBenjamin Herrenschmidt module_init(i2c_powermac_init); 288a28d3af2SBenjamin Herrenschmidt module_exit(i2c_powermac_cleanup); 289