static int gb_vibrator_probe(struct gb_bundle *bundle, const struct greybus_bundle_id *id) { struct greybus_descriptor_cport *cport_desc; struct gb_connection *connection; struct gb_vibrator_device *vib; struct device *dev; int retval; if (bundle->num_cports != 1) return -ENODEV; cport_desc = &bundle->cport_desc[0]; if (cport_desc->protocol_id != GREYBUS_PROTOCOL_VIBRATOR) return -ENODEV; vib = kzalloc(sizeof(*vib), GFP_KERNEL); if (!vib) return -ENOMEM; connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), NULL); if (IS_ERR(connection)) { retval = PTR_ERR(connection); goto err_free_vib; } gb_connection_set_data(connection, vib); vib->connection = connection; greybus_set_drvdata(bundle, vib); retval = gb_connection_enable(connection); if (retval) goto err_connection_destroy; /* * For now we create a device in sysfs for the vibrator, but odds are * there is a "real" device somewhere in the kernel for this, but I * can't find it at the moment... */ vib->minor = ida_simple_get(&minors, 0, 0, GFP_KERNEL); if (vib->minor < 0) { retval = vib->minor; goto err_connection_disable; } dev = device_create(&vibrator_class, &bundle->dev, MKDEV(0, 0), vib, "vibrator%d", vib->minor); if (IS_ERR(dev)) { retval = -EINVAL; goto err_ida_remove; } vib->dev = dev; INIT_DELAYED_WORK(&vib->delayed_work, gb_vibrator_worker); gb_pm_runtime_put_autosuspend(bundle); return 0; err_ida_remove: ida_simple_remove(&minors, vib->minor); err_connection_disable: gb_connection_disable(connection); err_connection_destroy: gb_connection_destroy(connection); err_free_vib: kfree(vib); return retval; }
static int gb_firmware_probe(struct gb_bundle *bundle, const struct greybus_bundle_id *id) { struct greybus_descriptor_cport *cport_desc; struct gb_connection *connection; struct gb_firmware *firmware; int ret; if (bundle->num_cports != 1) return -ENODEV; cport_desc = &bundle->cport_desc[0]; if (cport_desc->protocol_id != GREYBUS_PROTOCOL_FIRMWARE) return -ENODEV; firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) return -ENOMEM; connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), gb_firmware_request_handler); if (IS_ERR(connection)) { ret = PTR_ERR(connection); goto err_free_firmware; } gb_connection_set_data(connection, firmware); firmware->connection = connection; greybus_set_drvdata(bundle, firmware); ret = gb_connection_enable_tx(connection); if (ret) goto err_connection_destroy; ret = gb_firmware_get_version(firmware); if (ret) goto err_connection_disable; firmware_es2_fixup_vid_pid(firmware); ret = gb_connection_enable(connection); if (ret) goto err_connection_disable; /* Tell bootrom we're ready. */ ret = gb_operation_sync(connection, GB_FIRMWARE_TYPE_AP_READY, NULL, 0, NULL, 0); if (ret) { dev_err(&connection->bundle->dev, "failed to send AP READY: %d\n", ret); goto err_connection_disable; } dev_dbg(&bundle->dev, "AP_READY sent\n"); return 0; err_connection_disable: gb_connection_disable(connection); err_connection_destroy: gb_connection_destroy(connection); err_free_firmware: kfree(firmware); return ret; }
static int gb_gpio_probe(struct gbphy_device *gbphy_dev, const struct gbphy_device_id *id) { struct gb_connection *connection; struct gb_gpio_controller *ggc; struct gpio_chip *gpio; struct irq_chip *irqc; int ret; ggc = kzalloc(sizeof(*ggc), GFP_KERNEL); if (!ggc) return -ENOMEM; connection = gb_connection_create(gbphy_dev->bundle, le16_to_cpu(gbphy_dev->cport_desc->id), gb_gpio_request_handler); if (IS_ERR(connection)) { ret = PTR_ERR(connection); goto exit_ggc_free; } ggc->connection = connection; gb_connection_set_data(connection, ggc); ggc->gbphy_dev = gbphy_dev; gb_gbphy_set_data(gbphy_dev, ggc); ret = gb_connection_enable_tx(connection); if (ret) goto exit_connection_destroy; ret = gb_gpio_controller_setup(ggc); if (ret) goto exit_connection_disable; irqc = &ggc->irqc; irqc->irq_mask = gb_gpio_irq_mask; irqc->irq_unmask = gb_gpio_irq_unmask; irqc->irq_set_type = gb_gpio_irq_set_type; irqc->irq_bus_lock = gb_gpio_irq_bus_lock; irqc->irq_bus_sync_unlock = gb_gpio_irq_bus_sync_unlock; irqc->name = "greybus_gpio"; mutex_init(&ggc->irq_lock); gpio = &ggc->chip; gpio->label = "greybus_gpio"; gpio->parent = &gbphy_dev->dev; gpio->owner = THIS_MODULE; gpio->request = gb_gpio_request; gpio->free = gb_gpio_free; gpio->get_direction = gb_gpio_get_direction; gpio->direction_input = gb_gpio_direction_input; gpio->direction_output = gb_gpio_direction_output; gpio->get = gb_gpio_get; gpio->set = gb_gpio_set; gpio->set_config = gb_gpio_set_config; gpio->to_irq = gb_gpio_to_irq; gpio->base = -1; /* Allocate base dynamically */ gpio->ngpio = ggc->line_max + 1; gpio->can_sleep = true; ret = gb_connection_enable(connection); if (ret) goto exit_line_free; ret = gb_gpio_irqchip_add(gpio, irqc, 0, handle_level_irq, IRQ_TYPE_NONE); if (ret) { dev_err(&gbphy_dev->dev, "failed to add irq chip: %d\n", ret); goto exit_line_free; } ret = gpiochip_add(gpio); if (ret) { dev_err(&gbphy_dev->dev, "failed to add gpio chip: %d\n", ret); goto exit_gpio_irqchip_remove; } gbphy_runtime_put_autosuspend(gbphy_dev); return 0; exit_gpio_irqchip_remove: gb_gpio_irqchip_remove(ggc); exit_line_free: kfree(ggc->lines); exit_connection_disable: gb_connection_disable(connection); exit_connection_destroy: gb_connection_destroy(connection); exit_ggc_free: kfree(ggc); return ret; }
static int gb_gpio_connection_init(struct gb_connection *connection) { struct gb_gpio_controller *ggc; struct gpio_chip *gpio; struct irq_chip *irqc; int ret; ggc = kzalloc(sizeof(*ggc), GFP_KERNEL); if (!ggc) return -ENOMEM; ggc->connection = connection; gb_connection_set_data(connection, ggc); ret = gb_gpio_controller_setup(ggc); if (ret) goto err_free_controller; irqc = &ggc->irqc; irqc->irq_mask = gb_gpio_irq_mask; irqc->irq_unmask = gb_gpio_irq_unmask; irqc->irq_set_type = gb_gpio_irq_set_type; irqc->irq_bus_lock = gb_gpio_irq_bus_lock; irqc->irq_bus_sync_unlock = gb_gpio_irq_bus_sync_unlock; irqc->name = "greybus_gpio"; mutex_init(&ggc->irq_lock); gpio = &ggc->chip; gpio->label = "greybus_gpio"; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) gpio->parent = &connection->bundle->dev; #else gpio->dev = &connection->bundle->dev; #endif gpio->owner = THIS_MODULE; gpio->request = gb_gpio_request; gpio->free = gb_gpio_free; gpio->get_direction = gb_gpio_get_direction; gpio->direction_input = gb_gpio_direction_input; gpio->direction_output = gb_gpio_direction_output; gpio->get = gb_gpio_get; gpio->set = gb_gpio_set; gpio->set_debounce = gb_gpio_set_debounce; gpio->to_irq = gb_gpio_to_irq; gpio->base = -1; /* Allocate base dynamically */ gpio->ngpio = ggc->line_max + 1; gpio->can_sleep = true; ret = gpiochip_add(gpio); if (ret) { dev_err(&connection->bundle->dev, "failed to add gpio chip: %d\n", ret); goto err_free_lines; } ret = gb_gpio_irqchip_add(gpio, irqc, 0, handle_level_irq, IRQ_TYPE_NONE); if (ret) { dev_err(&connection->bundle->dev, "failed to add irq chip: %d\n", ret); goto irqchip_err; } return 0; irqchip_err: gb_gpiochip_remove(gpio); err_free_lines: kfree(ggc->lines); err_free_controller: kfree(ggc); return ret; }
static int gb_bootrom_probe(struct gb_bundle *bundle, const struct greybus_bundle_id *id) { struct greybus_descriptor_cport *cport_desc; struct gb_connection *connection; struct gb_bootrom *bootrom; int ret; if (bundle->num_cports != 1) return -ENODEV; cport_desc = &bundle->cport_desc[0]; if (cport_desc->protocol_id != GREYBUS_PROTOCOL_BOOTROM) return -ENODEV; bootrom = kzalloc(sizeof(*bootrom), GFP_KERNEL); if (!bootrom) return -ENOMEM; connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), gb_bootrom_request_handler); if (IS_ERR(connection)) { ret = PTR_ERR(connection); goto err_free_bootrom; } gb_connection_set_data(connection, bootrom); bootrom->connection = connection; mutex_init(&bootrom->mutex); INIT_DELAYED_WORK(&bootrom->dwork, gb_bootrom_timedout); greybus_set_drvdata(bundle, bootrom); ret = gb_connection_enable_tx(connection); if (ret) goto err_connection_destroy; ret = gb_bootrom_get_version(bootrom); if (ret) goto err_connection_disable; bootrom_es2_fixup_vid_pid(bootrom); ret = gb_connection_enable(connection); if (ret) goto err_connection_disable; /* Refresh timeout */ gb_bootrom_set_timeout(bootrom, NEXT_REQ_FIRMWARE_SIZE, NEXT_REQ_TIMEOUT_MS); /* Tell bootrom we're ready. */ ret = gb_operation_sync(connection, GB_BOOTROM_TYPE_AP_READY, NULL, 0, NULL, 0); if (ret) { dev_err(&connection->bundle->dev, "failed to send AP READY: %d\n", ret); goto err_cancel_timeout; } dev_dbg(&bundle->dev, "AP_READY sent\n"); return 0; err_cancel_timeout: gb_bootrom_cancel_timeout(bootrom); err_connection_disable: gb_connection_disable(connection); err_connection_destroy: gb_connection_destroy(connection); err_free_bootrom: kfree(bootrom); return ret; }
static int gb_lights_probe(struct gb_bundle *bundle, const struct greybus_bundle_id *id) { struct greybus_descriptor_cport *cport_desc; struct gb_connection *connection; struct gb_lights *glights; int ret; if (bundle->num_cports != 1) return -ENODEV; cport_desc = &bundle->cport_desc[0]; if (cport_desc->protocol_id != GREYBUS_PROTOCOL_LIGHTS) return -ENODEV; glights = kzalloc(sizeof(*glights), GFP_KERNEL); if (!glights) return -ENOMEM; mutex_init(&glights->lights_lock); connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), gb_lights_request_handler); if (IS_ERR(connection)) { ret = PTR_ERR(connection); goto out; } glights->connection = connection; gb_connection_set_data(connection, glights); greybus_set_drvdata(bundle, glights); /* We aren't ready to receive an incoming request yet */ ret = gb_connection_enable_tx(connection); if (ret) goto error_connection_destroy; /* * Setup all the lights devices over this connection, if anything goes * wrong tear down all lights */ ret = gb_lights_create_all(glights); if (ret < 0) goto error_connection_disable; /* We are ready to receive an incoming request now, enable RX as well */ ret = gb_connection_enable(connection); if (ret) goto error_connection_disable; /* Enable & register lights */ ret = gb_lights_register_all(glights); if (ret < 0) goto error_connection_disable; gb_pm_runtime_put_autosuspend(bundle); return 0; error_connection_disable: gb_connection_disable(connection); error_connection_destroy: gb_connection_destroy(connection); out: gb_lights_release(glights); return ret; }