From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 02C55318156 for ; Mon, 3 Nov 2025 16:30:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.52 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762187412; cv=none; b=hEwvv/r8uKe4U+6HFMPE5NznKcN5f3JVvifES1zI3552Qy7nPh5lqPMKymHjyknDchzY958KIR0saB1zXpl9/QlHG3psXv1ezHe99QDLOQ4WDfdKkB1YbDfpHu+brnArcq8Dd83dwl9SldAKrkvB7NWNwhU/UgSaIJl43S3LVlo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1762187412; c=relaxed/simple; bh=bEvIZ6b3ZPoI56NZVv/yoSC/UVLKTxOb/khDUfqNXZA=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=VZVKQcmClWhXn3UWJyNJ/o2QS+3sjInYy2WhJxLGxl87DkZ9A38F81WVvTjglXakwMZQx2mLRKwXHsnrG/NPxJ1uAW6koU9EOHgxT/mMu8WSS2kwKCfrJMFZVgtHhBoeOvt9O1JrGCO7z2Zz1qcCDSpVoFo8Aq/fMwLDrIN63CU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=riscstar.com; spf=pass smtp.mailfrom=riscstar.com; dkim=pass (2048-bit key) header.d=riscstar-com.20230601.gappssmtp.com header.i=@riscstar-com.20230601.gappssmtp.com header.b=F4kAPPtc; arc=none smtp.client-ip=209.85.128.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=riscstar.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=riscstar.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=riscstar-com.20230601.gappssmtp.com header.i=@riscstar-com.20230601.gappssmtp.com header.b="F4kAPPtc" Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-4711810948aso32901395e9.2 for ; Mon, 03 Nov 2025 08:30:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=riscstar-com.20230601.gappssmtp.com; s=20230601; t=1762187408; x=1762792208; darn=vger.kernel.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=84F0QgR4+jds+lqPjKDSBSqClUiU/2oz/AngUspSNH8=; b=F4kAPPtcZZVu3wZgcaCHUtPsottZ6u5GzyBptAODlIGAnm6CnH8jVIRrOuWQQhFnMa QMwF2YkaQbr7Ueoos65dmmiVbIAiWoHhovBuJtX87K7P6salpJ4umMAuQnoKQwmDKJrQ Q+e1h9Lz5t2GBN+zV5niKSJMRype73Dfc20Fi89W7AL4zRfpOwcXwBsLxLukaFDdHVPU aNlarHPqZ18b0cchO1o7jyP9gfnTpuxsJjslNYHo83/O3UmMOds/HqnOlysK32c2VhLJ x5Zu2Rbiq4Xb/qUlSZ4IoxBwsz05zqNLTHPWJf4Om2J1HZVT2WSd9aAU+zitlHijKgeX Hs3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762187408; x=1762792208; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=84F0QgR4+jds+lqPjKDSBSqClUiU/2oz/AngUspSNH8=; b=GOhd5bWrFKY28TCIdTF0YYwC2OZ/Z6ZqdMCG6nhQDtOE57vvddnOiyrFTJD+FXiPiO OupieU6K/sJOFctfs2zeIJXWMS0Sl4VU9IOdRL0LGzo7J9cChISezKpMJhFzk0CLlsAf TFz4KjppIjUrhR36DnfMP2qW3Lj204yCC7i5n8uiVeZ4F6ingMQiu7xwVAwUw3f72Z36 BizGENdS/jPMyKu7/QNINEpajCAbEUT438MeidVWnLRajhD75jKm6CYxRYIIdDnOXycK nsfe3jibGWZR0Wj4l6XHrHXjZMHyFHvfCjp9RaLiG0cxfyBndzbPKTDRupVhNoctDvwl 9EmQ== X-Forwarded-Encrypted: i=1; AJvYcCWTv3zqQyP0X/xdl4lBdM7GowPGEW5ylTnSsx69hl6/iN2jWAZFpVX9iZH5EKoWAmVrxuG10biOYdi6kKQ=@vger.kernel.org X-Gm-Message-State: AOJu0YyVHbNmRzN0l3r2UuWaJaefh9Zm2scbqdNvJLKG/v6QjbvYHUna XOKs43vVC+XsR4IW90TrNZCfINfIfggBQsFfEae69zJ6JTiM7ByS4Ph0hc97X2CC2LY= X-Gm-Gg: ASbGnctIj01MZsUKf8W3tGmTR1j+hknA+wq7+dWhu3HDhcV7m/ZdIanJliDTDwPFRY9 Mjtf5xsSPf30gN0z68fqEpV63RvKs9hlimsSdAaumqX3xaSVhO1WjDladhHFJNb1RVsO/2Mx9cd W8G/C5adyTqWIzE51glRjGnZbcRiRLUi9ffGPqZQC3EQjuuBDD90O3M2DWC4nu6pXWH0o+aH7dz y6IDpk/JWQkB6SXIugHKcCyvazTGL83lMz7IkF3n/IP6Tu+un9LlJ1YtT2HYx6oOfd9IgEVyBv9 xCT2kXnqXThweNjhs+UGBCPf9RS5aXE2LxuFJGgUPXnEDyVp45FFtVMQA6Pa5GVj5SS2lx5HkXL i/mjDwj8Zq++VjCaC4aBR0rRBG57iKBaDIfS/xwu1drwWW0JPZrIQvXPU/V+fFCw/1nUFEbP7Bn soJDxTgP01NsFMxAyO5/cOtERbVL7alVNHLvFwfS/x07ufu9rLI/hV2GwkHb+uukod4nn/VA== X-Google-Smtp-Source: AGHT+IF/kGs5jea5FahI1rZFZGhV1Eh4Fy1sLd4uiFaXvIWVe3vieePJLCoPtu7DkEqIeKjkJL2wCg== X-Received: by 2002:a05:600c:83ce:b0:471:989:9d85 with SMTP id 5b1f17b1804b1-47730871fa6mr144953305e9.19.1762187406607; Mon, 03 Nov 2025 08:30:06 -0800 (PST) Received: from aspen.lan (aztw-34-b2-v4wan-166919-cust780.vm26.cable.virginm.net. [82.37.195.13]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-429d1061efasm9781324f8f.24.2025.11.03.08.30.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Nov 2025 08:30:05 -0800 (PST) Date: Mon, 3 Nov 2025 16:31:35 +0000 From: Daniel Thompson To: Junjie Cao Cc: Lee Jones , Daniel Thompson , Jingoo Han , Pavel Machek , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Helge Deller , dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fbdev@vger.kernel.org, Pengyu Luo Subject: Re: [PATCH v2 2/2] backlight: aw99706: Add support for Awinic AW99706 backlight Message-ID: References: <20251103110648.878325-1-caojunjie650@gmail.com> <20251103110648.878325-3-caojunjie650@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20251103110648.878325-3-caojunjie650@gmail.com> On Mon, Nov 03, 2025 at 07:06:48PM +0800, Junjie Cao wrote: > From: Pengyu Luo > > Add support for Awinic AW99706 backlight, which can be found in > tablet and notebook backlight, one case is the Lenovo Legion Y700 > Gen4. This driver refers to the official datasheets and android > driver, they can be found in [1]. > > [1] https://www.awinic.com/en/productDetail/AW99706QNR > > Signed-off-by: Pengyu Luo > Signed-off-by: Junjie Cao > --- > Changes in v2: > - add handler for max-brightness and default-brightness > - use proper units for properties (Krzysztof) > - drop non-fixed properties (Krzysztof) > - include default values in the aw99706_dt_props table (Daniel) > - warn when a property value from DT is invalid (Daniel) > - drop warning when optional properties are missing (Daniel) > - add a function pointer into the aw99706_dt_props table to handle lookup (Daniel) > - use a lookup function instead of hardcoding the formula for the iLED max (Daniel) > - move BL enalbe handler into aw99706_update_brightness (Daniel) > - Link to v1: https://lore.kernel.org/linux-leds/20251026123923.1531727-3-caojunjie650@gmail.com Thanks for the changes. I'm afraid I don't like encoding the `shift` in the DT properties table. Caching something that is so easy to recalculate makes no sense to me. See below: > +struct aw99706_dt_prop { > + const char * const name; > + int (*lookup)(const struct aw99706_dt_prop *prop, u32 dt_val, u8 *val); > + const u32 * const lookup_tbl; > + u8 tbl_size; > + u8 reg; > + u8 mask; > + u8 shift; There should bee no need to record `shift` here. It's just a duplicating information already held in `mask`. > + u32 def_val; > +}; > + > +static int aw99706_dt_property_lookup(const struct aw99706_dt_prop *prop, > + u32 dt_val, u8 *val) > +{ > + int i; > + > + if (!prop->lookup_tbl) { > + *val = dt_val; > + return 0; > + } > + > + for (i = 0; i < prop->tbl_size; i++) > + if (prop->lookup_tbl[i] == dt_val) > + break; > + > + *val = i; > + > + return i == prop->tbl_size ? -1 : 0; > +} > + > +#define MIN_ILED_MAX 5000 > +#define MAX_ILED_MAX 50000 > +#define STEP_ILED_MAX 500 > + > +static int > +aw99706_dt_property_iled_max_convert(const struct aw99706_dt_prop *prop, > + u32 dt_val, u8 *val) > +{ > + if (dt_val > MAX_ILED_MAX || dt_val < MIN_ILED_MAX) > + return -1; > + > + *val = (dt_val - MIN_ILED_MAX) / STEP_ILED_MAX; > + > + return (dt_val - MIN_ILED_MAX) % STEP_ILED_MAX; > +} > + > +static const struct aw99706_dt_prop aw99706_dt_props[] = { > + { > + "awinic,dim-mode", aw99706_dt_property_lookup, > + NULL, 0, > + AW99706_CFG0_REG, > + AW99706_DIM_MODE_MASK, __builtin_ctz(AW99706_DIM_MODE_MASK), These __builtin_ctz() calls shouldn't be in the lookup table (if they are not in the lookup table then can never be inconsistant with the mask). > + 1, > + }, > + { > + "awinic,ramp-ctl", aw99706_dt_property_lookup, > + NULL, 0, > + AW99706_CFG6_REG, > + AW99706_RAMP_CTL_MASK, __builtin_ctz(AW99706_RAMP_CTL_MASK), > + 2, > + }, > +}; > + > +struct reg_init_data { > + u8 reg; > + u8 mask; > + u8 val; > +}; > + > +static struct reg_init_data reg_init_tbl[ARRAY_SIZE(aw99706_dt_props)]; > + > +static void aw99706_dt_parse(struct aw99706_device *aw, > + struct backlight_properties *bl_props) > +{ > + const struct aw99706_dt_prop *prop; > + u32 dt_val; > + int ret, i; > + u8 val; > + > + for (i = 0; i < ARRAY_SIZE(aw99706_dt_props); i++) { > + prop = &aw99706_dt_props[i]; > + ret = device_property_read_u32(aw->dev, prop->name, &dt_val); > + if (ret < 0) > + dt_val = prop->def_val; > + > + if (prop->lookup(prop, dt_val, &val)) { > + dev_warn(aw->dev, "invalid value %d for property %s, using default value %d\n", > + dt_val, prop->name, prop->def_val); > + > + prop->lookup(prop, prop->def_val, &val); > + } > + > + reg_init_tbl[i].reg = prop->reg; > + reg_init_tbl[i].mask = prop->mask; > + reg_init_tbl[i].val = val << prop->shift; Can't you just use FIELD_PREP() to set val (either here or at the point the init table is consumed)? That why there's no ffs() or clz() at all. > + } > + > + aw->init_tbl = reg_init_tbl; > + aw->init_tbl_size = ARRAY_SIZE(reg_init_tbl); Copying a pointer to a single instance static data buffer into a dynamically allocated data structure isn't right. You should include the init table as part of `struct aw99706_device`. > + > + bl_props->brightness = AW99706_MAX_BRT_LVL >> 1; > + bl_props->max_brightness = AW99706_MAX_BRT_LVL; > + device_property_read_u32(aw->dev, "default-brightness", > + &bl_props->brightness); > + device_property_read_u32(aw->dev, "max-brightness", > + &bl_props->max_brightness); > + > + if (bl_props->max_brightness > AW99706_MAX_BRT_LVL) > + bl_props->max_brightness = AW99706_MAX_BRT_LVL; > + > + if (bl_props->brightness > bl_props->max_brightness) > + bl_props->brightness = bl_props->max_brightness; > +} > + > +static int aw99706_hw_init(struct aw99706_device *aw) > +{ > + int ret, i; > + > + gpiod_set_value_cansleep(aw->hwen_gpio, 1); > + > + for (i = 0; i < aw->init_tbl_size; i++) { > + ret = aw99706_i2c_update_bits(aw, aw->init_tbl[i].reg, > + aw->init_tbl[i].mask, > + aw->init_tbl[i].val); > + if (ret < 0) { > + dev_err(aw->dev, "Failed to write init data %d\n", ret); > + return ret; > + } > + } > + > + return 0; > +} > + > +static int aw99706_bl_enable(struct aw99706_device *aw, bool en) > +{ > + int ret; > + u8 val; > + > + FIELD_MODIFY(AW99706_BACKLIGHT_EN_MASK, &val, en); This should use FIELD_PREP() not FIELD_MODIFY(); > + ret = aw99706_i2c_update_bits(aw, AW99706_CFGD_REG, > + AW99706_BACKLIGHT_EN_MASK, val); > + if (ret) > + dev_err(aw->dev, "Failed to enable backlight!\n"); > + > + return ret; > +} Daniel.