Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 1 | /* |
| 2 | * I2C bridge driver for the Greybus "generic" I2C module. |
| 3 | * |
| 4 | * Copyright 2014 Google Inc. |
| 5 | * |
| 6 | * Released under the GPLv2 only. |
| 7 | */ |
| 8 | |
| 9 | #include <linux/kernel.h> |
| 10 | #include <linux/module.h> |
| 11 | #include <linux/slab.h> |
| 12 | #include <linux/i2c.h> |
| 13 | #include "greybus.h" |
| 14 | |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 15 | struct gb_i2c_device { |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 16 | struct i2c_adapter *adapter; |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 17 | struct greybus_module *gmod; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 18 | }; |
| 19 | |
Greg Kroah-Hartman | 6584c8a | 2014-09-01 13:31:31 -0700 | [diff] [blame] | 20 | static const struct greybus_module_id id_table[] = { |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 21 | { GREYBUS_DEVICE(0x42, 0x42) }, /* make shit up */ |
| 22 | { }, /* terminating NULL entry */ |
| 23 | }; |
| 24 | |
| 25 | /* We BETTER be able to do SMBUS protocl calls, otherwise we are bit-banging the |
| 26 | * slowest thing possible over the fastest bus possible, crazy... |
| 27 | * FIXME - research this, for now just assume we can |
| 28 | */ |
| 29 | |
| 30 | |
| 31 | static s32 i2c_gb_access(struct i2c_adapter *adap, u16 addr, |
| 32 | unsigned short flags, char read_write, u8 command, |
| 33 | int size, union i2c_smbus_data *data) |
| 34 | { |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 35 | struct gb_i2c_device *gb_i2c_dev; |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 36 | struct greybus_module *gmod; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 37 | |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 38 | gb_i2c_dev = i2c_get_adapdata(adap); |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 39 | gmod = gb_i2c_dev->gmod; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 40 | |
| 41 | // FIXME - do the actual work of sending a i2c message here... |
| 42 | switch (size) { |
| 43 | case I2C_SMBUS_QUICK: |
| 44 | case I2C_SMBUS_BYTE: |
| 45 | case I2C_SMBUS_BYTE_DATA: |
| 46 | case I2C_SMBUS_WORD_DATA: |
| 47 | case I2C_SMBUS_PROC_CALL: |
| 48 | case I2C_SMBUS_BLOCK_DATA: |
| 49 | case I2C_SMBUS_I2C_BLOCK_BROKEN: |
| 50 | case I2C_SMBUS_BLOCK_PROC_CALL: |
| 51 | case I2C_SMBUS_I2C_BLOCK_DATA: |
| 52 | default: |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 53 | dev_err(&gmod->dev, "Unsupported transaction %d\n", size); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 54 | return -EOPNOTSUPP; |
| 55 | } |
| 56 | |
| 57 | return 0; |
| 58 | } |
| 59 | |
| 60 | static u32 i2c_gb_func(struct i2c_adapter *adapter) |
| 61 | { |
| 62 | // FIXME - someone figure out what we really can support, for now just guess... |
| 63 | return I2C_FUNC_SMBUS_QUICK | |
| 64 | I2C_FUNC_SMBUS_BYTE | |
| 65 | I2C_FUNC_SMBUS_BYTE_DATA | |
| 66 | I2C_FUNC_SMBUS_WORD_DATA | |
| 67 | I2C_FUNC_SMBUS_BLOCK_DATA | |
| 68 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | |
| 69 | I2C_FUNC_SMBUS_PEC | |
| 70 | I2C_FUNC_SMBUS_READ_I2C_BLOCK; |
| 71 | } |
| 72 | |
| 73 | static const struct i2c_algorithm smbus_algorithm = { |
| 74 | .smbus_xfer = i2c_gb_access, |
| 75 | .functionality = i2c_gb_func, |
| 76 | }; |
| 77 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 78 | int gb_i2c_probe(struct greybus_module *gmod, |
Greg Kroah-Hartman | 6584c8a | 2014-09-01 13:31:31 -0700 | [diff] [blame] | 79 | const struct greybus_module_id *id) |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 80 | { |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 81 | struct gb_i2c_device *gb_i2c_dev; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 82 | struct i2c_adapter *adapter; |
Greg Kroah-Hartman | 53419e0 | 2014-08-11 17:01:15 +0800 | [diff] [blame] | 83 | int retval; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 84 | |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 85 | gb_i2c_dev = kzalloc(sizeof(*gb_i2c_dev), GFP_KERNEL); |
| 86 | if (!gb_i2c_dev) |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 87 | return -ENOMEM; |
| 88 | adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); |
| 89 | if (!adapter) { |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 90 | kfree(gb_i2c_dev); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 91 | return -ENOMEM; |
| 92 | } |
| 93 | |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 94 | i2c_set_adapdata(adapter, gb_i2c_dev); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 95 | adapter->owner = THIS_MODULE; |
| 96 | adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; |
| 97 | adapter->algo = &smbus_algorithm; |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 98 | adapter->dev.parent = &gmod->dev; |
Greg Kroah-Hartman | 53419e0 | 2014-08-11 17:01:15 +0800 | [diff] [blame] | 99 | adapter->retries = 3; /* we have to pick something... */ |
| 100 | snprintf(adapter->name, sizeof(adapter->name), "Greybus i2c adapter"); |
| 101 | retval = i2c_add_adapter(adapter); |
| 102 | if (retval) { |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 103 | dev_err(&gmod->dev, "Can not add SMBus adapter\n"); |
Greg Kroah-Hartman | 53419e0 | 2014-08-11 17:01:15 +0800 | [diff] [blame] | 104 | goto error; |
| 105 | } |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 106 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 107 | gb_i2c_dev->gmod = gmod; |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 108 | gb_i2c_dev->adapter = adapter; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 109 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 110 | gmod->gb_i2c_dev = gb_i2c_dev; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 111 | return 0; |
Greg Kroah-Hartman | 53419e0 | 2014-08-11 17:01:15 +0800 | [diff] [blame] | 112 | error: |
| 113 | kfree(adapter); |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 114 | kfree(gb_i2c_dev); |
Greg Kroah-Hartman | 53419e0 | 2014-08-11 17:01:15 +0800 | [diff] [blame] | 115 | return retval; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 116 | } |
| 117 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 118 | void gb_i2c_disconnect(struct greybus_module *gmod) |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 119 | { |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 120 | struct gb_i2c_device *gb_i2c_dev; |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 121 | |
Alex Elder | 778c69c | 2014-09-22 19:19:03 -0500 | [diff] [blame] | 122 | gb_i2c_dev = gmod->gb_i2c_dev; |
Greg Kroah-Hartman | 3d9efaa | 2014-08-30 16:49:59 -0700 | [diff] [blame] | 123 | i2c_del_adapter(gb_i2c_dev->adapter); |
| 124 | kfree(gb_i2c_dev->adapter); |
| 125 | kfree(gb_i2c_dev); |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 126 | } |
| 127 | |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 128 | #if 0 |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 129 | static struct greybus_driver i2c_gb_driver = { |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 130 | .probe = gb_i2c_probe, |
| 131 | .disconnect = gb_i2c_disconnect, |
Greg Kroah-Hartman | c8a797a | 2014-08-11 15:30:45 +0800 | [diff] [blame] | 132 | .id_table = id_table, |
| 133 | }; |
| 134 | |
| 135 | module_greybus_driver(i2c_gb_driver); |
| 136 | MODULE_LICENSE("GPL"); |
| 137 | MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>"); |
Greg Kroah-Hartman | 199d68d | 2014-08-30 16:20:22 -0700 | [diff] [blame] | 138 | #endif |