From patchwork Mon Jan 21 21:56:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Murphy X-Patchwork-Id: 156258 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp6848734jaa; Mon, 21 Jan 2019 13:57:11 -0800 (PST) X-Google-Smtp-Source: ALg8bN7HGWztzJOldrpNLC3hqbXaB8cRBCyAyg+FSb3WHjqd0CskFHT6uUlKUgY7KxkjR9lWSmHC X-Received: by 2002:a63:f444:: with SMTP id p4mr29385664pgk.124.1548107830972; Mon, 21 Jan 2019 13:57:10 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1548107830; cv=none; d=google.com; s=arc-20160816; b=I2dsnfLlSJLUK6ztXlRSYDQAupdkXd6PLR75J0ZtUN8TkqZI1MMLadqR1RfGRKyWbj XGbf9KYxEf3A2vSofro737uCi1s+v/9R9eb86M2apAgNBU8i7JrgieMW7HLgazRMvwVm FxOfTG0TrLfPsA9P1eyvHnLqxxdYruaQuwm7iJ5iDYVGe/BxtyfJe3KSqHojdVmGpOKV PNF+jcvaeRAqunwZTTeMoh4JSpviGXxzF0RlOTmz1UYlNJplVK2qKzTAxWiGJTrOsH4u hkfc0pmKsvx2CXoxgdCP6ulIT2Tlv+0imoiLvrG6i4I2cj2cpGKHVRzbcqDw4gbXCUXr GEFw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=57Dj8gV87Uw0bDKGkiBqskXLqAer7ww/13u0RdYkBzA=; b=UuMwhzv7gfj/FFVAooNsq+RWYmgzY1C3hGgt8fgfHdXgVWpcCaDRtVUSkgbyv3f0BU Jbd8xo4Uabw2DsnpYxa/s1m8iBiKpH1w9YZtIcEQnyttKaQLnQihfrD++1SsJ521mbrD ucUR3cIxpaOZqvwfEou7uVjeUqbl+PrkmQIRjHWMqjoqedYZIjyvD8NU9ou7+C83Q+Ec 8KKgc5mnVvtnySpPY9eftHRjdU7x2RFfOwVrFrAdfTU+ywRsXgszrHrpf5NTsLemuMwH Dj4tRY5QZXpHzzLYrpMsMwVMX/Fgwi/G9p9AdTAAFsE18k2Dyckbqtv4O6oRZ6j9Dt8h oJvQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=EflN7UnC; spf=pass (google.com: best guess record for domain of linux-leds-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-leds-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 9si14124932plc.40.2019.01.21.13.57.10; Mon, 21 Jan 2019 13:57:10 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-leds-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=EflN7UnC; spf=pass (google.com: best guess record for domain of linux-leds-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-leds-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725993AbfAUV5K (ORCPT + 1 other); Mon, 21 Jan 2019 16:57:10 -0500 Received: from lelv0142.ext.ti.com ([198.47.23.249]:33258 "EHLO lelv0142.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727513AbfAUV5K (ORCPT ); Mon, 21 Jan 2019 16:57:10 -0500 Received: from lelv0265.itg.ti.com ([10.180.67.224]) by lelv0142.ext.ti.com (8.15.2/8.15.2) with ESMTP id x0LLv56e020291; Mon, 21 Jan 2019 15:57:05 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1548107825; bh=57Dj8gV87Uw0bDKGkiBqskXLqAer7ww/13u0RdYkBzA=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=EflN7UnC1mtKDBN4lFRL8Xl2xlGVSaQr9+uyxvl0iyetz/tEK3NCgjm6Iys8ys2IK OH/Q0xgfEPgeePKIaPwbLn/wBSSRBa38B7AW11M0L7xIgN/oAgVyLVNSAQg2f6hz+o StbUJPW0rsNiXwlTJqXY7VYTrKBxr2pb7HQoHSTc= Received: from DLEE112.ent.ti.com (dlee112.ent.ti.com [157.170.170.23]) by lelv0265.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x0LLv54p047465 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 21 Jan 2019 15:57:05 -0600 Received: from DLEE113.ent.ti.com (157.170.170.24) by DLEE112.ent.ti.com (157.170.170.23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Mon, 21 Jan 2019 15:57:05 -0600 Received: from dflp33.itg.ti.com (10.64.6.16) by DLEE113.ent.ti.com (157.170.170.24) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Mon, 21 Jan 2019 15:57:05 -0600 Received: from legion.dal.desgin.ti.com (legion.dal.design.ti.com [128.247.22.53]) by dflp33.itg.ti.com (8.14.3/8.13.8) with ESMTP id x0LLv5f0020877; Mon, 21 Jan 2019 15:57:05 -0600 Received: from localhost (a0272616local-lt.dhcp.ti.com [172.22.78.123]) by legion.dal.desgin.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id x0LLv4U20744; Mon, 21 Jan 2019 15:57:04 -0600 (CST) From: Dan Murphy To: CC: , , , Dan Murphy Subject: [RFC PATCH 6/6] leds: cpcap: Use the RGB framework for Droid4 Date: Mon, 21 Jan 2019 15:56:59 -0600 Message-ID: <20190121215659.31125-7-dmurphy@ti.com> X-Mailer: git-send-email 2.12.2 In-Reply-To: <20190121215659.31125-1-dmurphy@ti.com> References: <20190121215659.31125-1-dmurphy@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-leds-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Signed-off-by: Dan Murphy --- drivers/leds/leds-cpcap.c | 291 +++++++++++++++++++++++++++++++++-- drivers/mfd/motorola-cpcap.c | 8 +- 2 files changed, 288 insertions(+), 11 deletions(-) -- 2.20.1.98.gecbdaf0899 diff --git a/drivers/leds/leds-cpcap.c b/drivers/leds/leds-cpcap.c index f0f28c442807..4088a52de26b 100644 --- a/drivers/leds/leds-cpcap.c +++ b/drivers/leds/leds-cpcap.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -28,6 +29,10 @@ struct cpcap_led_info { u16 limit; u16 init_mask; u16 init_val; + u16 rgb_combo; + u16 red_reg; + u16 green_reg; + u16 blue_reg; }; static const struct cpcap_led_info cpcap_led_red = { @@ -48,6 +53,15 @@ static const struct cpcap_led_info cpcap_led_blue = { .limit = 31, }; +static const struct cpcap_led_info cpcap_led_rgb = { + .red_reg = CPCAP_REG_REDC, + .green_reg = CPCAP_REG_GREENC, + .blue_reg = CPCAP_REG_BLUEC, + .rgb_combo = 0x1, + .mask = 0x03FF, + .limit = 31, +}; + /* aux display light */ static const struct cpcap_led_info cpcap_led_adl = { .reg = CPCAP_REG_ADLC, @@ -68,6 +82,7 @@ static const struct cpcap_led_info cpcap_led_cp = { struct cpcap_led { struct led_classdev led; + struct led_classdev_rgb rgb_cdev; const struct cpcap_led_info *info; struct device *dev; struct regmap *regmap; @@ -116,6 +131,11 @@ static int cpcap_led_set(struct led_classdev *ledc, enum led_brightness value) mutex_lock(&led->update_lock); + if (led->info->rgb_combo) { + err = 0; + goto exit; + } + if (value > LED_OFF) { err = cpcap_led_set_power(led, true); if (err) @@ -154,10 +174,232 @@ static int cpcap_led_set(struct led_classdev *ledc, enum led_brightness value) return err; } +static struct cpcap_led *rgbled_cdev_to_led(struct led_classdev_rgb *rgbled_cdev) +{ + return container_of(rgbled_cdev, struct cpcap_led, rgb_cdev); +} + +static int cpcap_led_set_red(struct led_classdev_rgb *rgbled_cdev, + enum led_brightness value) +{ + struct cpcap_led *led = rgbled_cdev_to_led(rgbled_cdev); + int brightness; + int err; + + mutex_lock(&led->update_lock); + + if (value > LED_OFF) { + err = cpcap_led_set_power(led, true); + if (err) + goto exit; + } + + if (value == LED_OFF) { + /* Avoid HW issue by turning off current before duty cycle */ + err = regmap_update_bits(led->regmap, + led->info->red_reg, led->info->mask, CPCAP_LED_NO_CURRENT); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + brightness = cpcap_led_val(value, LED_OFF); + } else { + brightness = cpcap_led_val(value, LED_ON); + } + + err = regmap_update_bits(led->regmap, led->info->red_reg, led->info->mask, + brightness); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + if (value == LED_OFF) + err = cpcap_led_set_power(led, false); + +exit: + mutex_unlock(&led->update_lock); + return err; +} + +static int cpcap_led_set_green(struct led_classdev_rgb *rgbled_cdev, + enum led_brightness value) +{ + struct cpcap_led *led = rgbled_cdev_to_led(rgbled_cdev); + int brightness; + int err; + + mutex_lock(&led->update_lock); + + if (value > LED_OFF) { + err = cpcap_led_set_power(led, true); + if (err) + goto exit; + } + + if (value == LED_OFF) { + /* Avoid HW issue by turning off current before duty cycle */ + err = regmap_update_bits(led->regmap, + led->info->green_reg, led->info->mask, CPCAP_LED_NO_CURRENT); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + brightness = cpcap_led_val(value, LED_OFF); + } else { + brightness = cpcap_led_val(value, LED_ON); + } + + err = regmap_update_bits(led->regmap, led->info->green_reg, led->info->mask, + brightness); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + if (value == LED_OFF) + err = cpcap_led_set_power(led, false); +exit: + mutex_unlock(&led->update_lock); + return err; +} + +static int cpcap_led_set_blue(struct led_classdev_rgb *rgbled_cdev, + enum led_brightness value) +{ + struct cpcap_led *led = rgbled_cdev_to_led(rgbled_cdev); + int brightness; + int err; + + mutex_lock(&led->update_lock); + + if (value > LED_OFF) { + err = cpcap_led_set_power(led, true); + if (err) + goto exit; + } + + if (value == LED_OFF) { + /* Avoid HW issue by turning off current before duty cycle */ + err = regmap_update_bits(led->regmap, + led->info->blue_reg, led->info->mask, CPCAP_LED_NO_CURRENT); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + brightness = cpcap_led_val(value, LED_OFF); + } else { + brightness = cpcap_led_val(value, LED_ON); + } + + err = regmap_update_bits(led->regmap, led->info->blue_reg, led->info->mask, + brightness); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + if (value == LED_OFF) + err = cpcap_led_set_power(led, false); + +exit: + mutex_unlock(&led->update_lock); + return err; +} +static int cpcap_led_set_color(struct led_classdev_rgb *rgbled_cdev) +{ + struct led_rgb_colors *colors = &rgbled_cdev->rgb_colors; + struct cpcap_led *led = rgbled_cdev_to_led(rgbled_cdev); + int red_brightness, green_brightness, blue_brightness; + int err; + + mutex_lock(&led->update_lock); + + if (colors->red > LED_OFF || colors->green > LED_OFF || + colors->blue > LED_OFF) { + err = cpcap_led_set_power(led, true); + if (err) + goto exit; + } + + if (colors->red == LED_OFF && colors->green == LED_OFF && + colors->blue == LED_OFF) { + /* Avoid HW issue by turning off current before duty cycle */ + err = regmap_update_bits(led->regmap, + led->info->red_reg, led->info->mask, CPCAP_LED_NO_CURRENT); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + err = regmap_update_bits(led->regmap, + led->info->green_reg, led->info->mask, CPCAP_LED_NO_CURRENT); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + err = regmap_update_bits(led->regmap, + led->info->blue_reg, led->info->mask, CPCAP_LED_NO_CURRENT); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + red_brightness = cpcap_led_val(colors->red, LED_OFF); + green_brightness = cpcap_led_val(colors->green, LED_OFF); + blue_brightness = cpcap_led_val(colors->blue, LED_OFF); + } else { + red_brightness = cpcap_led_val(colors->red, LED_ON); + green_brightness = cpcap_led_val(colors->green, LED_ON); + blue_brightness = cpcap_led_val(colors->blue, LED_ON); + } + + err = regmap_update_bits(led->regmap, led->info->red_reg, led->info->mask, + red_brightness); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + err = regmap_update_bits(led->regmap, led->info->green_reg, led->info->mask, + green_brightness); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + err = regmap_update_bits(led->regmap, led->info->blue_reg, led->info->mask, + blue_brightness); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + goto exit; + } + + if (colors->red == LED_OFF && colors->green == LED_OFF && + colors->blue == LED_OFF) + err = cpcap_led_set_power(led, false); + +exit: + mutex_unlock(&led->update_lock); + return err; +} + +static struct led_rgb_ops cpcap_led_rgb_ops = { + .set_color = cpcap_led_set_color, + .set_red_brightness = cpcap_led_set_red, + .set_green_brightness = cpcap_led_set_green, + .set_blue_brightness = cpcap_led_set_blue, +}; + static const struct of_device_id cpcap_led_of_match[] = { { .compatible = "motorola,cpcap-led-red", .data = &cpcap_led_red }, { .compatible = "motorola,cpcap-led-green", .data = &cpcap_led_green }, { .compatible = "motorola,cpcap-led-blue", .data = &cpcap_led_blue }, + { .compatible = "motorola,cpcap-led-rgb", .data = &cpcap_led_rgb }, { .compatible = "motorola,cpcap-led-adl", .data = &cpcap_led_adl }, { .compatible = "motorola,cpcap-led-cp", .data = &cpcap_led_cp }, {}, @@ -167,6 +409,7 @@ MODULE_DEVICE_TABLE(of, cpcap_led_of_match); static int cpcap_led_probe(struct platform_device *pdev) { const struct of_device_id *match; + struct led_classdev *led_cdev; struct cpcap_led *led; int err; @@ -181,7 +424,7 @@ static int cpcap_led_probe(struct platform_device *pdev) led->info = match->data; led->dev = &pdev->dev; - if (led->info->reg == 0x0000) { + if (!led->info->rgb_combo && led->info->reg == 0x0000) { dev_err(led->dev, "Unsupported LED"); return -ENODEV; } @@ -204,19 +447,49 @@ static int cpcap_led_probe(struct platform_device *pdev) } if (led->info->init_mask) { - err = regmap_update_bits(led->regmap, led->info->reg, - led->info->init_mask, led->info->init_val); - if (err) { - dev_err(led->dev, "regmap failed: %d", err); - return err; + if (led->info->rgb_combo) { + err = regmap_update_bits(led->regmap, led->info->red_reg, + led->info->init_mask, led->info->init_val); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + return err; + } + err = regmap_update_bits(led->regmap, led->info->green_reg, + led->info->init_mask, led->info->init_val); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + return err; + } + err = regmap_update_bits(led->regmap, led->info->blue_reg, + led->info->init_mask, led->info->init_val); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + return err; + } + } else { + err = regmap_update_bits(led->regmap, led->info->reg, + led->info->init_mask, led->info->init_val); + if (err) { + dev_err(led->dev, "regmap failed: %d", err); + return err; + } } } mutex_init(&led->update_lock); - led->led.max_brightness = led->info->limit; - led->led.brightness_set_blocking = cpcap_led_set; - err = devm_led_classdev_register(&pdev->dev, &led->led); + if (!led->info->rgb_combo) { + led->led.max_brightness = led->info->limit; + led->led.brightness_set_blocking = cpcap_led_set; + err = devm_led_classdev_register(&pdev->dev, &led->led); + } else { + led->rgb_cdev.ops = &cpcap_led_rgb_ops; + led_cdev = &led->rgb_cdev.led_cdev; + led_cdev->name = led->led.name; + led_cdev->brightness_set_blocking = cpcap_led_set; + err = led_classdev_rgb_register(&pdev->dev, &led->rgb_cdev); + } + if (err) { dev_err(led->dev, "Couldn't register LED: %d", err); return err; diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c index 20d9692640e1..beb7063559bb 100644 --- a/drivers/mfd/motorola-cpcap.c +++ b/drivers/mfd/motorola-cpcap.c @@ -253,11 +253,15 @@ static const struct mfd_cell cpcap_mfd_devices[] = { .of_compatible = "motorola,cpcap-led-blue", }, { .name = "cpcap-led", - .id = 3, + .id = 4, + .of_compatible = "motorola,cpcap-led-rgb", + }, { + .name = "cpcap-led", + .id = 5, .of_compatible = "motorola,cpcap-led-adl", }, { .name = "cpcap-led", - .id = 4, + .id = 6, .of_compatible = "motorola,cpcap-led-cp", }, { .name = "cpcap-codec",