Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: cros_ec: Support multiple EC in a system

Chromebooks can have more than one Embedded Controller so the
cros_ec device id has to be incremented for each EC registered.

Add a new structure to represent multiple EC as different char
devices (e.g: /dev/cros_ec, /dev/cros_pd). It connects to
cros_ec_device and allows sysfs inferface for cros_pd.

Also reduce number of allocated objects, make chromeos sysfs
class object a static and add refcounting to prevent object
deletion while command is in progress.

Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Lee Jones <lee.jones@linaro.org>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Gwendal Grignou and committed by
Lee Jones
57b33ff0 d3654070

+236 -127
+1 -1
drivers/input/keyboard/cros_ec_keyb.c
··· 275 275 ckdev->dev = dev; 276 276 dev_set_drvdata(&pdev->dev, ckdev); 277 277 278 - idev->name = ec->ec_name; 278 + idev->name = CROS_EC_DEV_NAME; 279 279 idev->phys = ec->phys_name; 280 280 __set_bit(EV_REP, idev->evbit); 281 281
+46 -8
drivers/mfd/cros_ec.c
··· 24 24 #include <linux/mfd/core.h> 25 25 #include <linux/mfd/cros_ec.h> 26 26 27 - static const struct mfd_cell cros_devs[] = { 28 - { 29 - .name = "cros-ec-ctl", 30 - .id = PLATFORM_DEVID_AUTO, 31 - }, 27 + #define CROS_EC_DEV_EC_INDEX 0 28 + #define CROS_EC_DEV_PD_INDEX 1 29 + 30 + struct cros_ec_platform ec_p = { 31 + .ec_name = CROS_EC_DEV_NAME, 32 + .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX), 33 + }; 34 + 35 + struct cros_ec_platform pd_p = { 36 + .ec_name = CROS_EC_DEV_PD_NAME, 37 + .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX), 38 + }; 39 + 40 + struct mfd_cell ec_cell = { 41 + .name = "cros-ec-ctl", 42 + .platform_data = &ec_p, 43 + .pdata_size = sizeof(ec_p), 44 + }; 45 + 46 + struct mfd_cell ec_pd_cell = { 47 + .name = "cros-ec-ctl", 48 + .platform_data = &pd_p, 49 + .pdata_size = sizeof(pd_p), 32 50 }; 33 51 34 52 int cros_ec_register(struct cros_ec_device *ec_dev) ··· 70 52 71 53 cros_ec_query_all(ec_dev); 72 54 73 - err = mfd_add_devices(dev, 0, cros_devs, 74 - ARRAY_SIZE(cros_devs), 55 + err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, 1, 75 56 NULL, ec_dev->irq, NULL); 76 57 if (err) { 77 - dev_err(dev, "failed to add mfd devices\n"); 58 + dev_err(dev, 59 + "Failed to register Embedded Controller subdevice %d\n", 60 + err); 78 61 return err; 62 + } 63 + 64 + if (ec_dev->max_passthru) { 65 + /* 66 + * Register a PD device as well on top of this device. 67 + * We make the following assumptions: 68 + * - behind an EC, we have a pd 69 + * - only one device added. 70 + * - the EC is responsive at init time (it is not true for a 71 + * sensor hub. 72 + */ 73 + err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, 74 + &ec_pd_cell, 1, NULL, ec_dev->irq, NULL); 75 + if (err) { 76 + dev_err(dev, 77 + "Failed to register Power Delivery subdevice %d\n", 78 + err); 79 + return err; 80 + } 79 81 } 80 82 81 83 if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
-1
drivers/mfd/cros_ec_i2c.c
··· 302 302 ec_dev->irq = client->irq; 303 303 ec_dev->cmd_xfer = cros_ec_cmd_xfer_i2c; 304 304 ec_dev->pkt_xfer = cros_ec_pkt_xfer_i2c; 305 - ec_dev->ec_name = client->name; 306 305 ec_dev->phys_name = client->adapter->name; 307 306 ec_dev->din_size = sizeof(struct ec_host_response_i2c) + 308 307 sizeof(struct ec_response_get_protocol_info);
-1
drivers/mfd/cros_ec_spi.c
··· 637 637 ec_dev->irq = spi->irq; 638 638 ec_dev->cmd_xfer = cros_ec_cmd_xfer_spi; 639 639 ec_dev->pkt_xfer = cros_ec_pkt_xfer_spi; 640 - ec_dev->ec_name = ec_spi->spi->modalias; 641 640 ec_dev->phys_name = dev_name(&ec_spi->spi->dev); 642 641 ec_dev->din_size = EC_MSG_PREAMBLE_COUNT + 643 642 sizeof(struct ec_host_response) +
+91 -39
drivers/platform/chrome/cros_ec_dev.c
··· 27 27 28 28 /* Device variables */ 29 29 #define CROS_MAX_DEV 128 30 - static struct class *cros_class; 31 30 static int ec_major; 32 31 32 + static const struct attribute_group *cros_ec_groups[] = { 33 + &cros_ec_attr_group, 34 + &cros_ec_lightbar_attr_group, 35 + NULL, 36 + }; 37 + 38 + static struct class cros_class = { 39 + .owner = THIS_MODULE, 40 + .name = "chromeos", 41 + .dev_groups = cros_ec_groups, 42 + }; 43 + 33 44 /* Basic communication */ 34 - static int ec_get_version(struct cros_ec_device *ec, char *str, int maxlen) 45 + static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen) 35 46 { 36 47 struct ec_response_get_version *resp; 37 48 static const char * const current_image_name[] = { ··· 56 45 return -ENOMEM; 57 46 58 47 msg->version = 0; 59 - msg->command = EC_CMD_GET_VERSION; 48 + msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; 60 49 msg->insize = sizeof(*resp); 61 50 msg->outsize = 0; 62 51 63 - ret = cros_ec_cmd_xfer(ec, msg); 52 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 64 53 if (ret < 0) 65 54 goto exit; 66 55 ··· 89 78 /* Device file ops */ 90 79 static int ec_device_open(struct inode *inode, struct file *filp) 91 80 { 92 - filp->private_data = container_of(inode->i_cdev, 93 - struct cros_ec_device, cdev); 81 + struct cros_ec_dev *ec = container_of(inode->i_cdev, 82 + struct cros_ec_dev, cdev); 83 + filp->private_data = ec; 84 + nonseekable_open(inode, filp); 94 85 return 0; 95 86 } 96 87 ··· 104 91 static ssize_t ec_device_read(struct file *filp, char __user *buffer, 105 92 size_t length, loff_t *offset) 106 93 { 107 - struct cros_ec_device *ec = filp->private_data; 94 + struct cros_ec_dev *ec = filp->private_data; 108 95 char msg[sizeof(struct ec_response_get_version) + 109 96 sizeof(CROS_EC_DEV_VERSION)]; 110 97 size_t count; ··· 127 114 } 128 115 129 116 /* Ioctls */ 130 - static long ec_device_ioctl_xcmd(struct cros_ec_device *ec, void __user *arg) 117 + static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) 131 118 { 132 119 long ret; 133 120 struct cros_ec_command u_cmd; ··· 146 133 goto exit; 147 134 } 148 135 149 - ret = cros_ec_cmd_xfer(ec, s_cmd); 136 + s_cmd->command += ec->cmd_offset; 137 + ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd); 150 138 /* Only copy data to userland if data was received. */ 151 139 if (ret < 0) 152 140 goto exit; ··· 159 145 return ret; 160 146 } 161 147 162 - static long ec_device_ioctl_readmem(struct cros_ec_device *ec, void __user *arg) 148 + static long ec_device_ioctl_readmem(struct cros_ec_dev *ec, void __user *arg) 163 149 { 150 + struct cros_ec_device *ec_dev = ec->ec_dev; 164 151 struct cros_ec_readmem s_mem = { }; 165 152 long num; 166 153 167 154 /* Not every platform supports direct reads */ 168 - if (!ec->cmd_readmem) 155 + if (!ec_dev->cmd_readmem) 169 156 return -ENOTTY; 170 157 171 158 if (copy_from_user(&s_mem, arg, sizeof(s_mem))) 172 159 return -EFAULT; 173 160 174 - num = ec->cmd_readmem(ec, s_mem.offset, s_mem.bytes, s_mem.buffer); 161 + num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes, 162 + s_mem.buffer); 175 163 if (num <= 0) 176 164 return num; 177 165 ··· 186 170 static long ec_device_ioctl(struct file *filp, unsigned int cmd, 187 171 unsigned long arg) 188 172 { 189 - struct cros_ec_device *ec = filp->private_data; 173 + struct cros_ec_dev *ec = filp->private_data; 190 174 191 175 if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) 192 176 return -ENOTTY; ··· 209 193 .unlocked_ioctl = ec_device_ioctl, 210 194 }; 211 195 196 + static void __remove(struct device *dev) 197 + { 198 + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, 199 + class_dev); 200 + kfree(ec); 201 + } 202 + 212 203 static int ec_device_probe(struct platform_device *pdev) 213 204 { 214 - struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); 215 - int retval = -ENOTTY; 216 - dev_t devno = MKDEV(ec_major, 0); 205 + int retval = -ENOMEM; 206 + struct device *dev = &pdev->dev; 207 + struct cros_ec_platform *ec_platform = dev_get_platdata(dev); 208 + dev_t devno = MKDEV(ec_major, pdev->id); 209 + struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); 217 210 218 - /* Instantiate it (and remember the EC) */ 211 + if (!ec) 212 + return retval; 213 + 214 + dev_set_drvdata(dev, ec); 215 + ec->ec_dev = dev_get_drvdata(dev->parent); 216 + ec->dev = dev; 217 + ec->cmd_offset = ec_platform->cmd_offset; 218 + device_initialize(&ec->class_dev); 219 219 cdev_init(&ec->cdev, &fops); 220 220 221 + /* 222 + * Add the character device 223 + * Link cdev to the class device to be sure device is not used 224 + * before unbinding it. 225 + */ 226 + ec->cdev.kobj.parent = &ec->class_dev.kobj; 221 227 retval = cdev_add(&ec->cdev, devno, 1); 222 228 if (retval) { 223 - dev_err(&pdev->dev, ": failed to add character device\n"); 224 - return retval; 229 + dev_err(dev, ": failed to add character device\n"); 230 + goto cdev_add_failed; 225 231 } 226 232 227 - ec->vdev = device_create(cros_class, NULL, devno, ec, 228 - CROS_EC_DEV_NAME); 229 - if (IS_ERR(ec->vdev)) { 230 - retval = PTR_ERR(ec->vdev); 231 - dev_err(&pdev->dev, ": failed to create device\n"); 232 - cdev_del(&ec->cdev); 233 - return retval; 233 + /* 234 + * Add the class device 235 + * Link to the character device for creating the /dev entry 236 + * in devtmpfs. 237 + */ 238 + ec->class_dev.devt = ec->cdev.dev; 239 + ec->class_dev.class = &cros_class; 240 + ec->class_dev.parent = dev; 241 + ec->class_dev.release = __remove; 242 + 243 + retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name); 244 + if (retval) { 245 + dev_err(dev, "dev_set_name failed => %d\n", retval); 246 + goto set_named_failed; 234 247 } 235 248 236 - /* Initialize extra interfaces */ 237 - ec_dev_sysfs_init(ec); 238 - ec_dev_lightbar_init(ec); 249 + retval = device_add(&ec->class_dev); 250 + if (retval) { 251 + dev_err(dev, "device_register failed => %d\n", retval); 252 + goto dev_reg_failed; 253 + } 239 254 240 255 return 0; 256 + 257 + dev_reg_failed: 258 + set_named_failed: 259 + dev_set_drvdata(dev, NULL); 260 + cdev_del(&ec->cdev); 261 + cdev_add_failed: 262 + kfree(ec); 263 + return retval; 241 264 } 242 265 243 266 static int ec_device_remove(struct platform_device *pdev) 244 267 { 245 - struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); 246 - 247 - ec_dev_lightbar_remove(ec); 248 - ec_dev_sysfs_remove(ec); 249 - device_destroy(cros_class, MKDEV(ec_major, 0)); 268 + struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); 250 269 cdev_del(&ec->cdev); 270 + device_unregister(&ec->class_dev); 251 271 return 0; 252 272 } 253 273 ··· 300 248 int ret; 301 249 dev_t dev = 0; 302 250 303 - cros_class = class_create(THIS_MODULE, "chromeos"); 304 - if (IS_ERR(cros_class)) { 251 + ret = class_register(&cros_class); 252 + if (ret) { 305 253 pr_err(CROS_EC_DEV_NAME ": failed to register device class\n"); 306 - return PTR_ERR(cros_class); 254 + return ret; 307 255 } 308 256 309 257 /* Get a range of minor numbers (starting with 0) to work with */ ··· 325 273 failed_devreg: 326 274 unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV); 327 275 failed_chrdevreg: 328 - class_destroy(cros_class); 276 + class_unregister(&cros_class); 329 277 return ret; 330 278 } 331 279 ··· 333 281 { 334 282 platform_driver_unregister(&cros_ec_dev_driver); 335 283 unregister_chrdev(ec_major, CROS_EC_DEV_NAME); 336 - class_destroy(cros_class); 284 + class_unregister(&cros_class); 337 285 } 338 286 339 287 module_init(cros_ec_dev_init);
-7
drivers/platform/chrome/cros_ec_dev.h
··· 24 24 #include <linux/types.h> 25 25 #include <linux/mfd/cros_ec.h> 26 26 27 - #define CROS_EC_DEV_NAME "cros_ec" 28 27 #define CROS_EC_DEV_VERSION "1.0.0" 29 28 30 29 /* ··· 42 43 #define CROS_EC_DEV_IOC 0xEC 43 44 #define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) 44 45 #define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) 45 - 46 - void ec_dev_sysfs_init(struct cros_ec_device *); 47 - void ec_dev_sysfs_remove(struct cros_ec_device *); 48 - 49 - void ec_dev_lightbar_init(struct cros_ec_device *); 50 - void ec_dev_lightbar_remove(struct cros_ec_device *); 51 46 52 47 #endif /* _CROS_EC_DEV_H_ */
+41 -34
drivers/platform/chrome/cros_ec_lightbar.c
··· 92 92 return ret; 93 93 } 94 94 95 - static struct cros_ec_command *alloc_lightbar_cmd_msg(void) 95 + static struct cros_ec_command *alloc_lightbar_cmd_msg(struct cros_ec_dev *ec) 96 96 { 97 97 struct cros_ec_command *msg; 98 98 int len; ··· 105 105 return NULL; 106 106 107 107 msg->version = 0; 108 - msg->command = EC_CMD_LIGHTBAR_CMD; 108 + msg->command = EC_CMD_LIGHTBAR_CMD + ec->cmd_offset; 109 109 msg->outsize = sizeof(struct ec_params_lightbar); 110 110 msg->insize = sizeof(struct ec_response_lightbar); 111 111 112 112 return msg; 113 113 } 114 114 115 - static int get_lightbar_version(struct cros_ec_device *ec, 115 + static int get_lightbar_version(struct cros_ec_dev *ec, 116 116 uint32_t *ver_ptr, uint32_t *flg_ptr) 117 117 { 118 118 struct ec_params_lightbar *param; ··· 120 120 struct cros_ec_command *msg; 121 121 int ret; 122 122 123 - msg = alloc_lightbar_cmd_msg(); 123 + msg = alloc_lightbar_cmd_msg(ec); 124 124 if (!msg) 125 125 return 0; 126 126 127 127 param = (struct ec_params_lightbar *)msg->data; 128 128 param->cmd = LIGHTBAR_CMD_VERSION; 129 - ret = cros_ec_cmd_xfer(ec, msg); 129 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 130 130 if (ret < 0) { 131 131 ret = 0; 132 132 goto exit; ··· 165 165 struct device_attribute *attr, char *buf) 166 166 { 167 167 uint32_t version = 0, flags = 0; 168 - struct cros_ec_device *ec = dev_get_drvdata(dev); 168 + struct cros_ec_dev *ec = container_of(dev, 169 + struct cros_ec_dev, class_dev); 169 170 int ret; 170 171 171 172 ret = lb_throttle(); ··· 188 187 struct cros_ec_command *msg; 189 188 int ret; 190 189 unsigned int val; 191 - struct cros_ec_device *ec = dev_get_drvdata(dev); 190 + struct cros_ec_dev *ec = container_of(dev, 191 + struct cros_ec_dev, class_dev); 192 192 193 193 if (kstrtouint(buf, 0, &val)) 194 194 return -EINVAL; 195 195 196 - msg = alloc_lightbar_cmd_msg(); 196 + msg = alloc_lightbar_cmd_msg(ec); 197 197 if (!msg) 198 198 return -ENOMEM; 199 199 ··· 205 203 if (ret) 206 204 goto exit; 207 205 208 - ret = cros_ec_cmd_xfer(ec, msg); 206 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 209 207 if (ret < 0) 210 208 goto exit; 211 209 ··· 233 231 { 234 232 struct ec_params_lightbar *param; 235 233 struct cros_ec_command *msg; 236 - struct cros_ec_device *ec = dev_get_drvdata(dev); 234 + struct cros_ec_dev *ec = container_of(dev, 235 + struct cros_ec_dev, class_dev); 237 236 unsigned int val[4]; 238 237 int ret, i = 0, j = 0, ok = 0; 239 238 240 - msg = alloc_lightbar_cmd_msg(); 239 + msg = alloc_lightbar_cmd_msg(ec); 241 240 if (!msg) 242 241 return -ENOMEM; 243 242 ··· 271 268 return ret; 272 269 } 273 270 274 - ret = cros_ec_cmd_xfer(ec, msg); 271 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 275 272 if (ret < 0) 276 273 goto exit; 277 274 ··· 307 304 struct ec_response_lightbar *resp; 308 305 struct cros_ec_command *msg; 309 306 int ret; 310 - struct cros_ec_device *ec = dev_get_drvdata(dev); 307 + struct cros_ec_dev *ec = container_of(dev, 308 + struct cros_ec_dev, class_dev); 311 309 312 - msg = alloc_lightbar_cmd_msg(); 310 + msg = alloc_lightbar_cmd_msg(ec); 313 311 if (!msg) 314 312 return -ENOMEM; 315 313 ··· 320 316 if (ret) 321 317 goto exit; 322 318 323 - ret = cros_ec_cmd_xfer(ec, msg); 319 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 324 320 if (ret < 0) 325 321 goto exit; 326 322 ··· 349 345 struct cros_ec_command *msg; 350 346 unsigned int num; 351 347 int ret, len; 352 - struct cros_ec_device *ec = dev_get_drvdata(dev); 348 + struct cros_ec_dev *ec = container_of(dev, 349 + struct cros_ec_dev, class_dev); 353 350 354 - msg = alloc_lightbar_cmd_msg(); 351 + msg = alloc_lightbar_cmd_msg(ec); 355 352 if (!msg) 356 353 return -ENOMEM; 357 354 ··· 377 372 if (ret) 378 373 return ret; 379 374 380 - ret = cros_ec_cmd_xfer(ec, msg); 375 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 381 376 if (ret < 0) 382 377 return ret; 383 378 ··· 402 397 &dev_attr_sequence.attr, 403 398 NULL, 404 399 }; 405 - static struct attribute_group lb_cmds_attr_group = { 406 - .name = "lightbar", 407 - .attrs = __lb_cmds_attrs, 408 - }; 409 400 410 - void ec_dev_lightbar_init(struct cros_ec_device *ec) 401 + static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj, 402 + struct attribute *a, int n) 411 403 { 412 - int ret = 0; 404 + struct device *dev = container_of(kobj, struct device, kobj); 405 + struct cros_ec_dev *ec = container_of(dev, 406 + struct cros_ec_dev, class_dev); 407 + struct platform_device *pdev = container_of(ec->dev, 408 + struct platform_device, dev); 409 + if (pdev->id != 0) 410 + return 0; 413 411 414 412 /* Only instantiate this stuff if the EC has a lightbar */ 415 - if (!get_lightbar_version(ec, NULL, NULL)) 416 - return; 417 - 418 - ret = sysfs_create_group(&ec->vdev->kobj, &lb_cmds_attr_group); 419 - if (ret) 420 - pr_warn("sysfs_create_group() failed: %d\n", ret); 413 + if (get_lightbar_version(ec, NULL, NULL)) 414 + return a->mode; 415 + else 416 + return 0; 421 417 } 422 418 423 - void ec_dev_lightbar_remove(struct cros_ec_device *ec) 424 - { 425 - sysfs_remove_group(&ec->vdev->kobj, &lb_cmds_attr_group); 426 - } 419 + struct attribute_group cros_ec_lightbar_attr_group = { 420 + .name = "lightbar", 421 + .attrs = __lb_cmds_attrs, 422 + .is_visible = cros_ec_lightbar_attrs_are_visible, 423 + };
-1
drivers/platform/chrome/cros_ec_lpc.c
··· 283 283 284 284 platform_set_drvdata(pdev, ec_dev); 285 285 ec_dev->dev = dev; 286 - ec_dev->ec_name = pdev->name; 287 286 ec_dev->phys_name = dev_name(dev); 288 287 ec_dev->cmd_xfer = cros_ec_cmd_xfer_lpc; 289 288 ec_dev->pkt_xfer = cros_ec_pkt_xfer_lpc;
+19 -29
drivers/platform/chrome/cros_ec_sysfs.c
··· 72 72 int got_cmd = 0, offset = 0; 73 73 int i; 74 74 int ret; 75 - struct cros_ec_device *ec = dev_get_drvdata(dev); 75 + struct cros_ec_dev *ec = container_of(dev, 76 + struct cros_ec_dev, class_dev); 76 77 77 78 msg = kmalloc(sizeof(*msg) + sizeof(*param), GFP_KERNEL); 78 79 if (!msg) ··· 113 112 } 114 113 115 114 msg->version = 0; 116 - msg->command = EC_CMD_REBOOT_EC; 115 + msg->command = EC_CMD_REBOOT_EC + ec->cmd_offset; 117 116 msg->outsize = sizeof(*param); 118 117 msg->insize = 0; 119 - ret = cros_ec_cmd_xfer(ec, msg); 118 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 120 119 if (ret < 0) { 121 120 count = ret; 122 121 goto exit; ··· 140 139 struct cros_ec_command *msg; 141 140 int ret; 142 141 int count = 0; 143 - struct cros_ec_device *ec = dev_get_drvdata(dev); 142 + struct cros_ec_dev *ec = container_of(dev, 143 + struct cros_ec_dev, class_dev); 144 144 145 145 msg = kmalloc(sizeof(*msg) + EC_HOST_PARAM_SIZE, GFP_KERNEL); 146 146 if (!msg) ··· 149 147 150 148 /* Get versions. RW may change. */ 151 149 msg->version = 0; 152 - msg->command = EC_CMD_GET_VERSION; 150 + msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; 153 151 msg->insize = sizeof(*r_ver); 154 152 msg->outsize = 0; 155 - ret = cros_ec_cmd_xfer(ec, msg); 153 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 156 154 if (ret < 0) { 157 155 count = ret; 158 156 goto exit; ··· 177 175 image_names[r_ver->current_image] : "?")); 178 176 179 177 /* Get build info. */ 180 - msg->command = EC_CMD_GET_BUILD_INFO; 178 + msg->command = EC_CMD_GET_BUILD_INFO + ec->cmd_offset; 181 179 msg->insize = EC_HOST_PARAM_SIZE; 182 - ret = cros_ec_cmd_xfer(ec, msg); 180 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 183 181 if (ret < 0) 184 182 count += scnprintf(buf + count, PAGE_SIZE - count, 185 183 "Build info: XFER ERROR %d\n", ret); ··· 193 191 } 194 192 195 193 /* Get chip info. */ 196 - msg->command = EC_CMD_GET_CHIP_INFO; 194 + msg->command = EC_CMD_GET_CHIP_INFO + ec->cmd_offset; 197 195 msg->insize = sizeof(*r_chip); 198 - ret = cros_ec_cmd_xfer(ec, msg); 196 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 199 197 if (ret < 0) 200 198 count += scnprintf(buf + count, PAGE_SIZE - count, 201 199 "Chip info: XFER ERROR %d\n", ret); ··· 217 215 } 218 216 219 217 /* Get board version */ 220 - msg->command = EC_CMD_GET_BOARD_VERSION; 218 + msg->command = EC_CMD_GET_BOARD_VERSION + ec->cmd_offset; 221 219 msg->insize = sizeof(*r_board); 222 - ret = cros_ec_cmd_xfer(ec, msg); 220 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 223 221 if (ret < 0) 224 222 count += scnprintf(buf + count, PAGE_SIZE - count, 225 223 "Board version: XFER ERROR %d\n", ret); ··· 245 243 struct ec_response_flash_info *resp; 246 244 struct cros_ec_command *msg; 247 245 int ret; 248 - struct cros_ec_device *ec = dev_get_drvdata(dev); 246 + struct cros_ec_dev *ec = container_of(dev, 247 + struct cros_ec_dev, class_dev); 249 248 250 249 msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); 251 250 if (!msg) ··· 254 251 255 252 /* The flash info shouldn't ever change, but ask each time anyway. */ 256 253 msg->version = 0; 257 - msg->command = EC_CMD_FLASH_INFO; 254 + msg->command = EC_CMD_FLASH_INFO + ec->cmd_offset; 258 255 msg->insize = sizeof(*resp); 259 256 msg->outsize = 0; 260 - ret = cros_ec_cmd_xfer(ec, msg); 257 + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); 261 258 if (ret < 0) 262 259 goto exit; 263 260 if (msg->result != EC_RES_SUCCESS) { ··· 291 288 NULL, 292 289 }; 293 290 294 - static struct attribute_group ec_attr_group = { 291 + struct attribute_group cros_ec_attr_group = { 295 292 .attrs = __ec_attrs, 296 293 }; 297 294 298 - void ec_dev_sysfs_init(struct cros_ec_device *ec) 299 - { 300 - int error; 301 - 302 - error = sysfs_create_group(&ec->vdev->kobj, &ec_attr_group); 303 - if (error) 304 - pr_warn("failed to create group: %d\n", error); 305 - } 306 - 307 - void ec_dev_sysfs_remove(struct cros_ec_device *ec) 308 - { 309 - sysfs_remove_group(&ec->vdev->kobj, &ec_attr_group); 310 - }
+38 -6
include/linux/mfd/cros_ec.h
··· 17 17 #define __LINUX_MFD_CROS_EC_H 18 18 19 19 #include <linux/cdev.h> 20 + #include <linux/device.h> 20 21 #include <linux/notifier.h> 21 22 #include <linux/mfd/cros_ec_commands.h> 22 23 #include <linux/mutex.h> 24 + 25 + #define CROS_EC_DEV_NAME "cros_ec" 26 + #define CROS_EC_DEV_PD_NAME "cros_pd" 23 27 24 28 /* 25 29 * The EC is unresponsive for a time after a reboot command. Add a ··· 75 71 /** 76 72 * struct cros_ec_device - Information about a ChromeOS EC device 77 73 * 78 - * @ec_name: name of EC device (e.g. 'chromeos-ec') 79 74 * @phys_name: name of physical comms layer (e.g. 'i2c-4') 80 75 * @dev: Device pointer for physical comms device 81 - * @vdev: Device pointer for virtual comms device 82 - * @cdev: Character device structure for virtual comms device 83 76 * @was_wake_device: true if this device was set to wake the system from 84 77 * sleep at the last suspend 85 78 * @cmd_readmem: direct read of the EC memory-mapped region, if supported ··· 88 87 * 89 88 * @priv: Private data 90 89 * @irq: Interrupt to use 90 + * @id: Device id 91 91 * @din: input buffer (for data from EC) 92 92 * @dout: output buffer (for data to EC) 93 93 * \note ··· 111 109 struct cros_ec_device { 112 110 113 111 /* These are used by other drivers that want to talk to the EC */ 114 - const char *ec_name; 115 112 const char *phys_name; 116 113 struct device *dev; 117 - struct device *vdev; 118 - struct cdev cdev; 119 114 bool was_wake_device; 120 115 struct class *cros_class; 121 116 int (*cmd_readmem)(struct cros_ec_device *ec, unsigned int offset, ··· 135 136 int (*pkt_xfer)(struct cros_ec_device *ec, 136 137 struct cros_ec_command *msg); 137 138 struct mutex lock; 139 + }; 140 + 141 + /* struct cros_ec_platform - ChromeOS EC platform information 142 + * 143 + * @ec_name: name of EC device (e.g. 'cros-ec', 'cros-pd', ...) 144 + * used in /dev/ and sysfs. 145 + * @cmd_offset: offset to apply for each command. Set when 146 + * registering a devicde behind another one. 147 + */ 148 + struct cros_ec_platform { 149 + const char *ec_name; 150 + u16 cmd_offset; 151 + }; 152 + 153 + /* 154 + * struct cros_ec_dev - ChromeOS EC device entry point 155 + * 156 + * @class_dev: Device structure used in sysfs 157 + * @cdev: Character device structure in /dev 158 + * @ec_dev: cros_ec_device structure to talk to the physical device 159 + * @dev: pointer to the platform device 160 + * @cmd_offset: offset to apply for each command. 161 + */ 162 + struct cros_ec_dev { 163 + struct device class_dev; 164 + struct cdev cdev; 165 + struct cros_ec_device *ec_dev; 166 + struct device *dev; 167 + u16 cmd_offset; 138 168 }; 139 169 140 170 /** ··· 251 223 * @return 0 if ok, -ve on error 252 224 */ 253 225 int cros_ec_query_all(struct cros_ec_device *ec_dev); 226 + 227 + /* sysfs stuff */ 228 + extern struct attribute_group cros_ec_attr_group; 229 + extern struct attribute_group cros_ec_lightbar_attr_group; 254 230 255 231 #endif /* __LINUX_MFD_CROS_EC_H */