Updates for 5.12-rc1. Besides usual fixes and new drivers, we are
changing CLASS_FLASH to return success to make it easier to work with V4L2 stuff disabled, and we are getting rid of enum that should have been plain integer long time ago. I'm slightly nervous about potential warnings, but it needed to be fixed at some point. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iEYEABECAAYFAmA2ETMACgkQMOfwapXb+vI0MQCgrQMf02DV2hvyJm2Oj4Vx6WKd 5VYAn0J/8OKSj4BHiW82s4H4tuP8e1TD =GYC4 -----END PGP SIGNATURE----- Merge tag 'leds-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds Pull LED updates from Pavel Machek: "Besides the usual fixes and new drivers, we are changing CLASS_FLASH to return success to make it easier to work with V4L2 stuff disabled, and we are getting rid of enum that should have been plain integer long time ago. I'm slightly nervous about potential warnings, but it needed to be fixed at some point" * tag 'leds-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pavel/linux-leds: leds: lp50xx: Get rid of redundant explicit casting leds: lp50xx: Update headers block to reflect reality leds: lp50xx: Get rid of redundant check in lp50xx_enable_disable() leds: lp50xx: Reduce level of dereferences leds: lp50xx: Switch to new style i2c-driver probe function leds: lp50xx: Don't spam logs when probe is deferred leds: apu: extend support for PC Engines APU1 with newer firmware leds: flash: Fix multicolor no-ops registration by return 0 leds: flash: Add flash registration with undefined CONFIG_LEDS_CLASS_FLASH leds: lgm: Add LED controller driver for LGM SoC dt-bindings: leds: Add bindings for Intel LGM SoC leds: led-core: Get rid of enum led_brightness leds: gpio: Set max brightness to 1 leds: lm3533: Switch to using the new API kobj_to_dev() leds: ss4200: simplify the return expression of register_nasgpio_led() leds: Use DEVICE_ATTR_{RW, RO, WO} macros
This commit is contained in:
Коммит
fecfd01539
|
@ -0,0 +1,113 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/leds/leds-lgm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Intel Lightning Mountain (LGM) SoC LED Serial Shift Output (SSO) Controller driver
|
||||
|
||||
maintainers:
|
||||
- Zhu, Yi Xin <Yixin.zhu@intel.com>
|
||||
- Amireddy Mallikarjuna reddy <mallikarjunax.reddy@intel.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: intel,lgm-ssoled
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
'#gpio-cells':
|
||||
const: 2
|
||||
|
||||
ngpios:
|
||||
minimum: 0
|
||||
maximum: 32
|
||||
description:
|
||||
Number of GPIOs this controller provides.
|
||||
|
||||
intel,sso-update-rate-hz:
|
||||
description:
|
||||
Blink frequency for SOUTs in Hz.
|
||||
|
||||
led-controller:
|
||||
type: object
|
||||
description:
|
||||
This sub-node must contain a sub-node for each leds.
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^led@[0-23]$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: Index of the LED.
|
||||
minimum: 0
|
||||
maximum: 2
|
||||
|
||||
intel,sso-hw-trigger:
|
||||
type: boolean
|
||||
description: This property indicates Hardware driven/control LED.
|
||||
|
||||
intel,sso-hw-blink:
|
||||
type: boolean
|
||||
description: This property indicates Enable LED blink by Hardware.
|
||||
|
||||
intel,sso-blink-rate-hz:
|
||||
description: LED HW blink frequency.
|
||||
|
||||
retain-state-suspended:
|
||||
type: boolean
|
||||
description: The suspend state of LED can be retained.
|
||||
|
||||
retain-state-shutdown:
|
||||
type: boolean
|
||||
description: Retain the state of the LED on shutdown.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#gpio-cells"
|
||||
- gpio-controller
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/intel,lgm-clk.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
ssogpio: ssogpio@e0d40000 {
|
||||
compatible = "intel,sso-led";
|
||||
reg = <0xE0D40000 0x2E4>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
ngpios = <32>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ledc>;
|
||||
clocks = <&cgu0 LGM_GCLK_LEDC0>, <&afeclk>;
|
||||
clock-names = "sso", "fpid";
|
||||
intel,sso-update-rate-hz = <250000>;
|
||||
|
||||
led-controller {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led@0 {
|
||||
reg = <0>;
|
||||
function = "gphy";
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
led-gpio = <&ssogpio 0 0>;
|
||||
};
|
||||
|
||||
led@23 {
|
||||
reg = <23>;
|
||||
function = LED_FUNCTION_POWER;
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
led-gpio = <&ssogpio 23 0>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -934,4 +934,7 @@ source "drivers/leds/flash/Kconfig"
|
|||
comment "LED Triggers"
|
||||
source "drivers/leds/trigger/Kconfig"
|
||||
|
||||
comment "LED Blink"
|
||||
source "drivers/leds/blink/Kconfig"
|
||||
|
||||
endif # NEW_LEDS
|
||||
|
|
|
@ -108,3 +108,6 @@ obj-$(CONFIG_LEDS_CLASS_FLASH) += flash/
|
|||
|
||||
# LED Triggers
|
||||
obj-$(CONFIG_LEDS_TRIGGERS) += trigger/
|
||||
|
||||
# LED Blink
|
||||
obj-$(CONFIG_LEDS_BLINK) += blink/
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
menuconfig LEDS_BLINK
|
||||
bool "LED Blink support"
|
||||
depends on LEDS_CLASS
|
||||
help
|
||||
This option enables blink support for the leds class.
|
||||
If unsure, say Y.
|
||||
|
||||
if LEDS_BLINK
|
||||
|
||||
config LEDS_BLINK_LGM
|
||||
tristate "LED support for Intel LGM SoC series"
|
||||
depends on LEDS_CLASS
|
||||
depends on MFD_SYSCON
|
||||
depends on OF
|
||||
help
|
||||
Parallel to serial conversion, which is also called SSO controller,
|
||||
can drive external shift register for LED outputs.
|
||||
This enables LED support for Serial Shift Output controller(SSO).
|
||||
|
||||
endif # LEDS_BLINK
|
|
@ -0,0 +1,2 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_LEDS_BLINK_LGM) += leds-lgm-sso.o
|
|
@ -0,0 +1,888 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Intel Lightning Mountain SoC LED Serial Shift Output Controller driver
|
||||
*
|
||||
* Copyright (c) 2020 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define SSO_DEV_NAME "lgm-sso"
|
||||
|
||||
#define LED_BLINK_H8_0 0x0
|
||||
#define LED_BLINK_H8_1 0x4
|
||||
#define GET_FREQ_OFFSET(pin, src) (((pin) * 6) + ((src) * 2))
|
||||
#define GET_SRC_OFFSET(pinc) (((pin) * 6) + 4)
|
||||
|
||||
#define DUTY_CYCLE(x) (0x8 + ((x) * 4))
|
||||
#define SSO_CON0 0x2B0
|
||||
#define SSO_CON0_RZFL BIT(26)
|
||||
#define SSO_CON0_BLINK_R BIT(30)
|
||||
#define SSO_CON0_SWU BIT(31)
|
||||
|
||||
#define SSO_CON1 0x2B4
|
||||
#define SSO_CON1_FCDSC GENMASK(21, 20) /* Fixed Divider Shift Clock */
|
||||
#define SSO_CON1_FPID GENMASK(24, 23)
|
||||
#define SSO_CON1_GPTD GENMASK(26, 25)
|
||||
#define SSO_CON1_US GENMASK(31, 30)
|
||||
|
||||
#define SSO_CPU 0x2B8
|
||||
#define SSO_CON2 0x2C4
|
||||
#define SSO_CON3 0x2C8
|
||||
|
||||
/* Driver MACRO */
|
||||
#define MAX_PIN_NUM_PER_BANK SZ_32
|
||||
#define MAX_GROUP_NUM SZ_4
|
||||
#define PINS_PER_GROUP SZ_8
|
||||
#define FPID_FREQ_RANK_MAX SZ_4
|
||||
#define SSO_LED_MAX_NUM SZ_32
|
||||
#define MAX_FREQ_RANK 10
|
||||
#define DEF_GPTC_CLK_RATE 200000000
|
||||
#define SSO_DEF_BRIGHTNESS LED_HALF
|
||||
#define DATA_CLK_EDGE 0 /* 0-rising, 1-falling */
|
||||
|
||||
static const u32 freq_div_tbl[] = {4000, 2000, 1000, 800};
|
||||
static const int freq_tbl[] = {2, 4, 8, 10, 50000, 100000, 200000, 250000};
|
||||
static const int shift_clk_freq_tbl[] = {25000000, 12500000, 6250000, 3125000};
|
||||
|
||||
/*
|
||||
* Update Source to update the SOUTs
|
||||
* SW - Software has to update the SWU bit
|
||||
* GPTC - General Purpose timer is used as clock source
|
||||
* FPID - Divided FSC clock (FPID) is used as clock source
|
||||
*/
|
||||
enum {
|
||||
US_SW = 0,
|
||||
US_GPTC = 1,
|
||||
US_FPID = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
MAX_FPID_FREQ_RANK = 5, /* 1 to 4 */
|
||||
MAX_GPTC_FREQ_RANK = 9, /* 5 to 8 */
|
||||
MAX_GPTC_HS_FREQ_RANK = 10, /* 9 to 10 */
|
||||
};
|
||||
|
||||
enum {
|
||||
LED_GRP0_PIN_MAX = 24,
|
||||
LED_GRP1_PIN_MAX = 29,
|
||||
LED_GRP2_PIN_MAX = 32,
|
||||
};
|
||||
|
||||
enum {
|
||||
LED_GRP0_0_23,
|
||||
LED_GRP1_24_28,
|
||||
LED_GRP2_29_31,
|
||||
LED_GROUP_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
CLK_SRC_FPID = 0,
|
||||
CLK_SRC_GPTC = 1,
|
||||
CLK_SRC_GPTC_HS = 2,
|
||||
};
|
||||
|
||||
struct sso_led_priv;
|
||||
|
||||
struct sso_led_desc {
|
||||
const char *name;
|
||||
const char *default_trigger;
|
||||
unsigned int brightness;
|
||||
unsigned int blink_rate;
|
||||
unsigned int retain_state_suspended:1;
|
||||
unsigned int retain_state_shutdown:1;
|
||||
unsigned int panic_indicator:1;
|
||||
unsigned int hw_blink:1;
|
||||
unsigned int hw_trig:1;
|
||||
unsigned int blinking:1;
|
||||
int freq_idx;
|
||||
u32 pin;
|
||||
};
|
||||
|
||||
struct sso_led {
|
||||
struct list_head list;
|
||||
struct led_classdev cdev;
|
||||
struct gpio_desc *gpiod;
|
||||
struct sso_led_desc desc;
|
||||
struct sso_led_priv *priv;
|
||||
};
|
||||
|
||||
struct sso_gpio {
|
||||
struct gpio_chip chip;
|
||||
int shift_clk_freq;
|
||||
int edge;
|
||||
int freq;
|
||||
u32 pins;
|
||||
u32 alloc_bitmap;
|
||||
};
|
||||
|
||||
struct sso_led_priv {
|
||||
struct regmap *mmap;
|
||||
struct device *dev;
|
||||
struct platform_device *pdev;
|
||||
struct clk *gclk;
|
||||
struct clk *fpid_clk;
|
||||
u32 fpid_clkrate;
|
||||
u32 gptc_clkrate;
|
||||
u32 freq[MAX_FREQ_RANK];
|
||||
struct list_head led_list;
|
||||
struct sso_gpio gpio;
|
||||
};
|
||||
|
||||
static int sso_get_blink_rate_idx(struct sso_led_priv *priv, u32 rate)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_FREQ_RANK; i++) {
|
||||
if (rate <= priv->freq[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned int sso_led_pin_to_group(u32 pin)
|
||||
{
|
||||
if (pin < LED_GRP0_PIN_MAX)
|
||||
return LED_GRP0_0_23;
|
||||
else if (pin < LED_GRP1_PIN_MAX)
|
||||
return LED_GRP1_24_28;
|
||||
else
|
||||
return LED_GRP2_29_31;
|
||||
}
|
||||
|
||||
static u32 sso_led_get_freq_src(int freq_idx)
|
||||
{
|
||||
if (freq_idx < MAX_FPID_FREQ_RANK)
|
||||
return CLK_SRC_FPID;
|
||||
else if (freq_idx < MAX_GPTC_FREQ_RANK)
|
||||
return CLK_SRC_GPTC;
|
||||
else
|
||||
return CLK_SRC_GPTC_HS;
|
||||
}
|
||||
|
||||
static u32 sso_led_pin_blink_off(u32 pin, unsigned int group)
|
||||
{
|
||||
if (group == LED_GRP2_29_31)
|
||||
return pin - LED_GRP1_PIN_MAX;
|
||||
else if (group == LED_GRP1_24_28)
|
||||
return pin - LED_GRP0_PIN_MAX;
|
||||
else /* led 0 - 23 in led 32 location */
|
||||
return SSO_LED_MAX_NUM - LED_GRP1_PIN_MAX;
|
||||
}
|
||||
|
||||
static struct sso_led
|
||||
*cdev_to_sso_led_data(struct led_classdev *led_cdev)
|
||||
{
|
||||
return container_of(led_cdev, struct sso_led, cdev);
|
||||
}
|
||||
|
||||
static void sso_led_freq_set(struct sso_led_priv *priv, u32 pin, int freq_idx)
|
||||
{
|
||||
u32 reg, off, freq_src, val_freq;
|
||||
u32 low, high, val;
|
||||
unsigned int group;
|
||||
|
||||
if (!freq_idx)
|
||||
return;
|
||||
|
||||
group = sso_led_pin_to_group(pin);
|
||||
freq_src = sso_led_get_freq_src(freq_idx);
|
||||
off = sso_led_pin_blink_off(pin, group);
|
||||
|
||||
if (group == LED_GRP0_0_23)
|
||||
return;
|
||||
else if (group == LED_GRP1_24_28)
|
||||
reg = LED_BLINK_H8_0;
|
||||
else
|
||||
reg = LED_BLINK_H8_1;
|
||||
|
||||
if (freq_src == CLK_SRC_FPID)
|
||||
val_freq = freq_idx - 1;
|
||||
else if (freq_src == CLK_SRC_GPTC)
|
||||
val_freq = freq_idx - MAX_FPID_FREQ_RANK;
|
||||
|
||||
/* set blink rate idx */
|
||||
if (freq_src != CLK_SRC_GPTC_HS) {
|
||||
low = GET_FREQ_OFFSET(off, freq_src);
|
||||
high = low + 2;
|
||||
val = val_freq << high;
|
||||
regmap_update_bits(priv->mmap, reg, GENMASK(high, low), val);
|
||||
}
|
||||
|
||||
/* select clock source */
|
||||
low = GET_SRC_OFFSET(off);
|
||||
high = low + 2;
|
||||
val = freq_src << high;
|
||||
regmap_update_bits(priv->mmap, reg, GENMASK(high, low), val);
|
||||
}
|
||||
|
||||
static void sso_led_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct sso_led_priv *priv;
|
||||
struct sso_led_desc *desc;
|
||||
struct sso_led *led;
|
||||
int val;
|
||||
|
||||
led = cdev_to_sso_led_data(led_cdev);
|
||||
priv = led->priv;
|
||||
desc = &led->desc;
|
||||
|
||||
desc->brightness = brightness;
|
||||
regmap_write(priv->mmap, DUTY_CYCLE(desc->pin), brightness);
|
||||
|
||||
if (brightness == LED_OFF)
|
||||
val = 0;
|
||||
else
|
||||
val = 1;
|
||||
|
||||
/* HW blink off */
|
||||
if (desc->hw_blink && !val && desc->blinking) {
|
||||
desc->blinking = 0;
|
||||
regmap_update_bits(priv->mmap, SSO_CON2, BIT(desc->pin), 0);
|
||||
} else if (desc->hw_blink && val && !desc->blinking) {
|
||||
desc->blinking = 1;
|
||||
regmap_update_bits(priv->mmap, SSO_CON2, BIT(desc->pin),
|
||||
1 << desc->pin);
|
||||
}
|
||||
|
||||
if (!desc->hw_trig && led->gpiod)
|
||||
gpiod_set_value(led->gpiod, val);
|
||||
}
|
||||
|
||||
static enum led_brightness sso_led_brightness_get(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct sso_led *led = cdev_to_sso_led_data(led_cdev);
|
||||
|
||||
return (enum led_brightness)led->desc.brightness;
|
||||
}
|
||||
|
||||
static int
|
||||
delay_to_freq_idx(struct sso_led *led, unsigned long *delay_on,
|
||||
unsigned long *delay_off)
|
||||
{
|
||||
struct sso_led_priv *priv = led->priv;
|
||||
unsigned long delay;
|
||||
int freq_idx;
|
||||
u32 freq;
|
||||
|
||||
if (!*delay_on && !*delay_off) {
|
||||
*delay_on = *delay_off = (1000 / priv->freq[0]) / 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delay = *delay_on + *delay_off;
|
||||
freq = 1000 / delay;
|
||||
|
||||
freq_idx = sso_get_blink_rate_idx(priv, freq);
|
||||
if (freq_idx == -1)
|
||||
freq_idx = MAX_FREQ_RANK - 1;
|
||||
|
||||
delay = 1000 / priv->freq[freq_idx];
|
||||
*delay_on = *delay_off = delay / 2;
|
||||
|
||||
if (!*delay_on)
|
||||
*delay_on = *delay_off = 1;
|
||||
|
||||
return freq_idx;
|
||||
}
|
||||
|
||||
static int
|
||||
sso_led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,
|
||||
unsigned long *delay_off)
|
||||
{
|
||||
struct sso_led_priv *priv;
|
||||
struct sso_led *led;
|
||||
int freq_idx;
|
||||
|
||||
led = cdev_to_sso_led_data(led_cdev);
|
||||
priv = led->priv;
|
||||
freq_idx = delay_to_freq_idx(led, delay_on, delay_off);
|
||||
|
||||
sso_led_freq_set(priv, led->desc.pin, freq_idx);
|
||||
regmap_update_bits(priv->mmap, SSO_CON2, BIT(led->desc.pin),
|
||||
1 << led->desc.pin);
|
||||
led->desc.freq_idx = freq_idx;
|
||||
led->desc.blink_rate = priv->freq[freq_idx];
|
||||
led->desc.blinking = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void sso_led_hw_cfg(struct sso_led_priv *priv, struct sso_led *led)
|
||||
{
|
||||
struct sso_led_desc *desc = &led->desc;
|
||||
|
||||
/* set freq */
|
||||
if (desc->hw_blink) {
|
||||
sso_led_freq_set(priv, desc->pin, desc->freq_idx);
|
||||
regmap_update_bits(priv->mmap, SSO_CON2, BIT(desc->pin),
|
||||
1 << desc->pin);
|
||||
}
|
||||
|
||||
if (desc->hw_trig)
|
||||
regmap_update_bits(priv->mmap, SSO_CON3, BIT(desc->pin),
|
||||
1 << desc->pin);
|
||||
|
||||
/* set brightness */
|
||||
regmap_write(priv->mmap, DUTY_CYCLE(desc->pin), desc->brightness);
|
||||
|
||||
/* enable output */
|
||||
if (!desc->hw_trig && desc->brightness)
|
||||
gpiod_set_value(led->gpiod, 1);
|
||||
}
|
||||
|
||||
static int sso_create_led(struct sso_led_priv *priv, struct sso_led *led,
|
||||
struct fwnode_handle *child)
|
||||
{
|
||||
struct sso_led_desc *desc = &led->desc;
|
||||
struct led_init_data init_data;
|
||||
int err;
|
||||
|
||||
init_data.fwnode = child;
|
||||
init_data.devicename = SSO_DEV_NAME;
|
||||
init_data.default_label = ":";
|
||||
|
||||
led->cdev.default_trigger = desc->default_trigger;
|
||||
led->cdev.brightness_set = sso_led_brightness_set;
|
||||
led->cdev.brightness_get = sso_led_brightness_get;
|
||||
led->cdev.brightness = desc->brightness;
|
||||
led->cdev.max_brightness = LED_FULL;
|
||||
|
||||
if (desc->retain_state_shutdown)
|
||||
led->cdev.flags |= LED_RETAIN_AT_SHUTDOWN;
|
||||
if (desc->retain_state_suspended)
|
||||
led->cdev.flags |= LED_CORE_SUSPENDRESUME;
|
||||
if (desc->panic_indicator)
|
||||
led->cdev.flags |= LED_PANIC_INDICATOR;
|
||||
|
||||
if (desc->hw_blink)
|
||||
led->cdev.blink_set = sso_led_blink_set;
|
||||
|
||||
sso_led_hw_cfg(priv, led);
|
||||
|
||||
err = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
list_add(&led->list, &priv->led_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sso_init_freq(struct sso_led_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
priv->freq[0] = 0;
|
||||
for (i = 1; i < MAX_FREQ_RANK; i++) {
|
||||
if (i < MAX_FPID_FREQ_RANK) {
|
||||
priv->freq[i] = priv->fpid_clkrate / freq_div_tbl[i - 1];
|
||||
} else if (i < MAX_GPTC_FREQ_RANK) {
|
||||
priv->freq[i] = priv->gptc_clkrate /
|
||||
freq_div_tbl[i - MAX_FPID_FREQ_RANK];
|
||||
} else if (i < MAX_GPTC_HS_FREQ_RANK) {
|
||||
priv->freq[i] = priv->gptc_clkrate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sso_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct sso_led_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
if (priv->gpio.alloc_bitmap & BIT(offset))
|
||||
return -EINVAL;
|
||||
|
||||
priv->gpio.alloc_bitmap |= BIT(offset);
|
||||
regmap_write(priv->mmap, DUTY_CYCLE(offset), 0xFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sso_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct sso_led_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
priv->gpio.alloc_bitmap &= ~BIT(offset);
|
||||
regmap_write(priv->mmap, DUTY_CYCLE(offset), 0x0);
|
||||
}
|
||||
|
||||
static int sso_gpio_get_dir(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return GPIOF_DIR_OUT;
|
||||
}
|
||||
|
||||
static int
|
||||
sso_gpio_dir_out(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct sso_led_priv *priv = gpiochip_get_data(chip);
|
||||
bool bit = !!value;
|
||||
|
||||
regmap_update_bits(priv->mmap, SSO_CPU, BIT(offset), bit << offset);
|
||||
if (!priv->gpio.freq)
|
||||
regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_SWU,
|
||||
SSO_CON0_SWU);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sso_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct sso_led_priv *priv = gpiochip_get_data(chip);
|
||||
u32 reg_val;
|
||||
|
||||
regmap_read(priv->mmap, SSO_CPU, ®_val);
|
||||
|
||||
return !!(reg_val & BIT(offset));
|
||||
}
|
||||
|
||||
static void sso_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct sso_led_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
regmap_update_bits(priv->mmap, SSO_CPU, BIT(offset), value << offset);
|
||||
if (!priv->gpio.freq)
|
||||
regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_SWU,
|
||||
SSO_CON0_SWU);
|
||||
}
|
||||
|
||||
static int sso_gpio_gc_init(struct device *dev, struct sso_led_priv *priv)
|
||||
{
|
||||
struct gpio_chip *gc = &priv->gpio.chip;
|
||||
|
||||
gc->request = sso_gpio_request;
|
||||
gc->free = sso_gpio_free;
|
||||
gc->get_direction = sso_gpio_get_dir;
|
||||
gc->direction_output = sso_gpio_dir_out;
|
||||
gc->get = sso_gpio_get;
|
||||
gc->set = sso_gpio_set;
|
||||
|
||||
gc->label = "lgm-sso";
|
||||
gc->base = -1;
|
||||
/* To exclude pins from control, use "gpio-reserved-ranges" */
|
||||
gc->ngpio = priv->gpio.pins;
|
||||
gc->parent = dev;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->of_node = dev->of_node;
|
||||
|
||||
return devm_gpiochip_add_data(dev, gc, priv);
|
||||
}
|
||||
|
||||
static int sso_gpio_get_freq_idx(int freq)
|
||||
{
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(freq_tbl); idx++) {
|
||||
if (freq <= freq_tbl[idx])
|
||||
return idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void sso_register_shift_clk(struct sso_led_priv *priv)
|
||||
{
|
||||
int idx, size = ARRAY_SIZE(shift_clk_freq_tbl);
|
||||
u32 val = 0;
|
||||
|
||||
for (idx = 0; idx < size; idx++) {
|
||||
if (shift_clk_freq_tbl[idx] <= priv->gpio.shift_clk_freq) {
|
||||
val = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == size)
|
||||
dev_warn(priv->dev, "%s: Invalid freq %d\n",
|
||||
__func__, priv->gpio.shift_clk_freq);
|
||||
|
||||
regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_FCDSC,
|
||||
FIELD_PREP(SSO_CON1_FCDSC, val));
|
||||
}
|
||||
|
||||
static int sso_gpio_freq_set(struct sso_led_priv *priv)
|
||||
{
|
||||
int freq_idx;
|
||||
u32 val;
|
||||
|
||||
freq_idx = sso_gpio_get_freq_idx(priv->gpio.freq);
|
||||
if (freq_idx == -1)
|
||||
freq_idx = ARRAY_SIZE(freq_tbl) - 1;
|
||||
|
||||
val = freq_idx % FPID_FREQ_RANK_MAX;
|
||||
|
||||
if (!priv->gpio.freq) {
|
||||
regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_BLINK_R, 0);
|
||||
regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_US,
|
||||
FIELD_PREP(SSO_CON1_US, US_SW));
|
||||
} else if (freq_idx < FPID_FREQ_RANK_MAX) {
|
||||
regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_BLINK_R,
|
||||
SSO_CON0_BLINK_R);
|
||||
regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_US,
|
||||
FIELD_PREP(SSO_CON1_US, US_FPID));
|
||||
regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_FPID,
|
||||
FIELD_PREP(SSO_CON1_FPID, val));
|
||||
} else {
|
||||
regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_BLINK_R,
|
||||
SSO_CON0_BLINK_R);
|
||||
regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_US,
|
||||
FIELD_PREP(SSO_CON1_US, US_GPTC));
|
||||
regmap_update_bits(priv->mmap, SSO_CON1, SSO_CON1_GPTD,
|
||||
FIELD_PREP(SSO_CON1_GPTD, val));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sso_gpio_hw_init(struct sso_led_priv *priv)
|
||||
{
|
||||
u32 activate;
|
||||
int i, err;
|
||||
|
||||
/* Clear all duty cycles */
|
||||
for (i = 0; i < priv->gpio.pins; i++) {
|
||||
err = regmap_write(priv->mmap, DUTY_CYCLE(i), 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* 4 groups for total 32 pins */
|
||||
for (i = 1; i <= MAX_GROUP_NUM; i++) {
|
||||
activate = !!(i * PINS_PER_GROUP <= priv->gpio.pins ||
|
||||
priv->gpio.pins > (i - 1) * PINS_PER_GROUP);
|
||||
err = regmap_update_bits(priv->mmap, SSO_CON1, BIT(i - 1),
|
||||
activate << (i - 1));
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* NO HW directly controlled pin by default */
|
||||
err = regmap_write(priv->mmap, SSO_CON3, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* NO BLINK for all pins */
|
||||
err = regmap_write(priv->mmap, SSO_CON2, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* OUTPUT 0 by default */
|
||||
err = regmap_write(priv->mmap, SSO_CPU, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* update edge */
|
||||
err = regmap_update_bits(priv->mmap, SSO_CON0, SSO_CON0_RZFL,
|
||||
FIELD_PREP(SSO_CON0_RZFL, priv->gpio.edge));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set GPIO update rate */
|
||||
sso_gpio_freq_set(priv);
|
||||
|
||||
/* Register shift clock */
|
||||
sso_register_shift_clk(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sso_led_shutdown(struct sso_led *led)
|
||||
{
|
||||
struct sso_led_priv *priv = led->priv;
|
||||
|
||||
/* unregister led */
|
||||
devm_led_classdev_unregister(priv->dev, &led->cdev);
|
||||
|
||||
/* clear HW control bit */
|
||||
if (led->desc.hw_trig)
|
||||
regmap_update_bits(priv->mmap, SSO_CON3, BIT(led->desc.pin), 0);
|
||||
|
||||
if (led->gpiod)
|
||||
devm_gpiod_put(priv->dev, led->gpiod);
|
||||
|
||||
led->priv = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
__sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
|
||||
{
|
||||
struct fwnode_handle *fwnode_child;
|
||||
struct device *dev = priv->dev;
|
||||
struct sso_led_desc *desc;
|
||||
struct sso_led *led;
|
||||
struct list_head *p;
|
||||
const char *tmp;
|
||||
u32 prop;
|
||||
int ret;
|
||||
|
||||
fwnode_for_each_child_node(fw_ssoled, fwnode_child) {
|
||||
led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&led->list);
|
||||
led->priv = priv;
|
||||
desc = &led->desc;
|
||||
|
||||
led->gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL,
|
||||
fwnode_child,
|
||||
GPIOD_ASIS, NULL);
|
||||
if (IS_ERR(led->gpiod)) {
|
||||
dev_err(dev, "led: get gpio fail!\n");
|
||||
goto __dt_err;
|
||||
}
|
||||
|
||||
fwnode_property_read_string(fwnode_child,
|
||||
"linux,default-trigger",
|
||||
&desc->default_trigger);
|
||||
|
||||
if (fwnode_property_present(fwnode_child,
|
||||
"retain-state-suspended"))
|
||||
desc->retain_state_suspended = 1;
|
||||
|
||||
if (fwnode_property_present(fwnode_child,
|
||||
"retain-state-shutdown"))
|
||||
desc->retain_state_shutdown = 1;
|
||||
|
||||
if (fwnode_property_present(fwnode_child, "panic-indicator"))
|
||||
desc->panic_indicator = 1;
|
||||
|
||||
ret = fwnode_property_read_u32(fwnode_child, "reg", &prop);
|
||||
if (ret != 0 || prop >= SSO_LED_MAX_NUM) {
|
||||
dev_err(dev, "invalid LED pin:%u\n", prop);
|
||||
goto __dt_err;
|
||||
}
|
||||
desc->pin = prop;
|
||||
|
||||
if (fwnode_property_present(fwnode_child, "intel,sso-hw-blink"))
|
||||
desc->hw_blink = 1;
|
||||
|
||||
desc->hw_trig = fwnode_property_read_bool(fwnode_child,
|
||||
"intel,sso-hw-trigger");
|
||||
if (desc->hw_trig) {
|
||||
desc->default_trigger = NULL;
|
||||
desc->retain_state_shutdown = 0;
|
||||
desc->retain_state_suspended = 0;
|
||||
desc->panic_indicator = 0;
|
||||
desc->hw_blink = 0;
|
||||
}
|
||||
|
||||
if (fwnode_property_read_u32(fwnode_child,
|
||||
"intel,sso-blink-rate-hz", &prop)) {
|
||||
/* default first freq rate */
|
||||
desc->freq_idx = 0;
|
||||
desc->blink_rate = priv->freq[desc->freq_idx];
|
||||
} else {
|
||||
desc->freq_idx = sso_get_blink_rate_idx(priv, prop);
|
||||
if (desc->freq_idx == -1)
|
||||
desc->freq_idx = MAX_FREQ_RANK - 1;
|
||||
|
||||
desc->blink_rate = priv->freq[desc->freq_idx];
|
||||
}
|
||||
|
||||
if (!fwnode_property_read_string(fwnode_child, "default-state", &tmp)) {
|
||||
if (!strcmp(tmp, "on"))
|
||||
desc->brightness = LED_FULL;
|
||||
}
|
||||
|
||||
if (sso_create_led(priv, led, fwnode_child))
|
||||
goto __dt_err;
|
||||
}
|
||||
fwnode_handle_put(fw_ssoled);
|
||||
|
||||
return 0;
|
||||
__dt_err:
|
||||
fwnode_handle_put(fw_ssoled);
|
||||
/* unregister leds */
|
||||
list_for_each(p, &priv->led_list) {
|
||||
led = list_entry(p, struct sso_led, list);
|
||||
sso_led_shutdown(led);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int sso_led_dt_parse(struct sso_led_priv *priv)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(priv->dev);
|
||||
struct fwnode_handle *fw_ssoled;
|
||||
struct device *dev = priv->dev;
|
||||
int count;
|
||||
int ret;
|
||||
|
||||
count = device_get_child_node_count(dev);
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
fw_ssoled = fwnode_get_named_child_node(fwnode, "ssoled");
|
||||
if (fw_ssoled) {
|
||||
ret = __sso_led_dt_parse(priv, fw_ssoled);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sso_probe_gpios(struct sso_led_priv *priv)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
int ret;
|
||||
|
||||
if (device_property_read_u32(dev, "ngpios", &priv->gpio.pins))
|
||||
priv->gpio.pins = MAX_PIN_NUM_PER_BANK;
|
||||
|
||||
if (priv->gpio.pins > MAX_PIN_NUM_PER_BANK)
|
||||
return -EINVAL;
|
||||
|
||||
if (device_property_read_u32(dev, "intel,sso-update-rate-hz",
|
||||
&priv->gpio.freq))
|
||||
priv->gpio.freq = 0;
|
||||
|
||||
priv->gpio.edge = DATA_CLK_EDGE;
|
||||
priv->gpio.shift_clk_freq = -1;
|
||||
|
||||
ret = sso_gpio_hw_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sso_gpio_gc_init(dev, priv);
|
||||
}
|
||||
|
||||
static void sso_clk_disable(void *data)
|
||||
{
|
||||
struct sso_led_priv *priv = data;
|
||||
|
||||
clk_disable_unprepare(priv->fpid_clk);
|
||||
clk_disable_unprepare(priv->gclk);
|
||||
}
|
||||
|
||||
static int intel_sso_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sso_led_priv *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->pdev = pdev;
|
||||
priv->dev = dev;
|
||||
|
||||
/* gate clock */
|
||||
priv->gclk = devm_clk_get(dev, "sso");
|
||||
if (IS_ERR(priv->gclk)) {
|
||||
dev_err(dev, "get sso gate clock failed!\n");
|
||||
return PTR_ERR(priv->gclk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->gclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to prepate/enable sso gate clock!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->fpid_clk = devm_clk_get(dev, "fpid");
|
||||
if (IS_ERR(priv->fpid_clk)) {
|
||||
dev_err(dev, "Failed to get fpid clock!\n");
|
||||
return PTR_ERR(priv->fpid_clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->fpid_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to prepare/enable fpid clock!\n");
|
||||
return ret;
|
||||
}
|
||||
priv->fpid_clkrate = clk_get_rate(priv->fpid_clk);
|
||||
|
||||
ret = devm_add_action_or_reset(dev, sso_clk_disable, priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to devm_add_action_or_reset, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->mmap = syscon_node_to_regmap(dev->of_node);
|
||||
if (IS_ERR(priv->mmap)) {
|
||||
dev_err(dev, "Failed to map iomem!\n");
|
||||
return PTR_ERR(priv->mmap);
|
||||
}
|
||||
|
||||
ret = sso_probe_gpios(priv);
|
||||
if (ret) {
|
||||
regmap_exit(priv->mmap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&priv->led_list);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
sso_init_freq(priv);
|
||||
|
||||
priv->gptc_clkrate = DEF_GPTC_CLK_RATE;
|
||||
|
||||
ret = sso_led_dt_parse(priv);
|
||||
if (ret) {
|
||||
regmap_exit(priv->mmap);
|
||||
return ret;
|
||||
}
|
||||
dev_info(priv->dev, "sso LED init success!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_sso_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sso_led_priv *priv;
|
||||
struct list_head *pos, *n;
|
||||
struct sso_led *led;
|
||||
|
||||
priv = platform_get_drvdata(pdev);
|
||||
|
||||
list_for_each_safe(pos, n, &priv->led_list) {
|
||||
list_del(pos);
|
||||
led = list_entry(pos, struct sso_led, list);
|
||||
sso_led_shutdown(led);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(priv->fpid_clk);
|
||||
clk_disable_unprepare(priv->gclk);
|
||||
regmap_exit(priv->mmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_sso_led_match[] = {
|
||||
{ .compatible = "intel,lgm-ssoled" },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, of_sso_led_match);
|
||||
|
||||
static struct platform_driver intel_sso_led_driver = {
|
||||
.probe = intel_sso_led_probe,
|
||||
.remove = intel_sso_led_remove,
|
||||
.driver = {
|
||||
.name = "lgm-ssoled",
|
||||
.of_match_table = of_match_ptr(of_sso_led_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(intel_sso_led_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Intel SSO LED/GPIO driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -145,8 +145,7 @@ static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
|
|||
device_remove_file(led_cdev->dev, &dev_attr_brightness_hw_changed);
|
||||
}
|
||||
|
||||
void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev, unsigned int brightness)
|
||||
{
|
||||
if (WARN_ON(!led_cdev->brightness_hw_changed_kn))
|
||||
return;
|
||||
|
|
|
@ -39,8 +39,7 @@ const char * const led_colors[LED_COLOR_ID_MAX] = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(led_colors);
|
||||
|
||||
static int __led_set_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
static int __led_set_brightness(struct led_classdev *led_cdev, unsigned int value)
|
||||
{
|
||||
if (!led_cdev->brightness_set)
|
||||
return -ENOTSUPP;
|
||||
|
@ -50,8 +49,7 @@ static int __led_set_brightness(struct led_classdev *led_cdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __led_set_brightness_blocking(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
static int __led_set_brightness_blocking(struct led_classdev *led_cdev, unsigned int value)
|
||||
{
|
||||
if (!led_cdev->brightness_set_blocking)
|
||||
return -ENOTSUPP;
|
||||
|
@ -240,8 +238,7 @@ void led_stop_software_blink(struct led_classdev *led_cdev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(led_stop_software_blink);
|
||||
|
||||
void led_set_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
void led_set_brightness(struct led_classdev *led_cdev, unsigned int brightness)
|
||||
{
|
||||
/*
|
||||
* If software blink is active, delay brightness setting
|
||||
|
@ -253,7 +250,7 @@ void led_set_brightness(struct led_classdev *led_cdev,
|
|||
* work queue task to avoid problems in case we are called
|
||||
* from hard irq context.
|
||||
*/
|
||||
if (brightness == LED_OFF) {
|
||||
if (!brightness) {
|
||||
set_bit(LED_BLINK_DISABLE, &led_cdev->work_flags);
|
||||
schedule_work(&led_cdev->set_brightness_work);
|
||||
} else {
|
||||
|
@ -268,8 +265,7 @@ void led_set_brightness(struct led_classdev *led_cdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(led_set_brightness);
|
||||
|
||||
void led_set_brightness_nopm(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
void led_set_brightness_nopm(struct led_classdev *led_cdev, unsigned int value)
|
||||
{
|
||||
/* Use brightness_set op if available, it is guaranteed not to sleep */
|
||||
if (!__led_set_brightness(led_cdev, value))
|
||||
|
@ -281,8 +277,7 @@ void led_set_brightness_nopm(struct led_classdev *led_cdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(led_set_brightness_nopm);
|
||||
|
||||
void led_set_brightness_nosleep(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
void led_set_brightness_nosleep(struct led_classdev *led_cdev, unsigned int value)
|
||||
{
|
||||
led_cdev->brightness = min(value, led_cdev->max_brightness);
|
||||
|
||||
|
@ -293,8 +288,7 @@ void led_set_brightness_nosleep(struct led_classdev *led_cdev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(led_set_brightness_nosleep);
|
||||
|
||||
int led_set_brightness_sync(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value)
|
||||
{
|
||||
if (led_cdev->blink_delay_on || led_cdev->blink_delay_off)
|
||||
return -EBUSY;
|
||||
|
|
|
@ -83,6 +83,7 @@ static const struct apu_led_profile apu1_led_profile[] = {
|
|||
};
|
||||
|
||||
static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
|
||||
/* PC Engines APU with factory bios "SageBios_PCEngines_APU-45" */
|
||||
{
|
||||
.ident = "apu",
|
||||
.matches = {
|
||||
|
@ -90,6 +91,14 @@ static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "APU")
|
||||
}
|
||||
},
|
||||
/* PC Engines APU with "Mainline" bios >= 4.6.8 */
|
||||
{
|
||||
.ident = "apu",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "apu1")
|
||||
}
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table);
|
||||
|
@ -173,7 +182,7 @@ static int __init apu_led_init(void)
|
|||
int err;
|
||||
|
||||
if (!(dmi_match(DMI_SYS_VENDOR, "PC Engines") &&
|
||||
dmi_match(DMI_PRODUCT_NAME, "APU"))) {
|
||||
(dmi_match(DMI_PRODUCT_NAME, "APU") || dmi_match(DMI_PRODUCT_NAME, "apu1")))) {
|
||||
pr_err("No PC Engines APUv1 board detected. For APUv2,3 support, enable CONFIG_PCENGINES_APU2\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -192,13 +192,13 @@ static int store_color_common(struct device *dev, const char *buf, int color)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t show_red(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t red_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return show_color_common(dev, buf, RED);
|
||||
}
|
||||
|
||||
static ssize_t store_red(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t red_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
|
@ -209,15 +209,15 @@ static ssize_t store_red(struct device *dev, struct device_attribute *attr,
|
|||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(red, S_IRUGO | S_IWUSR, show_red, store_red);
|
||||
static DEVICE_ATTR_RW(red);
|
||||
|
||||
static ssize_t show_green(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t green_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return show_color_common(dev, buf, GREEN);
|
||||
}
|
||||
|
||||
static ssize_t store_green(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t green_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
|
||||
|
@ -229,15 +229,15 @@ static ssize_t store_green(struct device *dev, struct device_attribute *attr,
|
|||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(green, S_IRUGO | S_IWUSR, show_green, store_green);
|
||||
static DEVICE_ATTR_RW(green);
|
||||
|
||||
static ssize_t show_blue(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t blue_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return show_color_common(dev, buf, BLUE);
|
||||
}
|
||||
|
||||
static ssize_t store_blue(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t blue_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
|
@ -248,16 +248,16 @@ static ssize_t store_blue(struct device *dev, struct device_attribute *attr,
|
|||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(blue, S_IRUGO | S_IWUSR, show_blue, store_blue);
|
||||
static DEVICE_ATTR_RW(blue);
|
||||
|
||||
static ssize_t show_test(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t test_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"#Write into test to start test sequence!#\n");
|
||||
}
|
||||
|
||||
static ssize_t store_test(struct device *dev, struct device_attribute *attr,
|
||||
static ssize_t test_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
|
||||
|
@ -273,7 +273,7 @@ static ssize_t store_test(struct device *dev, struct device_attribute *attr,
|
|||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(test, S_IRUGO | S_IWUSR, show_test, store_test);
|
||||
static DEVICE_ATTR_RW(test);
|
||||
|
||||
/* TODO: HSB, fade, timeadj, script ... */
|
||||
|
||||
|
|
|
@ -96,7 +96,8 @@ static int create_gpio_led(const struct gpio_led *template,
|
|||
} else {
|
||||
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
|
||||
}
|
||||
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
|
||||
led_dat->cdev.brightness = state;
|
||||
led_dat->cdev.max_brightness = 1;
|
||||
if (!template->retain_state_suspended)
|
||||
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
|
||||
if (template->panic_indicator)
|
||||
|
|
|
@ -346,8 +346,8 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t lm3530_mode_get(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct lm3530_data *drvdata;
|
||||
|
@ -365,8 +365,8 @@ static ssize_t lm3530_mode_get(struct device *dev,
|
|||
return len;
|
||||
}
|
||||
|
||||
static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
|
||||
*attr, const char *buf, size_t size)
|
||||
static ssize_t mode_store(struct device *dev, struct device_attribute
|
||||
*attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct lm3530_data *drvdata;
|
||||
|
@ -397,7 +397,7 @@ static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute
|
|||
|
||||
return sizeof(drvdata->mode);
|
||||
}
|
||||
static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set);
|
||||
static DEVICE_ATTR_RW(mode);
|
||||
|
||||
static struct attribute *lm3530_attrs[] = {
|
||||
&dev_attr_mode.attr,
|
||||
|
|
|
@ -608,7 +608,7 @@ static struct attribute *lm3533_led_attributes[] = {
|
|||
static umode_t lm3533_led_attr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct lm3533_led *led = to_lm3533_led(led_cdev);
|
||||
umode_t mode = attr->mode;
|
||||
|
|
|
@ -349,9 +349,9 @@ static int lm355x_indicator_brightness_set(struct led_classdev *cdev,
|
|||
}
|
||||
|
||||
/* indicator pattern only for lm3556*/
|
||||
static ssize_t lm3556_indicator_pattern_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
static ssize_t pattern_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
|
@ -381,7 +381,7 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(pattern, S_IWUSR, NULL, lm3556_indicator_pattern_store);
|
||||
static DEVICE_ATTR_WO(pattern);
|
||||
|
||||
static struct attribute *lm355x_indicator_attrs[] = {
|
||||
&dev_attr_pattern.attr,
|
||||
|
|
|
@ -165,9 +165,9 @@ static int lm3642_control(struct lm3642_chip_data *chip,
|
|||
/* torch */
|
||||
|
||||
/* torch pin config for lm3642 */
|
||||
static ssize_t lm3642_torch_pin_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
static ssize_t torch_pin_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
|
@ -193,7 +193,7 @@ static ssize_t lm3642_torch_pin_store(struct device *dev,
|
|||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(torch_pin, S_IWUSR, NULL, lm3642_torch_pin_store);
|
||||
static DEVICE_ATTR_WO(torch_pin);
|
||||
|
||||
static int lm3642_torch_brightness_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
|
@ -212,9 +212,9 @@ static int lm3642_torch_brightness_set(struct led_classdev *cdev,
|
|||
/* flash */
|
||||
|
||||
/* strobe pin config for lm3642*/
|
||||
static ssize_t lm3642_strobe_pin_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
static ssize_t strobe_pin_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
|
@ -240,7 +240,7 @@ static ssize_t lm3642_strobe_pin_store(struct device *dev,
|
|||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(strobe_pin, S_IWUSR, NULL, lm3642_strobe_pin_store);
|
||||
static DEVICE_ATTR_WO(strobe_pin);
|
||||
|
||||
static int lm3642_strobe_brightness_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
|
|
|
@ -6,10 +6,9 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -322,7 +321,7 @@ static int lp50xx_brightness_set(struct led_classdev *cdev,
|
|||
|
||||
ret = regmap_write(led->priv->regmap, reg_val, brightness);
|
||||
if (ret) {
|
||||
dev_err(&led->priv->client->dev,
|
||||
dev_err(led->priv->dev,
|
||||
"Cannot write brightness value %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
@ -338,7 +337,7 @@ static int lp50xx_brightness_set(struct led_classdev *cdev,
|
|||
ret = regmap_write(led->priv->regmap, reg_val,
|
||||
mc_dev->subled_info[i].intensity);
|
||||
if (ret) {
|
||||
dev_err(&led->priv->client->dev,
|
||||
dev_err(led->priv->dev,
|
||||
"Cannot write intensity value %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
@ -360,8 +359,8 @@ static int lp50xx_set_banks(struct lp50xx *priv, u32 led_banks[])
|
|||
bank_enable_mask |= (1 << led_banks[i]);
|
||||
}
|
||||
|
||||
led_config_lo = (u8)(bank_enable_mask & 0xff);
|
||||
led_config_hi = (u8)(bank_enable_mask >> 8) & 0xff;
|
||||
led_config_lo = bank_enable_mask;
|
||||
led_config_hi = bank_enable_mask >> 8;
|
||||
|
||||
ret = regmap_write(priv->regmap, LP50XX_LED_CFG0, led_config_lo);
|
||||
if (ret)
|
||||
|
@ -382,11 +381,9 @@ static int lp50xx_enable_disable(struct lp50xx *priv, int enable_disable)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (priv->enable_gpio) {
|
||||
ret = gpiod_direction_output(priv->enable_gpio, enable_disable);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = gpiod_direction_output(priv->enable_gpio, enable_disable);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (enable_disable)
|
||||
return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN);
|
||||
|
@ -404,7 +401,7 @@ static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv,
|
|||
|
||||
if (num_leds > 1) {
|
||||
if (num_leds > priv->chip_info->max_modules) {
|
||||
dev_err(&priv->client->dev, "reg property is invalid\n");
|
||||
dev_err(priv->dev, "reg property is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -412,13 +409,13 @@ static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv,
|
|||
|
||||
ret = fwnode_property_read_u32_array(child, "reg", led_banks, num_leds);
|
||||
if (ret) {
|
||||
dev_err(&priv->client->dev, "reg property is missing\n");
|
||||
dev_err(priv->dev, "reg property is missing\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = lp50xx_set_banks(priv, led_banks);
|
||||
if (ret) {
|
||||
dev_err(&priv->client->dev, "Cannot setup banked LEDs\n");
|
||||
dev_err(priv->dev, "Cannot setup banked LEDs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -426,12 +423,12 @@ static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv,
|
|||
} else {
|
||||
ret = fwnode_property_read_u32(child, "reg", &led_number);
|
||||
if (ret) {
|
||||
dev_err(&priv->client->dev, "led reg property missing\n");
|
||||
dev_err(priv->dev, "led reg property missing\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (led_number > priv->chip_info->num_leds) {
|
||||
dev_err(&priv->client->dev, "led-sources property is invalid\n");
|
||||
dev_err(priv->dev, "led-sources property is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -455,12 +452,9 @@ static int lp50xx_probe_dt(struct lp50xx *priv)
|
|||
int i = 0;
|
||||
|
||||
priv->enable_gpio = devm_gpiod_get_optional(priv->dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->enable_gpio)) {
|
||||
ret = PTR_ERR(priv->enable_gpio);
|
||||
dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(priv->enable_gpio))
|
||||
return dev_err_probe(priv->dev, PTR_ERR(priv->enable_gpio),
|
||||
"Failed to get enable GPIO\n");
|
||||
|
||||
priv->regulator = devm_regulator_get(priv->dev, "vled");
|
||||
if (IS_ERR(priv->regulator))
|
||||
|
@ -470,7 +464,7 @@ static int lp50xx_probe_dt(struct lp50xx *priv)
|
|||
led = &priv->leds[i];
|
||||
ret = fwnode_property_count_u32(child, "reg");
|
||||
if (ret < 0) {
|
||||
dev_err(&priv->client->dev, "reg property is invalid\n");
|
||||
dev_err(priv->dev, "reg property is invalid\n");
|
||||
goto child_out;
|
||||
}
|
||||
|
||||
|
@ -510,12 +504,11 @@ static int lp50xx_probe_dt(struct lp50xx *priv)
|
|||
led_cdev = &led->mc_cdev.led_cdev;
|
||||
led_cdev->brightness_set_blocking = lp50xx_brightness_set;
|
||||
|
||||
ret = devm_led_classdev_multicolor_register_ext(&priv->client->dev,
|
||||
ret = devm_led_classdev_multicolor_register_ext(priv->dev,
|
||||
&led->mc_cdev,
|
||||
&init_data);
|
||||
if (ret) {
|
||||
dev_err(&priv->client->dev, "led register err: %d\n",
|
||||
ret);
|
||||
dev_err(priv->dev, "led register err: %d\n", ret);
|
||||
goto child_out;
|
||||
}
|
||||
i++;
|
||||
|
@ -529,8 +522,7 @@ child_out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int lp50xx_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
static int lp50xx_probe(struct i2c_client *client)
|
||||
{
|
||||
struct lp50xx *led;
|
||||
int count;
|
||||
|
@ -550,7 +542,7 @@ static int lp50xx_probe(struct i2c_client *client,
|
|||
mutex_init(&led->lock);
|
||||
led->client = client;
|
||||
led->dev = &client->dev;
|
||||
led->chip_info = &lp50xx_chip_info_tbl[id->driver_data];
|
||||
led->chip_info = device_get_match_data(&client->dev);
|
||||
i2c_set_clientdata(client, led);
|
||||
led->regmap = devm_regmap_init_i2c(client,
|
||||
led->chip_info->lp50xx_regmap_config);
|
||||
|
@ -579,15 +571,14 @@ static int lp50xx_remove(struct i2c_client *client)
|
|||
|
||||
ret = lp50xx_enable_disable(led, 0);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "Failed to disable chip\n");
|
||||
dev_err(led->dev, "Failed to disable chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (led->regulator) {
|
||||
ret = regulator_disable(led->regulator);
|
||||
if (ret)
|
||||
dev_err(&led->client->dev,
|
||||
"Failed to disable regulator\n");
|
||||
dev_err(led->dev, "Failed to disable regulator\n");
|
||||
}
|
||||
|
||||
mutex_destroy(&led->lock);
|
||||
|
@ -596,24 +587,24 @@ static int lp50xx_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id lp50xx_id[] = {
|
||||
{ "lp5009", LP5009 },
|
||||
{ "lp5012", LP5012 },
|
||||
{ "lp5018", LP5018 },
|
||||
{ "lp5024", LP5024 },
|
||||
{ "lp5030", LP5030 },
|
||||
{ "lp5036", LP5036 },
|
||||
{ "lp5009", (kernel_ulong_t)&lp50xx_chip_info_tbl[LP5009] },
|
||||
{ "lp5012", (kernel_ulong_t)&lp50xx_chip_info_tbl[LP5012] },
|
||||
{ "lp5018", (kernel_ulong_t)&lp50xx_chip_info_tbl[LP5018] },
|
||||
{ "lp5024", (kernel_ulong_t)&lp50xx_chip_info_tbl[LP5024] },
|
||||
{ "lp5030", (kernel_ulong_t)&lp50xx_chip_info_tbl[LP5030] },
|
||||
{ "lp5036", (kernel_ulong_t)&lp50xx_chip_info_tbl[LP5036] },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lp50xx_id);
|
||||
|
||||
static const struct of_device_id of_lp50xx_leds_match[] = {
|
||||
{ .compatible = "ti,lp5009", .data = (void *)LP5009 },
|
||||
{ .compatible = "ti,lp5012", .data = (void *)LP5012 },
|
||||
{ .compatible = "ti,lp5018", .data = (void *)LP5018 },
|
||||
{ .compatible = "ti,lp5024", .data = (void *)LP5024 },
|
||||
{ .compatible = "ti,lp5030", .data = (void *)LP5030 },
|
||||
{ .compatible = "ti,lp5036", .data = (void *)LP5036 },
|
||||
{},
|
||||
{ .compatible = "ti,lp5009", .data = &lp50xx_chip_info_tbl[LP5009] },
|
||||
{ .compatible = "ti,lp5012", .data = &lp50xx_chip_info_tbl[LP5012] },
|
||||
{ .compatible = "ti,lp5018", .data = &lp50xx_chip_info_tbl[LP5018] },
|
||||
{ .compatible = "ti,lp5024", .data = &lp50xx_chip_info_tbl[LP5024] },
|
||||
{ .compatible = "ti,lp5030", .data = &lp50xx_chip_info_tbl[LP5030] },
|
||||
{ .compatible = "ti,lp5036", .data = &lp50xx_chip_info_tbl[LP5036] },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_lp50xx_leds_match);
|
||||
|
||||
|
@ -622,7 +613,7 @@ static struct i2c_driver lp50xx_driver = {
|
|||
.name = "lp50xx",
|
||||
.of_match_table = of_lp50xx_leds_match,
|
||||
},
|
||||
.probe = lp50xx_probe,
|
||||
.probe_new = lp50xx_probe,
|
||||
.remove = lp50xx_remove,
|
||||
.id_table = lp50xx_id,
|
||||
};
|
||||
|
|
|
@ -160,8 +160,8 @@ static void max8997_led_brightness_set(struct led_classdev *led_cdev,
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t max8997_led_show_mode(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct max8997_led *led =
|
||||
|
@ -193,9 +193,9 @@ static ssize_t max8997_led_show_mode(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t max8997_led_store_mode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
static ssize_t mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct max8997_led *led =
|
||||
|
@ -222,7 +222,7 @@ static ssize_t max8997_led_store_mode(struct device *dev,
|
|||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode);
|
||||
static DEVICE_ATTR_RW(mode);
|
||||
|
||||
static struct attribute *max8997_attrs[] = {
|
||||
&dev_attr_mode.attr,
|
||||
|
|
|
@ -204,9 +204,9 @@ static void netxbig_led_set(struct led_classdev *led_cdev,
|
|||
spin_unlock_irqrestore(&led_dat->lock, flags);
|
||||
}
|
||||
|
||||
static ssize_t netxbig_led_sata_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buff, size_t count)
|
||||
static ssize_t sata_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buff, size_t count)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct netxbig_led_data *led_dat =
|
||||
|
@ -255,8 +255,8 @@ exit_unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t netxbig_led_sata_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t sata_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct netxbig_led_data *led_dat =
|
||||
|
@ -265,7 +265,7 @@ static ssize_t netxbig_led_sata_show(struct device *dev,
|
|||
return sprintf(buf, "%d\n", led_dat->sata);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store);
|
||||
static DEVICE_ATTR_RW(sata);
|
||||
|
||||
static struct attribute *netxbig_led_attrs[] = {
|
||||
&dev_attr_sata.attr,
|
||||
|
|
|
@ -441,8 +441,8 @@ static void set_power_light_amber_noblink(void)
|
|||
nasgpio_led_set_brightness(&amber->led_cdev, LED_FULL);
|
||||
}
|
||||
|
||||
static ssize_t nas_led_blink_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t blink_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
int blinking = 0;
|
||||
|
@ -451,9 +451,9 @@ static ssize_t nas_led_blink_show(struct device *dev,
|
|||
return sprintf(buf, "%u\n", blinking);
|
||||
}
|
||||
|
||||
static ssize_t nas_led_blink_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
static ssize_t blink_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
|
@ -468,7 +468,7 @@ static ssize_t nas_led_blink_store(struct device *dev,
|
|||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(blink, 0644, nas_led_blink_show, nas_led_blink_store);
|
||||
static DEVICE_ATTR_RW(blink);
|
||||
|
||||
static struct attribute *nasgpio_led_attrs[] = {
|
||||
&dev_attr_blink.attr,
|
||||
|
@ -478,7 +478,6 @@ ATTRIBUTE_GROUPS(nasgpio_led);
|
|||
|
||||
static int register_nasgpio_led(int led_nr)
|
||||
{
|
||||
int ret;
|
||||
struct nasgpio_led *nas_led = &nasgpio_leds[led_nr];
|
||||
struct led_classdev *led = get_classdev_for_led_nr(led_nr);
|
||||
|
||||
|
@ -489,11 +488,8 @@ static int register_nasgpio_led(int led_nr)
|
|||
led->brightness_set = nasgpio_led_set_brightness;
|
||||
led->blink_set = nasgpio_led_set_blink;
|
||||
led->groups = nasgpio_led_groups;
|
||||
ret = led_classdev_register(&nas_gpio_pci_dev->dev, led);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return led_classdev_register(&nas_gpio_pci_dev->dev, led);
|
||||
}
|
||||
|
||||
static void unregister_nasgpio_led(int led_nr)
|
||||
|
|
|
@ -155,8 +155,8 @@ static const char * const led_src_texts[] = {
|
|||
"soft",
|
||||
};
|
||||
|
||||
static ssize_t wm831x_status_src_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t src_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct wm831x_status *led = to_wm831x_status(led_cdev);
|
||||
|
@ -178,9 +178,9 @@ static ssize_t wm831x_status_src_show(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t wm831x_status_src_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
static ssize_t src_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct wm831x_status *led = to_wm831x_status(led_cdev);
|
||||
|
@ -197,7 +197,7 @@ static ssize_t wm831x_status_src_store(struct device *dev,
|
|||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(src, 0644, wm831x_status_src_show, wm831x_status_src_store);
|
||||
static DEVICE_ATTR_RW(src);
|
||||
|
||||
static struct attribute *wm831x_status_attrs[] = {
|
||||
&dev_attr_src.attr,
|
||||
|
|
|
@ -19,10 +19,8 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
|
|||
|
||||
void led_init_core(struct led_classdev *led_cdev);
|
||||
void led_stop_software_blink(struct led_classdev *led_cdev);
|
||||
void led_set_brightness_nopm(struct led_classdev *led_cdev,
|
||||
enum led_brightness value);
|
||||
void led_set_brightness_nosleep(struct led_classdev *led_cdev,
|
||||
enum led_brightness value);
|
||||
void led_set_brightness_nopm(struct led_classdev *led_cdev, unsigned int value);
|
||||
void led_set_brightness_nosleep(struct led_classdev *led_cdev, unsigned int value);
|
||||
ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t pos, size_t count);
|
||||
|
|
|
@ -85,6 +85,7 @@ static inline struct led_classdev_flash *lcdev_to_flcdev(
|
|||
return container_of(lcdev, struct led_classdev_flash, led_cdev);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS_FLASH)
|
||||
/**
|
||||
* led_classdev_flash_register_ext - register a new object of LED class with
|
||||
* init data and with support for flash LEDs
|
||||
|
@ -98,12 +99,6 @@ int led_classdev_flash_register_ext(struct device *parent,
|
|||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
static inline int led_classdev_flash_register(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{
|
||||
return led_classdev_flash_register_ext(parent, fled_cdev, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* led_classdev_flash_unregister - unregisters an object of led_classdev class
|
||||
* with support for flash LEDs
|
||||
|
@ -118,15 +113,44 @@ int devm_led_classdev_flash_register_ext(struct device *parent,
|
|||
struct led_init_data *init_data);
|
||||
|
||||
|
||||
void devm_led_classdev_flash_unregister(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int led_classdev_flash_register_ext(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev) {};
|
||||
static inline int devm_led_classdev_flash_register_ext(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void devm_led_classdev_flash_unregister(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{};
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_LEDS_CLASS_FLASH) */
|
||||
|
||||
static inline int led_classdev_flash_register(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{
|
||||
return led_classdev_flash_register_ext(parent, fled_cdev, NULL);
|
||||
}
|
||||
|
||||
static inline int devm_led_classdev_flash_register(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{
|
||||
return devm_led_classdev_flash_register_ext(parent, fled_cdev, NULL);
|
||||
}
|
||||
|
||||
void devm_led_classdev_flash_unregister(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev);
|
||||
|
||||
/**
|
||||
* led_set_flash_strobe - setup flash strobe
|
||||
* @fled_cdev: the flash LED to set strobe on
|
||||
|
|
|
@ -44,12 +44,6 @@ int led_classdev_multicolor_register_ext(struct device *parent,
|
|||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
static inline int led_classdev_multicolor_register(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{
|
||||
return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* led_classdev_multicolor_unregister - unregisters an object of led_classdev
|
||||
* class with support for multicolor LEDs
|
||||
|
@ -68,13 +62,6 @@ int devm_led_classdev_multicolor_register_ext(struct device *parent,
|
|||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data);
|
||||
|
||||
static inline int devm_led_classdev_multicolor_register(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{
|
||||
return devm_led_classdev_multicolor_register_ext(parent, mcled_cdev,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void devm_led_classdev_multicolor_unregister(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev);
|
||||
#else
|
||||
|
@ -83,27 +70,33 @@ static inline int led_classdev_multicolor_register_ext(struct device *parent,
|
|||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int led_classdev_multicolor_register(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{
|
||||
return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) {};
|
||||
static inline int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int devm_led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void devm_led_classdev_multicolor_unregister(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{};
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */
|
||||
|
||||
static inline int led_classdev_multicolor_register(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{
|
||||
return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL);
|
||||
}
|
||||
|
||||
static inline int devm_led_classdev_multicolor_register(struct device *parent,
|
||||
|
@ -113,9 +106,4 @@ static inline int devm_led_classdev_multicolor_register(struct device *parent,
|
|||
NULL);
|
||||
}
|
||||
|
||||
static inline void devm_led_classdev_multicolor_unregister(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{};
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */
|
||||
#endif /* _LINUX_MULTICOLOR_LEDS_H_INCLUDED */
|
||||
|
|
|
@ -63,8 +63,8 @@ struct led_hw_trigger_type {
|
|||
|
||||
struct led_classdev {
|
||||
const char *name;
|
||||
enum led_brightness brightness;
|
||||
enum led_brightness max_brightness;
|
||||
unsigned int brightness;
|
||||
unsigned int max_brightness;
|
||||
int flags;
|
||||
|
||||
/* Lower 16 bits reflect status */
|
||||
|
@ -253,8 +253,7 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev,
|
|||
* software blink timer that implements blinking when the
|
||||
* hardware doesn't. This function is guaranteed not to sleep.
|
||||
*/
|
||||
void led_set_brightness(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness);
|
||||
void led_set_brightness(struct led_classdev *led_cdev, unsigned int brightness);
|
||||
|
||||
/**
|
||||
* led_set_brightness_sync - set LED brightness synchronously
|
||||
|
@ -267,8 +266,7 @@ void led_set_brightness(struct led_classdev *led_cdev,
|
|||
*
|
||||
* Returns: 0 on success or negative error value on failure
|
||||
*/
|
||||
int led_set_brightness_sync(struct led_classdev *led_cdev,
|
||||
enum led_brightness value);
|
||||
int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value);
|
||||
|
||||
/**
|
||||
* led_update_brightness - update LED brightness
|
||||
|
@ -565,7 +563,7 @@ static inline void ledtrig_cpu(enum cpu_led_event evt)
|
|||
|
||||
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
|
||||
void led_classdev_notify_brightness_hw_changed(
|
||||
struct led_classdev *led_cdev, enum led_brightness brightness);
|
||||
struct led_classdev *led_cdev, unsigned int brightness);
|
||||
#else
|
||||
static inline void led_classdev_notify_brightness_hw_changed(
|
||||
struct led_classdev *led_cdev, enum led_brightness brightness) { }
|
||||
|
|
Загрузка…
Ссылка в новой задаче