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