From patchwork Wed Feb 18 16:20:41 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacek Anaszewski X-Patchwork-Id: 5845271 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 5A2069F373 for ; Wed, 18 Feb 2015 16:26:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1BA5220225 for ; Wed, 18 Feb 2015 16:26:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CF49320253 for ; Wed, 18 Feb 2015 16:26:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752634AbbBRQ0u (ORCPT ); Wed, 18 Feb 2015 11:26:50 -0500 Received: from mailout3.samsung.com ([203.254.224.33]:58891 "EHLO mailout3.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752295AbbBRQ0t (ORCPT ); Wed, 18 Feb 2015 11:26:49 -0500 Received: from epcpsbgm2.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0NJZ004IH70NW450@mailout3.samsung.com>; Thu, 19 Feb 2015 01:26:47 +0900 (KST) X-AuditID: cbfee61b-f79d76d0000024d6-42-54e4bd47cf01 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 61.34.09430.74DB4E45; Thu, 19 Feb 2015 01:26:47 +0900 (KST) Received: from AMDC2362.DIGITAL.local ([106.120.53.23]) by mmp1.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0NJZ003WS6QJDJ20@mmp1.samsung.com>; Thu, 19 Feb 2015 01:26:47 +0900 (KST) From: Jacek Anaszewski To: linux-leds@vger.kernel.org, linux-media@vger.kernel.org, devicetree@vger.kernel.org Cc: kyungmin.park@samsung.com, pavel@ucw.cz, cooloney@gmail.com, rpurdie@rpsys.net, sakari.ailus@iki.fi, s.nawrocki@samsung.com, Jacek Anaszewski , Sakari Ailus Subject: [PATCH/RFC v11 20/20] leds: aat1290: add support for V4L2 Flash sub-device Date: Wed, 18 Feb 2015 17:20:41 +0100 Message-id: <1424276441-3969-21-git-send-email-j.anaszewski@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1424276441-3969-1-git-send-email-j.anaszewski@samsung.com> References: <1424276441-3969-1-git-send-email-j.anaszewski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrHLMWRmVeSWpSXmKPExsVy+t9jAV33vU9CDDbvlbA4unMik8X8I+dY LXqvPme0ONv0ht1i65t1jBY9G7ayWtw9dZTNYveup6wWh9+0s1qc2b+SzeLTlm9MDtweO2fd Zfc4/HUhi8e8k4Eee+b/YPXo27KK0WPF6u/sHp83yQWwR3HZpKTmZJalFunbJXBlPJzWyV4w wbaiaaphA+Nzoy5GTg4JAROJz4tvsUHYYhIX7q0Hsrk4hAQWMUp8njaRFcJpZ5KY+XQ5M0gV m4ChxM8Xr5lAbBGBSIl3Ry8xgxQxC9xnlFj1aAkrSEJYIFRiyaRzQDYHB4uAqsTFu9ogYV4B D4kb748wg4QlBBQk5kyyATE5gcIXnnuAVAgJuEtMv/mOdQIj7wJGhlWMoqkFyQXFSem5RnrF ibnFpXnpesn5uZsYwaH4THoH46oGi0OMAhyMSjy8Db8fhwixJpYVV+YeYpTgYFYS4c1d+SRE iDclsbIqtSg/vqg0J7X4EKM0B4uSOK+SfVuIkEB6YklqdmpqQWoRTJaJg1OqgdFs/r0nLk8l tNzadTQXNC3smJGxfe/uu3fzHBgvbZQ+ImrqM+95Y0K3jb+RgFjQRvlg2a6izLlfvG78ilsd 1B1tKs4r+PJkdpXIFoO5YYsuPPh8d8eMmfoxSosci+srrt3fH/+oKWQG94e6iPULNc6Y3zTM anPzlZm474E9o6mw7YugC48vvFViKc5INNRiLipOBAC8pqPLQQIAAA== Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for V4L2 Flash sub-device to the aat1290 LED Flash class driver. The support allows for V4L2 Flash sub-device to take the control of the LED Flash class device. Signed-off-by: Jacek Anaszewski Acked-by: Kyungmin Park Cc: Bryan Wu Cc: Richard Purdie Cc: Sakari Ailus --- drivers/leds/leds-aat1290.c | 163 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c index b217f0a..0e32be7 100644 --- a/drivers/leds/leds-aat1290.c +++ b/drivers/leds/leds-aat1290.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #define AAT1290_MOVIE_MODE_CURRENT_ADDR 17 @@ -46,6 +47,9 @@ #define AAT1290_MM_CURRENT_SCALE_SIZE 15 struct aat1290_led_settings { +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) + struct led_flash_setting torch_brightness; +#endif struct led_flash_setting flash_timeout; }; @@ -57,11 +61,19 @@ struct aat1290_led { /* related LED Flash class device */ struct led_classdev_flash fled_cdev; + /* V4L2 Flash device */ + struct v4l2_flash *v4l2_flash; /* FLEN pin */ int flen_gpio; /* EN|SET pin */ int en_set_gpio; +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) + /* chooses flash strobe source - external or SoC gpio */ + int ext_strobe_gpio; + /* movie mode current scale */ + int *mm_current_scale; +#endif /* maximum flash timeout */ u32 max_flash_tm; @@ -279,6 +291,15 @@ static void aat1290_init_flash_settings(struct aat1290_led *led, { struct led_flash_setting *setting; +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) + /* Init flash intensity setting */ + setting = &s->torch_brightness; + setting->min = led->mm_current_scale[0]; + setting->max = led->mm_current_scale[AAT1290_MM_CURRENT_SCALE_SIZE - 1]; + setting->step = 1; + setting->val = setting->max; +#endif + /* Init flash timeout setting */ setting = &s->flash_timeout; setting->min = led->max_flash_tm / AAT1290_FLASH_TM_NUM_LEVELS; @@ -287,6 +308,97 @@ static void aat1290_init_flash_settings(struct aat1290_led *led, setting->val = setting->max; } +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) +enum led_brightness aat1290_intensity_to_brightness( + struct v4l2_flash *v4l2_flash, + s32 intensity) +{ + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; + struct aat1290_led *led = fled_cdev_to_led(fled_cdev); + int i; + + for (i = AAT1290_MM_CURRENT_SCALE_SIZE - 1; i >= 0; --i) + if (intensity >= led->mm_current_scale[i]) + return i + 1; + + return 1; +} + +s32 aat1290_brightness_to_intensity(struct v4l2_flash *v4l2_flash, + enum led_brightness brightness) +{ + struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; + struct aat1290_led *led = fled_cdev_to_led(fled_cdev); + + return led->mm_current_scale[brightness - 1]; +} + +static int aat1290_led_external_strobe_set(struct v4l2_flash *v4l2_flash, + bool enable) +{ + struct aat1290_led *led = fled_cdev_to_led(v4l2_flash->fled_cdev); + + led->movie_mode = false; + gpio_set_value(led->flen_gpio, 0); + gpio_set_value(led->en_set_gpio, 0); + gpio_set_value(led->ext_strobe_gpio, enable); + + return 0; +} + +int init_mm_current_scale(struct aat1290_led *led) +{ + int max_mm_current_percent[] = { 20, 22, 25, 28, 32, 36, 40, 45, 50, 56, + 63, 71, 79, 89, 100 }; + int i, max_mm_current = AAT1290_MAX_MM_CURRENT(led->max_flash_current); + + led->mm_current_scale = devm_kzalloc(&led->pdev->dev, + sizeof(max_mm_current_percent), + GFP_KERNEL); + if (!led->mm_current_scale) + return -ENOMEM; + + for (i = 0; i < AAT1290_MM_CURRENT_SCALE_SIZE; ++i) + led->mm_current_scale[i] = max_mm_current * + max_mm_current_percent[i] / 100; + + return 0; +} + +static void aat1290_init_v4l2_ctrl_config(struct aat1290_led *led, + struct aat1290_led_settings *s, + struct v4l2_flash_ctrl_config *config) +{ + struct led_flash_setting *setting; + struct v4l2_ctrl_config *c; + + c = &config->intensity; + setting = &s->torch_brightness; + c->min = setting->min; + c->max = setting->max; + c->step = setting->step; + c->def = setting->val; + + c = &config->flash_timeout; + setting = &s->flash_timeout; + c->min = setting->min; + c->max = setting->max; + c->step = setting->step; + c->def = setting->val; + + config->has_external_strobe = gpio_is_valid(led->ext_strobe_gpio); +} + +static const struct v4l2_flash_ops v4l2_flash_ops = { + .external_strobe_set = aat1290_led_external_strobe_set, + .intensity_to_led_brightness = aat1290_intensity_to_brightness, + .led_brightness_to_intensity = aat1290_brightness_to_intensity, +}; +#else +#define aat1290_init_v4l2_ctrl_config(led, s, config) +#define init_mm_current_scale(led) (0) +#endif + static const struct led_flash_ops flash_ops = { .strobe_set = aat1290_led_flash_strobe_set, .timeout_set = aat1290_led_flash_timeout_set, @@ -299,6 +411,10 @@ static int aat1290_led_probe(struct platform_device *pdev) struct aat1290_led *led; struct led_classdev *led_cdev; struct led_classdev_flash *fled_cdev; +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) + struct v4l2_flash_ctrl_config v4l2_flash_config; + int ext_strobe_gpio; +#endif struct aat1290_led_settings settings; int flen_gpio, enset_gpio, ret; @@ -342,6 +458,21 @@ static int aat1290_led_probe(struct platform_device *pdev) } led->en_set_gpio = enset_gpio; +#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS) + ext_strobe_gpio = of_get_gpio(dev_node, 2); + if (gpio_is_valid(ext_strobe_gpio)) { + ret = devm_gpio_request_one(dev, ext_strobe_gpio, GPIOF_DIR_OUT, + "aat1290_en_hw_strobe"); + if (ret < 0) { + dev_err(dev, + "failed to request GPIO %d, error %d\n", + ext_strobe_gpio, ret); + return ret; + } + } + led->ext_strobe_gpio = ext_strobe_gpio; +#endif + fled_cdev = &led->fled_cdev; led_cdev = &fled_cdev->led_cdev; @@ -349,9 +480,20 @@ static int aat1290_led_probe(struct platform_device *pdev) if (ret < 0) return ret; + /* + * Initialize non-linear movie mode current scale basing + * on the max flash current from Device Tree binding. + */ + ret = init_mm_current_scale(led); + if (ret < 0) + return ret; + /* Init flash settings */ aat1290_init_flash_settings(led, &settings); + /* Init V4L2 Flash controls basing on initialized settings */ + aat1290_init_v4l2_ctrl_config(led, &settings, &v4l2_flash_config); + fled_cdev->timeout = settings.flash_timeout; fled_cdev->ops = &flash_ops; @@ -370,13 +512,34 @@ static int aat1290_led_probe(struct platform_device *pdev) mutex_init(&led->lock); + of_node_get(dev_node); + led_cdev->dev->of_node = dev_node; + + /* Create V4L2 Flash subdev. */ + led->v4l2_flash = v4l2_flash_init(fled_cdev, + &v4l2_flash_ops, + &v4l2_flash_config); + if (IS_ERR(led->v4l2_flash)) { + ret = PTR_ERR(led->v4l2_flash); + goto error_v4l2_flash_init; + } + return 0; + +error_v4l2_flash_init: + of_node_put(dev_node); + led_classdev_flash_unregister(fled_cdev); + mutex_destroy(&led->lock); + + return ret; } static int aat1290_led_remove(struct platform_device *pdev) { struct aat1290_led *led = platform_get_drvdata(pdev); + v4l2_flash_release(led->v4l2_flash); + of_node_put(led->fled_cdev.led_cdev.dev->of_node); led_classdev_flash_unregister(&led->fled_cdev); cancel_work_sync(&led->work_brightness_set);