static int gb_blink_set(struct led_classdev *cdev, unsigned long *delay_on, unsigned long *delay_off) { struct gb_channel *channel = get_channel_from_cdev(cdev); struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_blink_request req; bool old_active; int ret; if (channel->releasing) return -ESHUTDOWN; mutex_lock(&channel->lock); ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) goto out_unlock; old_active = channel->active; req.light_id = channel->light->id; req.channel_id = channel->id; req.time_on_ms = cpu_to_le16(*delay_on); req.time_off_ms = cpu_to_le16(*delay_off); ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_BLINK, &req, sizeof(req), NULL, 0); if (ret < 0) goto out_pm_put; if (delay_on) channel->active = true; else channel->active = false; /* we need to keep module alive when turning to active state */ if (!old_active && channel->active) goto out_unlock; /* * on the other hand if going to inactive we still hold a reference and * need to put it, so we could go to suspend. */ if (old_active && !channel->active) gb_pm_runtime_put_autosuspend(bundle); out_pm_put: gb_pm_runtime_put_autosuspend(bundle); out_unlock: mutex_unlock(&channel->lock); return ret; }
static int gb_lights_flash_fault_get(struct led_classdev_flash *fcdev, u32 *fault) { struct gb_channel *channel = container_of(fcdev, struct gb_channel, fled); struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_get_flash_fault_request req; struct gb_lights_get_flash_fault_response resp; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_GET_FLASH_FAULT, &req, sizeof(req), &resp, sizeof(resp)); if (!ret) *fault = le32_to_cpu(resp.fault); gb_pm_runtime_put_autosuspend(bundle); return ret; }
static int gb_lights_flash_timeout_set(struct led_classdev_flash *fcdev, u32 timeout) { struct gb_channel *channel = container_of(fcdev, struct gb_channel, fled); struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_flash_timeout_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.timeout_us = cpu_to_le32(timeout); ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_TIMEOUT, &req, sizeof(req), NULL, 0); if (!ret) fcdev->timeout.val = timeout; gb_pm_runtime_put_autosuspend(bundle); return ret; }
static int gb_lights_flash_strobe_set(struct led_classdev_flash *fcdev, bool state) { struct gb_channel *channel = container_of(fcdev, struct gb_channel, fled); struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_flash_strobe_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.state = state ? 1 : 0; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_STROBE, &req, sizeof(req), NULL, 0); if (!ret) channel->strobe_state = state; gb_pm_runtime_put_autosuspend(bundle); return ret; }
static int gb_lights_fade_set(struct gb_channel *channel) { struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_fade_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.fade_in = channel->fade_in; req.fade_out = channel->fade_out; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FADE, &req, sizeof(req), NULL, 0); gb_pm_runtime_put_autosuspend(bundle); return ret; }
static int __gb_lights_flash_intensity_set(struct gb_channel *channel, u32 intensity) { struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_flash_intensity_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.intensity_uA = cpu_to_le32(intensity); ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_FLASH_INTENSITY, &req, sizeof(req), NULL, 0); gb_pm_runtime_put_autosuspend(bundle); return ret; }
static int __gb_lights_led_brightness_set(struct gb_channel *channel) { struct gb_lights_set_brightness_request req; struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; bool old_active; int ret; mutex_lock(&channel->lock); ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) goto out_unlock; old_active = channel->active; req.light_id = channel->light->id; req.channel_id = channel->id; req.brightness = (u8)channel->led->brightness; ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_BRIGHTNESS, &req, sizeof(req), NULL, 0); if (ret < 0) goto out_pm_put; if (channel->led->brightness) channel->active = true; else channel->active = false; /* we need to keep module alive when turning to active state */ if (!old_active && channel->active) goto out_unlock; /* * on the other hand if going to inactive we still hold a reference and * need to put it, so we could go to suspend. */ if (old_active && !channel->active) gb_pm_runtime_put_autosuspend(bundle); out_pm_put: gb_pm_runtime_put_autosuspend(bundle); out_unlock: mutex_unlock(&channel->lock); return ret; }
static int turn_off(struct gb_vibrator_device *vib) { struct gb_bundle *bundle = vib->connection->bundle; int ret; ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_OFF, NULL, 0, NULL, 0); gb_pm_runtime_put_autosuspend(bundle); return ret; }
static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms) { struct gb_bundle *bundle = vib->connection->bundle; int ret; ret = gb_pm_runtime_get_sync(bundle); if (ret) return ret; /* Vibrator was switched ON earlier */ if (cancel_delayed_work_sync(&vib->delayed_work)) turn_off(vib); ret = gb_operation_sync(vib->connection, GB_VIBRATOR_TYPE_ON, NULL, 0, NULL, 0); if (ret) { gb_pm_runtime_put_autosuspend(bundle); return ret; } schedule_delayed_work(&vib->delayed_work, msecs_to_jiffies(timeout_ms)); return 0; }
static int gb_lights_color_set(struct gb_channel *channel, u32 color) { struct gb_connection *connection = get_conn_from_channel(channel); struct gb_bundle *bundle = connection->bundle; struct gb_lights_set_color_request req; int ret; if (channel->releasing) return -ESHUTDOWN; ret = gb_pm_runtime_get_sync(bundle); if (ret < 0) return ret; req.light_id = channel->light->id; req.channel_id = channel->id; req.color = cpu_to_le32(color); ret = gb_operation_sync(connection, GB_LIGHTS_TYPE_SET_COLOR, &req, sizeof(req), NULL, 0); gb_pm_runtime_put_autosuspend(bundle); return ret; }
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_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; }