Received: by 2002:a05:7412:b995:b0:f9:9502:5bb8 with SMTP id it21csp2888192rdb; Tue, 26 Dec 2023 08:14:34 -0800 (PST) X-Google-Smtp-Source: AGHT+IG6CJJ27pkavd8ElY6LXz62uRI4QkKFTggGg7ztH2vRaW/cAPZp+DhakrURUgKfsABntpXX X-Received: by 2002:a05:6a20:1584:b0:194:d635:2557 with SMTP id h4-20020a056a20158400b00194d6352557mr9869925pzj.101.1703607274070; Tue, 26 Dec 2023 08:14:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1703607274; cv=none; d=google.com; s=arc-20160816; b=hN7Q0z8zkZA6fLQftfzJ6jPewKX5Bb31YApYVYF/iG2GeYZjxW5Qx5yMXEC2GqYxm1 SI3AwEXP1LfZZOIAk52g2eEsjsT4vpZxoG2io/8GSIWL2gtVaK7E1gtGLRC1kgx0RNbq 7tR0/mDBIqXCICu+2NYE1bGtam8cJzNLwQUKQXo6dTwKAZjjbHHI/NbXZi06xf/3qqxw WSyGx2aQXE/pCmC5uwpftzLMwFNZCHaAd+gsWzVAWlWNr6bELsbgV4rfm/KV7/JdPz3G ve5UXUnPe8qVSO6jgPXRZlGpwaPL6N8+UMpSjKyysqJHhONT3AyY5GTS4WuMjdYpSUJC Vq3Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :subject:cc:to:from:date:dkim-signature; bh=xg2uWClu5JMdgVCwL3d7XHA/CjZ32md7WpKcSce9Ero=; fh=31tsjd9K+scLMmPWMjfUopVpoYsgHdl6ScL9fHZFAuM=; b=PWd3m1r5aCtQelVNB9sWjz0MVNryk6bd+iTQUM5ptUoyutQFbF3Pp7Y39yLb945DXT 79jtu87ZnY/2NVW02Fu7BjQVUn1sraoNZ9mwdQ8ohT5uGV3VbNLTL6vG1YxMGXyzbRTt Daru4pgKwDS3h8LHeS6/vSQfInX5LB/1ueOnBaaeAO+nOLS0ADG4wDlSeO4vCzzD+zdg 9ZCJ/syRc0AWieNO/eFQS2Vmibc3T/UzLZJUuU+dd6uWismPMLtbL1f2S9yqGS8sAYE9 i8jAIzrVapLl39ohjMMLBxwhnGfR9Xzcl5KixQLfV9hU/eqymz3v/BjvJl9tM7Fg24Sb 0POQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=epxO4hWz; spf=pass (google.com: domain of linux-kernel+bounces-11570-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-11570-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [2604:1380:45e3:2400::1]) by mx.google.com with ESMTPS id x67-20020a636346000000b005ce0160641fsi6004736pgb.551.2023.12.26.08.14.33 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 Dec 2023 08:14:34 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-11570-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) client-ip=2604:1380:45e3:2400::1; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=epxO4hWz; spf=pass (google.com: domain of linux-kernel+bounces-11570-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-11570-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id A7E42282EB0 for ; Tue, 26 Dec 2023 16:14:33 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 243FB4F606; Tue, 26 Dec 2023 16:14:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="epxO4hWz" X-Original-To: linux-kernel@vger.kernel.org Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51B784F5E3; Tue, 26 Dec 2023 16:14:24 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3A8F3C433C8; Tue, 26 Dec 2023 16:14:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1703607263; bh=X17uhTrvUB4QI3u0hbcYr4MU2xf6/bp+rJzgV0J90LI=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=epxO4hWzji58L5LQDUuSA9/qCgSbnWFNEqV2gMT8eeVzg9uzDWdv3oEg+YmGzbLgA UY3oNsiwNGXk8nsFKxr8v3Z07+bYs+sSBRhZKqazF9yHn/3vQpOyyS7b3990zZ1AhE Rn5l0EW3BZ7BU1UQc8Qesyl0+2KTNAJJ3YbSIaXqi34anwYZ5CHNfht7n2EGlY0VYd lKfa3DB9L9DDF2sNap4XDL26UlzMZhYKzZMAPTZ3DeNGl0Zrl009jyn7sfTaUKv4js 6aNilQdolre7XMUHHNoiDel+jVtkWBpwtPDsbQ2wA1bRS+p+4d/vtXuvZH0VSVl/wO xPPis0p6qFkAQ== Date: Tue, 26 Dec 2023 16:14:14 +0000 From: Jonathan Cameron To: Javier Carrasco Cc: Christian Eggers , Lars-Peter Clausen , Rob Herring , Krzysztof Kozlowski , Conor Dooley , linux-iio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH 2/2] io: light: as73211: add support for as7331 Message-ID: <20231226161414.47d5171e@jic23-huawei> In-Reply-To: <20231220-as7331-v1-2-745b73c27703@gmail.com> References: <20231220-as7331-v1-0-745b73c27703@gmail.com> <20231220-as7331-v1-2-745b73c27703@gmail.com> X-Mailer: Claws Mail 4.2.0 (GTK 3.24.38; x86_64-pc-linux-gnu) 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-Transfer-Encoding: 7bit On Sat, 23 Dec 2023 11:46:14 +0100 Javier Carrasco wrote: > The AMS AS7331 is a UV light sensor with three channels: UVA, UVB and > UVC (also known as deep UV and referenced as DUV in the iio core). > Its internal structure and forming blocks are practically identical to > the ones the AS73211 contains: API, internal DAC, I2C interface and > registers, measurement modes, number of channels and pinout. > > The only difference between them is the photodiodes used to acquire > light, which means that only some modifications are required to add > support for the AS7331 in the existing driver. > > The temperature channel is identical for both devices and only the > channel modifiers of the IIO_INTENSITY channels need to account for the > device type. > > The scale values have been obtained from the chapter "7.5 Transfer > Function" of the official datasheet[1] for the configuration chosen as > basis (Nclk = 1024 and GAIN = 1). Those values keep the units from the > datasheet (nW/cm^2) because no additional upscaling is required to work > with integers as opposed to the scale values for the AS73211. Actually > if the same upscaling is used, their values will not fit in 4-byte > integers without affecting its sign. > > Instead, the AS7331-specific function to retrieve the intensity scales > returns decimal values as listed in the datasheet for every > combination of GAIN and Nclk, keeping the unit as nW/cm^2. > To achieve that, a fractional value is returned. > The AS73211 scales use nW/m^2 units to work with integers that fit in > a 4-byte integer, and in that case there is no need to modify the value > type. No need, but in general it's a nice to have if it works well with IIO_VAL_FRACTIONAL because in kernel users (there aren't really any for light sensors) can handle the maths better if they need to apply other scalings etc. > > Add a new device-specific data structure to account for the device > differences: channel types and scale of LSB per channel. A may not be worth doing it in this case, but usual approach to refactoring a driver to allow support of additional devices is to do it in two steps. 1) Refactor with no new support - so should be no operational changes. 2) Add the new device support. > > [1] https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf > > Signed-off-by: Javier Carrasco ... > diff --git a/drivers/iio/light/as73211.c b/drivers/iio/light/as73211.c > index ec97a3a46839..d53a0ae5255a 100644 > --- a/drivers/iio/light/as73211.c > +++ b/drivers/iio/light/as73211.c ... > > +static const struct iio_chan_spec as7331_channels[] = { > + { > + .type = IIO_TEMP, > + .info_mask_separate = > + BIT(IIO_CHAN_INFO_RAW) | > + BIT(IIO_CHAN_INFO_OFFSET) | > + BIT(IIO_CHAN_INFO_SCALE), > + .address = AS73211_OUT_TEMP, > + .scan_index = AS73211_SCAN_INDEX_TEMP, > + .scan_type = { > + .sign = 'u', > + .realbits = 16, > + .storagebits = 16, > + .endianness = IIO_LE, > + } > + }, > + AS73211_COLOR_CHANNEL(LIGHT_UVA, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1), > + AS73211_COLOR_CHANNEL(LIGHT_UVB, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2), > + AS73211_COLOR_CHANNEL(LIGHT_DUV, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3), > + IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS), > +}; > + > static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data) > { > /* > @@ -316,6 +361,50 @@ static int as73211_req_data(struct as73211_data *data) > return 0; > } > > +static int as73211_intensity_scale(struct as73211_data *data, int chan, int *val, int *val2) > +{ > + unsigned int scale; > + > + switch (chan) { > + case IIO_MOD_X: > + scale = AS73211_SCALE_X; > + break; > + case IIO_MOD_Y: > + scale = AS73211_SCALE_Y; > + break; > + case IIO_MOD_Z: > + scale = AS73211_SCALE_Z; > + break; > + default: > + return -EINVAL; > + } > + scale /= as73211_gain(data); > + scale /= as73211_integration_time_1024cyc(data); > + *val = scale; > + > + return IIO_VAL_INT; Obviously it's really a question about the original code but why not use IIO_VAL_FRACTIONAL here as well as below? Superficially looks like it should work in a similar fashion. If not, perhaps a comment here somewhere? > +} > + > +static int as7331_intensity_scale(struct as73211_data *data, int chan, int *val, int *val2) > +{ > + switch (chan) { > + case IIO_MOD_LIGHT_UVA: > + *val = AS7331_SCALE_UVA; > + break; > + case IIO_MOD_LIGHT_UVB: > + *val = AS7331_SCALE_UVB; > + break; > + case IIO_MOD_LIGHT_DUV: > + *val = AS7331_SCALE_UVC; > + break; > + default: > + return -EINVAL; > + } > + *val2 = as73211_gain(data) * as73211_integration_time_1024cyc(data); > + > + return IIO_VAL_FRACTIONAL; > +} > + > static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, > int *val, int *val2, long mask) > { > @@ -355,30 +444,12 @@ static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec cons > *val2 = AS73211_SCALE_TEMP_MICRO; > return IIO_VAL_INT_PLUS_MICRO; > > - case IIO_INTENSITY: { > - unsigned int scale; > - > - switch (chan->channel2) { > - case IIO_MOD_X: > - scale = AS73211_SCALE_X; > - break; > - case IIO_MOD_Y: > - scale = AS73211_SCALE_Y; > - break; > - case IIO_MOD_Z: > - scale = AS73211_SCALE_Z; > - break; > - default: > - return -EINVAL; > - } > - scale /= as73211_gain(data); > - scale /= as73211_integration_time_1024cyc(data); > - *val = scale; > - return IIO_VAL_INT; > + case IIO_INTENSITY: > + return data->spec_dev->intensity_scale(data, chan->channel2, val, val2); Where it doesn't hurt readability, I'd prefer we stayed as close to 80 chars or below as reasonably possible. So here wrap so val, val2); is on the next line. > > default: > return -EINVAL; > - }} > + } > > case IIO_CHAN_INFO_SAMP_FREQ: > /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */ > @@ -676,13 +747,20 @@ static int as73211_probe(struct i2c_client *client) > i2c_set_clientdata(client, indio_dev); > data->client = client; > > + if (dev_fwnode(dev)) > + data->spec_dev = device_get_match_data(dev); > + else > + data->spec_dev = i2c_get_match_data(client); Take a look at how i2c_get_match_data() is defined... https://elixir.bootlin.com/linux/latest/source/drivers/i2c/i2c-core-base.c#L117 and in particular what it calls first.. > + if (!data->spec_dev) > + return -EINVAL; > + > mutex_init(&data->mutex); > init_completion(&data->completion); > > indio_dev->info = &as73211_info; > indio_dev->name = AS73211_DRV_NAME; > - indio_dev->channels = as73211_channels; > - indio_dev->num_channels = ARRAY_SIZE(as73211_channels); > + indio_dev->channels = data->spec_dev->channel; > + indio_dev->num_channels = data->spec_dev->num_channels; > indio_dev->modes = INDIO_DIRECT_MODE; >