450 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 i2c Support for Apple SMU Controller4 5 Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.6 <benh@kernel.crashing.org>7 8 9*/10 11#include <linux/module.h>12#include <linux/kernel.h>13#include <linux/types.h>14#include <linux/i2c.h>15#include <linux/device.h>16#include <linux/platform_device.h>17#include <linux/of_irq.h>18 19#include <asm/pmac_low_i2c.h>20 21MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");22MODULE_DESCRIPTION("I2C driver for Apple PowerMac");23MODULE_LICENSE("GPL");24 25/*26 * SMBUS-type transfer entrypoint27 */28static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,29 u16 addr,30 unsigned short flags,31 char read_write,32 u8 command,33 int size,34 union i2c_smbus_data* data)35{36 struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);37 int rc = 0;38 int read = (read_write == I2C_SMBUS_READ);39 int addrdir = (addr << 1) | read;40 int mode, subsize, len;41 u32 subaddr;42 u8 *buf;43 u8 local[2];44 45 if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {46 mode = pmac_i2c_mode_std;47 subsize = 0;48 subaddr = 0;49 } else {50 mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;51 subsize = 1;52 subaddr = command;53 }54 55 switch (size) {56 case I2C_SMBUS_QUICK:57 buf = NULL;58 len = 0;59 break;60 case I2C_SMBUS_BYTE:61 case I2C_SMBUS_BYTE_DATA:62 buf = &data->byte;63 len = 1;64 break;65 case I2C_SMBUS_WORD_DATA:66 if (!read) {67 local[0] = data->word & 0xff;68 local[1] = (data->word >> 8) & 0xff;69 }70 buf = local;71 len = 2;72 break;73 74 /* Note that these are broken vs. the expected smbus API where75 * on reads, the length is actually returned from the function,76 * but I think the current API makes no sense and I don't want77 * any driver that I haven't verified for correctness to go78 * anywhere near a pmac i2c bus anyway ...79 */80 case I2C_SMBUS_BLOCK_DATA:81 buf = data->block;82 len = data->block[0] + 1;83 break;84 case I2C_SMBUS_I2C_BLOCK_DATA:85 buf = &data->block[1];86 len = data->block[0];87 break;88 89 default:90 return -EINVAL;91 }92 93 rc = pmac_i2c_open(bus, 0);94 if (rc) {95 dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);96 return rc;97 }98 99 rc = pmac_i2c_setmode(bus, mode);100 if (rc) {101 dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",102 mode, rc);103 goto bail;104 }105 106 rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);107 if (rc) {108 if (rc == -ENXIO)109 dev_dbg(&adap->dev,110 "I2C transfer at 0x%02x failed, size %d, "111 "err %d\n", addrdir >> 1, size, rc);112 else113 dev_err(&adap->dev,114 "I2C transfer at 0x%02x failed, size %d, "115 "err %d\n", addrdir >> 1, size, rc);116 goto bail;117 }118 119 if (size == I2C_SMBUS_WORD_DATA && read) {120 data->word = ((u16)local[1]) << 8;121 data->word |= local[0];122 }123 124 bail:125 pmac_i2c_close(bus);126 return rc;127}128 129/*130 * Generic i2c transfer entrypoint. This driver only supports single131 * messages (for "lame i2c" transfers). Anything else should use the smbus132 * entry point133 */134static int i2c_powermac_xfer(struct i2c_adapter *adap,135 struct i2c_msg *msgs,136 int num)137{138 struct pmac_i2c_bus *bus = i2c_get_adapdata(adap);139 int rc = 0;140 int addrdir;141 142 if (msgs->flags & I2C_M_TEN)143 return -EINVAL;144 addrdir = i2c_8bit_addr_from_msg(msgs);145 146 rc = pmac_i2c_open(bus, 0);147 if (rc) {148 dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);149 return rc;150 }151 rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);152 if (rc) {153 dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",154 pmac_i2c_mode_std, rc);155 goto bail;156 }157 rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);158 if (rc < 0) {159 if (rc == -ENXIO)160 dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n",161 addrdir & 1 ? "read from" : "write to",162 addrdir >> 1, rc);163 else164 dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",165 addrdir & 1 ? "read from" : "write to",166 addrdir >> 1, rc);167 }168 bail:169 pmac_i2c_close(bus);170 return rc < 0 ? rc : 1;171}172 173static u32 i2c_powermac_func(struct i2c_adapter * adapter)174{175 return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |176 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |177 I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;178}179 180/* For now, we only handle smbus */181static const struct i2c_algorithm i2c_powermac_algorithm = {182 .smbus_xfer = i2c_powermac_smbus_xfer,183 .xfer = i2c_powermac_xfer,184 .functionality = i2c_powermac_func,185};186 187static const struct i2c_adapter_quirks i2c_powermac_quirks = {188 .max_num_msgs = 1,189};190 191static void i2c_powermac_remove(struct platform_device *dev)192{193 struct i2c_adapter *adapter = platform_get_drvdata(dev);194 195 i2c_del_adapter(adapter);196 memset(adapter, 0, sizeof(*adapter));197}198 199static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,200 struct pmac_i2c_bus *bus,201 struct device_node *node)202{203 u32 prop;204 int ret;205 206 /* First check for valid "reg" */207 ret = of_property_read_u32(node, "reg", &prop);208 if (ret == 0)209 return (prop & 0xff) >> 1;210 211 /* Then check old-style "i2c-address" */212 ret = of_property_read_u32(node, "i2c-address", &prop);213 if (ret == 0)214 return (prop & 0xff) >> 1;215 216 /* Now handle some devices with missing "reg" properties */217 if (of_node_name_eq(node, "cereal"))218 return 0x60;219 else if (of_node_name_eq(node, "deq"))220 return 0x34;221 222 dev_warn(&adap->dev, "No i2c address for %pOF\n", node);223 224 return 0xffffffff;225}226 227static void i2c_powermac_create_one(struct i2c_adapter *adap,228 const char *type,229 u32 addr)230{231 struct i2c_board_info info = {};232 struct i2c_client *newdev;233 234 strscpy(info.type, type, sizeof(info.type));235 info.addr = addr;236 newdev = i2c_new_client_device(adap, &info);237 if (IS_ERR(newdev))238 dev_err(&adap->dev,239 "i2c-powermac: Failure to register missing %s\n",240 type);241}242 243static void i2c_powermac_add_missing(struct i2c_adapter *adap,244 struct pmac_i2c_bus *bus,245 bool found_onyx)246{247 struct device_node *busnode = pmac_i2c_get_bus_node(bus);248 int rc;249 250 /* Check for the onyx audio codec */251#define ONYX_REG_CONTROL 67252 if (of_device_is_compatible(busnode, "k2-i2c") && !found_onyx) {253 union i2c_smbus_data data;254 255 rc = i2c_smbus_xfer(adap, 0x46, 0, I2C_SMBUS_READ,256 ONYX_REG_CONTROL, I2C_SMBUS_BYTE_DATA,257 &data);258 if (rc >= 0)259 i2c_powermac_create_one(adap, "MAC,pcm3052", 0x46);260 261 rc = i2c_smbus_xfer(adap, 0x47, 0, I2C_SMBUS_READ,262 ONYX_REG_CONTROL, I2C_SMBUS_BYTE_DATA,263 &data);264 if (rc >= 0)265 i2c_powermac_create_one(adap, "MAC,pcm3052", 0x47);266 }267}268 269static bool i2c_powermac_get_type(struct i2c_adapter *adap,270 struct device_node *node,271 u32 addr, char *type, int type_size)272{273 char tmp[16];274 275 /*276 * Note: we do _NOT_ want the standard i2c drivers to match with any of277 * our powermac stuff unless they have been specifically modified to278 * handle it on a case by case basis. For example, for thermal control,279 * things like lm75 etc... shall match with their corresponding280 * windfarm drivers, _NOT_ the generic ones, so we force a prefix of281 * 'MAC', onto the modalias to make that happen282 */283 284 /* First try proper modalias */285 if (of_alias_from_compatible(node, tmp, sizeof(tmp)) >= 0) {286 snprintf(type, type_size, "MAC,%s", tmp);287 return true;288 }289 290 /* Now look for known workarounds */291 if (of_node_name_eq(node, "deq")) {292 /* Apple uses address 0x34 for TAS3001 and 0x35 for TAS3004 */293 if (addr == 0x34) {294 snprintf(type, type_size, "MAC,tas3001");295 return true;296 } else if (addr == 0x35) {297 snprintf(type, type_size, "MAC,tas3004");298 return true;299 }300 }301 302 dev_err(&adap->dev, "i2c-powermac: modalias failure on %pOF\n", node);303 return false;304}305 306static void i2c_powermac_register_devices(struct i2c_adapter *adap,307 struct pmac_i2c_bus *bus)308{309 struct i2c_client *newdev;310 struct device_node *node;311 bool found_onyx = false;312 313 /*314 * In some cases we end up with the via-pmu node itself, in this315 * case we skip this function completely as the device-tree will316 * not contain anything useful.317 */318 if (of_node_name_eq(adap->dev.of_node, "via-pmu"))319 return;320 321 for_each_child_of_node(adap->dev.of_node, node) {322 struct i2c_board_info info = {};323 u32 addr;324 325 /* Get address & channel */326 addr = i2c_powermac_get_addr(adap, bus, node);327 if (addr == 0xffffffff)328 continue;329 330 /* Multibus setup, check channel */331 if (!pmac_i2c_match_adapter(node, adap))332 continue;333 334 dev_dbg(&adap->dev, "i2c-powermac: register %pOF\n", node);335 336 /*337 * Keep track of some device existence to handle338 * workarounds later.339 */340 if (of_device_is_compatible(node, "pcm3052"))341 found_onyx = true;342 343 /* Make up a modalias */344 if (!i2c_powermac_get_type(adap, node, addr,345 info.type, sizeof(info.type))) {346 continue;347 }348 349 /* Fill out the rest of the info structure */350 info.addr = addr;351 info.irq = irq_of_parse_and_map(node, 0);352 info.of_node = of_node_get(node);353 354 newdev = i2c_new_client_device(adap, &info);355 if (IS_ERR(newdev)) {356 dev_err(&adap->dev, "i2c-powermac: Failure to register"357 " %pOF\n", node);358 of_node_put(node);359 /* We do not dispose of the interrupt mapping on360 * purpose. It's not necessary (interrupt cannot be361 * re-used) and somebody else might have grabbed it362 * via direct DT lookup so let's not bother363 */364 continue;365 }366 }367 368 /* Additional workarounds */369 i2c_powermac_add_missing(adap, bus, found_onyx);370}371 372static int i2c_powermac_probe(struct platform_device *dev)373{374 struct pmac_i2c_bus *bus = dev_get_platdata(&dev->dev);375 struct device_node *parent;376 struct i2c_adapter *adapter;377 int rc;378 379 if (bus == NULL)380 return -EINVAL;381 adapter = pmac_i2c_get_adapter(bus);382 383 /* Ok, now we need to make up a name for the interface that will384 * match what we used to do in the past, that is basically the385 * controller's parent device node for keywest. PMU didn't have a386 * naming convention and SMU has a different one387 */388 switch(pmac_i2c_get_type(bus)) {389 case pmac_i2c_bus_keywest:390 parent = of_get_parent(pmac_i2c_get_controller(bus));391 if (parent == NULL)392 return -EINVAL;393 snprintf(adapter->name, sizeof(adapter->name), "%pOFn %d",394 parent,395 pmac_i2c_get_channel(bus));396 of_node_put(parent);397 break;398 case pmac_i2c_bus_pmu:399 snprintf(adapter->name, sizeof(adapter->name), "pmu %d",400 pmac_i2c_get_channel(bus));401 break;402 case pmac_i2c_bus_smu:403 /* This is not what we used to do but I'm fixing drivers at404 * the same time as this change405 */406 snprintf(adapter->name, sizeof(adapter->name), "smu %d",407 pmac_i2c_get_channel(bus));408 break;409 default:410 return -EINVAL;411 }412 413 platform_set_drvdata(dev, adapter);414 adapter->algo = &i2c_powermac_algorithm;415 adapter->quirks = &i2c_powermac_quirks;416 i2c_set_adapdata(adapter, bus);417 adapter->dev.parent = &dev->dev;418 419 /* Clear of_node to skip automatic registration of i2c child nodes */420 adapter->dev.of_node = NULL;421 rc = i2c_add_adapter(adapter);422 if (rc) {423 printk(KERN_ERR "i2c-powermac: Adapter %s registration "424 "failed\n", adapter->name);425 memset(adapter, 0, sizeof(*adapter));426 return rc;427 }428 429 printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);430 431 /* Use custom child registration due to Apple device-tree funkyness */432 adapter->dev.of_node = dev->dev.of_node;433 i2c_powermac_register_devices(adapter, bus);434 435 return 0;436}437 438static struct platform_driver i2c_powermac_driver = {439 .probe = i2c_powermac_probe,440 .remove_new = i2c_powermac_remove,441 .driver = {442 .name = "i2c-powermac",443 .bus = &platform_bus_type,444 },445};446 447module_platform_driver(i2c_powermac_driver);448 449MODULE_ALIAS("platform:i2c-powermac");450