xref: /openbmc/linux/drivers/iio/light/rohm-bu27008.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
141ff93d1SMatti Vaittinen // SPDX-License-Identifier: GPL-2.0-only
241ff93d1SMatti Vaittinen /*
3*fdb48f9dSMatti Vaittinen  * ROHM Colour Sensor driver for
4*fdb48f9dSMatti Vaittinen  * - BU27008 RGBC sensor
5*fdb48f9dSMatti Vaittinen  * - BU27010 RGBC + Flickering sensor
641ff93d1SMatti Vaittinen  *
741ff93d1SMatti Vaittinen  * Copyright (c) 2023, ROHM Semiconductor.
841ff93d1SMatti Vaittinen  */
941ff93d1SMatti Vaittinen 
1041ff93d1SMatti Vaittinen #include <linux/bitfield.h>
1141ff93d1SMatti Vaittinen #include <linux/bitops.h>
1241ff93d1SMatti Vaittinen #include <linux/device.h>
1341ff93d1SMatti Vaittinen #include <linux/i2c.h>
1441ff93d1SMatti Vaittinen #include <linux/interrupt.h>
1541ff93d1SMatti Vaittinen #include <linux/module.h>
1641ff93d1SMatti Vaittinen #include <linux/property.h>
1741ff93d1SMatti Vaittinen #include <linux/regmap.h>
1841ff93d1SMatti Vaittinen #include <linux/regulator/consumer.h>
1941ff93d1SMatti Vaittinen #include <linux/units.h>
2041ff93d1SMatti Vaittinen 
2141ff93d1SMatti Vaittinen #include <linux/iio/iio.h>
2241ff93d1SMatti Vaittinen #include <linux/iio/iio-gts-helper.h>
2341ff93d1SMatti Vaittinen #include <linux/iio/trigger.h>
2441ff93d1SMatti Vaittinen #include <linux/iio/trigger_consumer.h>
2541ff93d1SMatti Vaittinen #include <linux/iio/triggered_buffer.h>
2641ff93d1SMatti Vaittinen 
27*fdb48f9dSMatti Vaittinen /*
28*fdb48f9dSMatti Vaittinen  * A word about register address and mask definitions.
29*fdb48f9dSMatti Vaittinen  *
30*fdb48f9dSMatti Vaittinen  * At a quick glance to the data-sheet register tables, the BU27010 has all the
31*fdb48f9dSMatti Vaittinen  * registers that the BU27008 has. On top of that the BU27010 adds couple of new
32*fdb48f9dSMatti Vaittinen  * ones.
33*fdb48f9dSMatti Vaittinen  *
34*fdb48f9dSMatti Vaittinen  * So, all definitions BU27008_REG_* are there also for BU27010 but none of the
35*fdb48f9dSMatti Vaittinen  * BU27010_REG_* are present on BU27008. This makes sense as BU27010 just adds
36*fdb48f9dSMatti Vaittinen  * some features (Flicker FIFO, more power control) on top of the BU27008.
37*fdb48f9dSMatti Vaittinen  *
38*fdb48f9dSMatti Vaittinen  * Unfortunately, some of the wheel has been re-invented. Even though the names
39*fdb48f9dSMatti Vaittinen  * of the registers have stayed the same, pretty much all of the functionality
40*fdb48f9dSMatti Vaittinen  * provided by the registers has changed place. Contents of all MODE_CONTROL
41*fdb48f9dSMatti Vaittinen  * registers on BU27008 and BU27010 are different.
42*fdb48f9dSMatti Vaittinen  *
43*fdb48f9dSMatti Vaittinen  * Chip-specific mapping from register addresses/bits to functionality is done
44*fdb48f9dSMatti Vaittinen  * in bu27_chip_data structures.
45*fdb48f9dSMatti Vaittinen  */
4641ff93d1SMatti Vaittinen #define BU27008_REG_SYSTEM_CONTROL	0x40
4741ff93d1SMatti Vaittinen #define BU27008_MASK_SW_RESET		BIT(7)
4841ff93d1SMatti Vaittinen #define BU27008_MASK_PART_ID		GENMASK(5, 0)
4941ff93d1SMatti Vaittinen #define BU27008_ID			0x1a
5041ff93d1SMatti Vaittinen #define BU27008_REG_MODE_CONTROL1	0x41
5141ff93d1SMatti Vaittinen #define BU27008_MASK_MEAS_MODE		GENMASK(2, 0)
5241ff93d1SMatti Vaittinen #define BU27008_MASK_CHAN_SEL		GENMASK(3, 2)
5341ff93d1SMatti Vaittinen 
5441ff93d1SMatti Vaittinen #define BU27008_REG_MODE_CONTROL2	0x42
5541ff93d1SMatti Vaittinen #define BU27008_MASK_RGBC_GAIN		GENMASK(7, 3)
5641ff93d1SMatti Vaittinen #define BU27008_MASK_IR_GAIN_LO		GENMASK(2, 0)
5741ff93d1SMatti Vaittinen #define BU27008_SHIFT_IR_GAIN		3
5841ff93d1SMatti Vaittinen 
5941ff93d1SMatti Vaittinen #define BU27008_REG_MODE_CONTROL3	0x43
6041ff93d1SMatti Vaittinen #define BU27008_MASK_VALID		BIT(7)
6141ff93d1SMatti Vaittinen #define BU27008_MASK_INT_EN		BIT(1)
6241ff93d1SMatti Vaittinen #define BU27008_INT_EN			BU27008_MASK_INT_EN
6341ff93d1SMatti Vaittinen #define BU27008_INT_DIS			0
6441ff93d1SMatti Vaittinen #define BU27008_MASK_MEAS_EN		BIT(0)
6541ff93d1SMatti Vaittinen #define BU27008_MEAS_EN			BIT(0)
6641ff93d1SMatti Vaittinen #define BU27008_MEAS_DIS		0
6741ff93d1SMatti Vaittinen 
6841ff93d1SMatti Vaittinen #define BU27008_REG_DATA0_LO		0x50
6941ff93d1SMatti Vaittinen #define BU27008_REG_DATA1_LO		0x52
7041ff93d1SMatti Vaittinen #define BU27008_REG_DATA2_LO		0x54
7141ff93d1SMatti Vaittinen #define BU27008_REG_DATA3_LO		0x56
7241ff93d1SMatti Vaittinen #define BU27008_REG_DATA3_HI		0x57
7341ff93d1SMatti Vaittinen #define BU27008_REG_MANUFACTURER_ID	0x92
7441ff93d1SMatti Vaittinen #define BU27008_REG_MAX BU27008_REG_MANUFACTURER_ID
7541ff93d1SMatti Vaittinen 
76*fdb48f9dSMatti Vaittinen /* BU27010 specific definitions */
77*fdb48f9dSMatti Vaittinen 
78*fdb48f9dSMatti Vaittinen #define BU27010_MASK_SW_RESET		BIT(7)
79*fdb48f9dSMatti Vaittinen #define BU27010_ID			0x1b
80*fdb48f9dSMatti Vaittinen #define BU27010_REG_POWER		0x3e
81*fdb48f9dSMatti Vaittinen #define BU27010_MASK_POWER		BIT(0)
82*fdb48f9dSMatti Vaittinen 
83*fdb48f9dSMatti Vaittinen #define BU27010_REG_RESET		0x3f
84*fdb48f9dSMatti Vaittinen #define BU27010_MASK_RESET		BIT(0)
85*fdb48f9dSMatti Vaittinen #define BU27010_RESET_RELEASE		BU27010_MASK_RESET
86*fdb48f9dSMatti Vaittinen 
87*fdb48f9dSMatti Vaittinen #define BU27010_MASK_MEAS_EN		BIT(1)
88*fdb48f9dSMatti Vaittinen 
89*fdb48f9dSMatti Vaittinen #define BU27010_MASK_CHAN_SEL		GENMASK(7, 6)
90*fdb48f9dSMatti Vaittinen #define BU27010_MASK_MEAS_MODE		GENMASK(5, 4)
91*fdb48f9dSMatti Vaittinen #define BU27010_MASK_RGBC_GAIN		GENMASK(3, 0)
92*fdb48f9dSMatti Vaittinen 
93*fdb48f9dSMatti Vaittinen #define BU27010_MASK_DATA3_GAIN		GENMASK(7, 6)
94*fdb48f9dSMatti Vaittinen #define BU27010_MASK_DATA2_GAIN		GENMASK(5, 4)
95*fdb48f9dSMatti Vaittinen #define BU27010_MASK_DATA1_GAIN		GENMASK(3, 2)
96*fdb48f9dSMatti Vaittinen #define BU27010_MASK_DATA0_GAIN		GENMASK(1, 0)
97*fdb48f9dSMatti Vaittinen 
98*fdb48f9dSMatti Vaittinen #define BU27010_MASK_FLC_MODE		BIT(7)
99*fdb48f9dSMatti Vaittinen #define BU27010_MASK_FLC_GAIN		GENMASK(4, 0)
100*fdb48f9dSMatti Vaittinen 
101*fdb48f9dSMatti Vaittinen #define BU27010_REG_MODE_CONTROL4	0x44
102*fdb48f9dSMatti Vaittinen /* If flicker is ever to be supported the IRQ must be handled as a field */
103*fdb48f9dSMatti Vaittinen #define BU27010_IRQ_DIS_ALL		GENMASK(1, 0)
104*fdb48f9dSMatti Vaittinen #define BU27010_DRDY_EN			BIT(0)
105*fdb48f9dSMatti Vaittinen #define BU27010_MASK_INT_SEL		GENMASK(1, 0)
106*fdb48f9dSMatti Vaittinen 
107*fdb48f9dSMatti Vaittinen #define BU27010_REG_MODE_CONTROL5	0x45
108*fdb48f9dSMatti Vaittinen #define BU27010_MASK_RGB_VALID		BIT(7)
109*fdb48f9dSMatti Vaittinen #define BU27010_MASK_FLC_VALID		BIT(6)
110*fdb48f9dSMatti Vaittinen #define BU27010_MASK_WAIT_EN		BIT(3)
111*fdb48f9dSMatti Vaittinen #define BU27010_MASK_FIFO_EN		BIT(2)
112*fdb48f9dSMatti Vaittinen #define BU27010_MASK_RGB_EN		BIT(1)
113*fdb48f9dSMatti Vaittinen #define BU27010_MASK_FLC_EN		BIT(0)
114*fdb48f9dSMatti Vaittinen 
115*fdb48f9dSMatti Vaittinen #define BU27010_REG_DATA_FLICKER_LO	0x56
116*fdb48f9dSMatti Vaittinen #define BU27010_MASK_DATA_FLICKER_HI	GENMASK(2, 0)
117*fdb48f9dSMatti Vaittinen #define BU27010_REG_FLICKER_COUNT	0x5a
118*fdb48f9dSMatti Vaittinen #define BU27010_REG_FIFO_LEVEL_LO	0x5b
119*fdb48f9dSMatti Vaittinen #define BU27010_MASK_FIFO_LEVEL_HI	BIT(0)
120*fdb48f9dSMatti Vaittinen #define BU27010_REG_FIFO_DATA_LO	0x5d
121*fdb48f9dSMatti Vaittinen #define BU27010_REG_FIFO_DATA_HI	0x5e
122*fdb48f9dSMatti Vaittinen #define BU27010_MASK_FIFO_DATA_HI	GENMASK(2, 0)
123*fdb48f9dSMatti Vaittinen #define BU27010_REG_MANUFACTURER_ID	0x92
124*fdb48f9dSMatti Vaittinen #define BU27010_REG_MAX BU27010_REG_MANUFACTURER_ID
125*fdb48f9dSMatti Vaittinen 
12641ff93d1SMatti Vaittinen /**
12741ff93d1SMatti Vaittinen  * enum bu27008_chan_type - BU27008 channel types
12841ff93d1SMatti Vaittinen  * @BU27008_RED:	Red channel. Always via data0.
12941ff93d1SMatti Vaittinen  * @BU27008_GREEN:	Green channel. Always via data1.
13041ff93d1SMatti Vaittinen  * @BU27008_BLUE:	Blue channel. Via data2 (when used).
13141ff93d1SMatti Vaittinen  * @BU27008_CLEAR:	Clear channel. Via data2 or data3 (when used).
13241ff93d1SMatti Vaittinen  * @BU27008_IR:		IR channel. Via data3 (when used).
13341ff93d1SMatti Vaittinen  * @BU27008_NUM_CHANS:	Number of channel types.
13441ff93d1SMatti Vaittinen  */
13541ff93d1SMatti Vaittinen enum bu27008_chan_type {
13641ff93d1SMatti Vaittinen 	BU27008_RED,
13741ff93d1SMatti Vaittinen 	BU27008_GREEN,
13841ff93d1SMatti Vaittinen 	BU27008_BLUE,
13941ff93d1SMatti Vaittinen 	BU27008_CLEAR,
14041ff93d1SMatti Vaittinen 	BU27008_IR,
14141ff93d1SMatti Vaittinen 	BU27008_NUM_CHANS
14241ff93d1SMatti Vaittinen };
14341ff93d1SMatti Vaittinen 
14441ff93d1SMatti Vaittinen /**
14541ff93d1SMatti Vaittinen  * enum bu27008_chan - BU27008 physical data channel
14641ff93d1SMatti Vaittinen  * @BU27008_DATA0:		Always red.
14741ff93d1SMatti Vaittinen  * @BU27008_DATA1:		Always green.
14841ff93d1SMatti Vaittinen  * @BU27008_DATA2:		Blue or clear.
14941ff93d1SMatti Vaittinen  * @BU27008_DATA3:		IR or clear.
15041ff93d1SMatti Vaittinen  * @BU27008_NUM_HW_CHANS:	Number of physical channels
15141ff93d1SMatti Vaittinen  */
15241ff93d1SMatti Vaittinen enum bu27008_chan {
15341ff93d1SMatti Vaittinen 	BU27008_DATA0,
15441ff93d1SMatti Vaittinen 	BU27008_DATA1,
15541ff93d1SMatti Vaittinen 	BU27008_DATA2,
15641ff93d1SMatti Vaittinen 	BU27008_DATA3,
15741ff93d1SMatti Vaittinen 	BU27008_NUM_HW_CHANS
15841ff93d1SMatti Vaittinen };
15941ff93d1SMatti Vaittinen 
16041ff93d1SMatti Vaittinen /* We can always measure red and green at same time */
16141ff93d1SMatti Vaittinen #define ALWAYS_SCANNABLE (BIT(BU27008_RED) | BIT(BU27008_GREEN))
16241ff93d1SMatti Vaittinen 
16341ff93d1SMatti Vaittinen /* We use these data channel configs. Ensure scan_masks below follow them too */
16441ff93d1SMatti Vaittinen #define BU27008_BLUE2_CLEAR3		0x0 /* buffer is R, G, B, C */
16541ff93d1SMatti Vaittinen #define BU27008_CLEAR2_IR3		0x1 /* buffer is R, G, C, IR */
16641ff93d1SMatti Vaittinen #define BU27008_BLUE2_IR3		0x2 /* buffer is R, G, B, IR */
16741ff93d1SMatti Vaittinen 
16841ff93d1SMatti Vaittinen static const unsigned long bu27008_scan_masks[] = {
16941ff93d1SMatti Vaittinen 	/* buffer is R, G, B, C */
17041ff93d1SMatti Vaittinen 	ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_CLEAR),
17141ff93d1SMatti Vaittinen 	/* buffer is R, G, C, IR */
17241ff93d1SMatti Vaittinen 	ALWAYS_SCANNABLE | BIT(BU27008_CLEAR) | BIT(BU27008_IR),
17341ff93d1SMatti Vaittinen 	/* buffer is R, G, B, IR */
17441ff93d1SMatti Vaittinen 	ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_IR),
17541ff93d1SMatti Vaittinen 	0
17641ff93d1SMatti Vaittinen };
17741ff93d1SMatti Vaittinen 
17841ff93d1SMatti Vaittinen /*
17941ff93d1SMatti Vaittinen  * Available scales with gain 1x - 1024x, timings 55, 100, 200, 400 mS
18041ff93d1SMatti Vaittinen  * Time impacts to gain: 1x, 2x, 4x, 8x.
18141ff93d1SMatti Vaittinen  *
18241ff93d1SMatti Vaittinen  * => Max total gain is HWGAIN * gain by integration time (8 * 1024) = 8192
18341ff93d1SMatti Vaittinen  *
18441ff93d1SMatti Vaittinen  * Max amplification is (HWGAIN * MAX integration-time multiplier) 1024 * 8
18541ff93d1SMatti Vaittinen  * = 8192. With NANO scale we get rid of accuracy loss when we start with the
18641ff93d1SMatti Vaittinen  * scale 16.0 for HWGAIN1, INT-TIME 55 mS. This way the nano scale for MAX
18741ff93d1SMatti Vaittinen  * total gain 8192 will be 1953125
18841ff93d1SMatti Vaittinen  */
18941ff93d1SMatti Vaittinen #define BU27008_SCALE_1X 16
19041ff93d1SMatti Vaittinen 
191*fdb48f9dSMatti Vaittinen /*
192*fdb48f9dSMatti Vaittinen  * On BU27010 available scales with gain 1x - 4096x,
193*fdb48f9dSMatti Vaittinen  * timings 55, 100, 200, 400 mS. Time impacts to gain: 1x, 2x, 4x, 8x.
194*fdb48f9dSMatti Vaittinen  *
195*fdb48f9dSMatti Vaittinen  * => Max total gain is HWGAIN * gain by integration time (8 * 4096)
196*fdb48f9dSMatti Vaittinen  *
197*fdb48f9dSMatti Vaittinen  * Using NANO precision for scale we must use scale 64x corresponding gain 1x
198*fdb48f9dSMatti Vaittinen  * to avoid precision loss.
199*fdb48f9dSMatti Vaittinen  */
200*fdb48f9dSMatti Vaittinen #define BU27010_SCALE_1X 64
201*fdb48f9dSMatti Vaittinen 
20241ff93d1SMatti Vaittinen /* See the data sheet for the "Gain Setting" table */
20341ff93d1SMatti Vaittinen #define BU27008_GSEL_1X		0x00
20441ff93d1SMatti Vaittinen #define BU27008_GSEL_4X		0x08
20541ff93d1SMatti Vaittinen #define BU27008_GSEL_8X		0x09
20641ff93d1SMatti Vaittinen #define BU27008_GSEL_16X	0x0a
20741ff93d1SMatti Vaittinen #define BU27008_GSEL_32X	0x0b
20841ff93d1SMatti Vaittinen #define BU27008_GSEL_64X	0x0c
20941ff93d1SMatti Vaittinen #define BU27008_GSEL_256X	0x18
21041ff93d1SMatti Vaittinen #define BU27008_GSEL_512X	0x19
21141ff93d1SMatti Vaittinen #define BU27008_GSEL_1024X	0x1a
21241ff93d1SMatti Vaittinen 
21341ff93d1SMatti Vaittinen static const struct iio_gain_sel_pair bu27008_gains[] = {
21441ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(1, BU27008_GSEL_1X),
21541ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(4, BU27008_GSEL_4X),
21641ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(8, BU27008_GSEL_8X),
21741ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(16, BU27008_GSEL_16X),
21841ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(32, BU27008_GSEL_32X),
21941ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(64, BU27008_GSEL_64X),
22041ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(256, BU27008_GSEL_256X),
22141ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(512, BU27008_GSEL_512X),
22241ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(1024, BU27008_GSEL_1024X),
22341ff93d1SMatti Vaittinen };
22441ff93d1SMatti Vaittinen 
22541ff93d1SMatti Vaittinen static const struct iio_gain_sel_pair bu27008_gains_ir[] = {
22641ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(2, BU27008_GSEL_1X),
22741ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(4, BU27008_GSEL_4X),
22841ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(8, BU27008_GSEL_8X),
22941ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(16, BU27008_GSEL_16X),
23041ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(32, BU27008_GSEL_32X),
23141ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(64, BU27008_GSEL_64X),
23241ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(256, BU27008_GSEL_256X),
23341ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(512, BU27008_GSEL_512X),
23441ff93d1SMatti Vaittinen 	GAIN_SCALE_GAIN(1024, BU27008_GSEL_1024X),
23541ff93d1SMatti Vaittinen };
23641ff93d1SMatti Vaittinen 
237*fdb48f9dSMatti Vaittinen #define BU27010_GSEL_1X		0x00	/* 000000 */
238*fdb48f9dSMatti Vaittinen #define BU27010_GSEL_4X		0x08	/* 001000 */
239*fdb48f9dSMatti Vaittinen #define BU27010_GSEL_16X	0x09	/* 001001 */
240*fdb48f9dSMatti Vaittinen #define BU27010_GSEL_64X	0x0e	/* 001110 */
241*fdb48f9dSMatti Vaittinen #define BU27010_GSEL_256X	0x1e	/* 011110 */
242*fdb48f9dSMatti Vaittinen #define BU27010_GSEL_1024X	0x2e	/* 101110 */
243*fdb48f9dSMatti Vaittinen #define BU27010_GSEL_4096X	0x3f	/* 111111 */
244*fdb48f9dSMatti Vaittinen 
245*fdb48f9dSMatti Vaittinen static const struct iio_gain_sel_pair bu27010_gains[] = {
246*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(1, BU27010_GSEL_1X),
247*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(4, BU27010_GSEL_4X),
248*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(16, BU27010_GSEL_16X),
249*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(64, BU27010_GSEL_64X),
250*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(256, BU27010_GSEL_256X),
251*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(1024, BU27010_GSEL_1024X),
252*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(4096, BU27010_GSEL_4096X),
253*fdb48f9dSMatti Vaittinen };
254*fdb48f9dSMatti Vaittinen 
255*fdb48f9dSMatti Vaittinen static const struct iio_gain_sel_pair bu27010_gains_ir[] = {
256*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(2, BU27010_GSEL_1X),
257*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(4, BU27010_GSEL_4X),
258*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(16, BU27010_GSEL_16X),
259*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(64, BU27010_GSEL_64X),
260*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(256, BU27010_GSEL_256X),
261*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(1024, BU27010_GSEL_1024X),
262*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_GAIN(4096, BU27010_GSEL_4096X),
263*fdb48f9dSMatti Vaittinen };
264*fdb48f9dSMatti Vaittinen 
26541ff93d1SMatti Vaittinen #define BU27008_MEAS_MODE_100MS		0x00
26641ff93d1SMatti Vaittinen #define BU27008_MEAS_MODE_55MS		0x01
26741ff93d1SMatti Vaittinen #define BU27008_MEAS_MODE_200MS		0x02
26841ff93d1SMatti Vaittinen #define BU27008_MEAS_MODE_400MS		0x04
269*fdb48f9dSMatti Vaittinen 
270*fdb48f9dSMatti Vaittinen #define BU27010_MEAS_MODE_100MS		0x00
271*fdb48f9dSMatti Vaittinen #define BU27010_MEAS_MODE_55MS		0x03
272*fdb48f9dSMatti Vaittinen #define BU27010_MEAS_MODE_200MS		0x01
273*fdb48f9dSMatti Vaittinen #define BU27010_MEAS_MODE_400MS		0x02
274*fdb48f9dSMatti Vaittinen 
27541ff93d1SMatti Vaittinen #define BU27008_MEAS_TIME_MAX_MS	400
27641ff93d1SMatti Vaittinen 
27741ff93d1SMatti Vaittinen static const struct iio_itime_sel_mul bu27008_itimes[] = {
27841ff93d1SMatti Vaittinen 	GAIN_SCALE_ITIME_US(400000, BU27008_MEAS_MODE_400MS, 8),
27941ff93d1SMatti Vaittinen 	GAIN_SCALE_ITIME_US(200000, BU27008_MEAS_MODE_200MS, 4),
28041ff93d1SMatti Vaittinen 	GAIN_SCALE_ITIME_US(100000, BU27008_MEAS_MODE_100MS, 2),
28141ff93d1SMatti Vaittinen 	GAIN_SCALE_ITIME_US(55000, BU27008_MEAS_MODE_55MS, 1),
28241ff93d1SMatti Vaittinen };
28341ff93d1SMatti Vaittinen 
284*fdb48f9dSMatti Vaittinen static const struct iio_itime_sel_mul bu27010_itimes[] = {
285*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_ITIME_US(400000, BU27010_MEAS_MODE_400MS, 8),
286*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_ITIME_US(200000, BU27010_MEAS_MODE_200MS, 4),
287*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_ITIME_US(100000, BU27010_MEAS_MODE_100MS, 2),
288*fdb48f9dSMatti Vaittinen 	GAIN_SCALE_ITIME_US(55000, BU27010_MEAS_MODE_55MS, 1),
289*fdb48f9dSMatti Vaittinen };
290*fdb48f9dSMatti Vaittinen 
29141ff93d1SMatti Vaittinen /*
29241ff93d1SMatti Vaittinen  * All the RGBC channels share the same gain.
29341ff93d1SMatti Vaittinen  * IR gain can be fine-tuned from the gain set for the RGBC by 2 bit, but this
29441ff93d1SMatti Vaittinen  * would yield quite complex gain setting. Especially since not all bit
29541ff93d1SMatti Vaittinen  * compinations are supported. And in any case setting GAIN for RGBC will
29641ff93d1SMatti Vaittinen  * always also change the IR-gain.
29741ff93d1SMatti Vaittinen  *
29841ff93d1SMatti Vaittinen  * On top of this, the selector '0' which corresponds to hw-gain 1X on RGBC,
29941ff93d1SMatti Vaittinen  * corresponds to gain 2X on IR. Rest of the selctors correspond to same gains
30041ff93d1SMatti Vaittinen  * though. This, however, makes it not possible to use shared gain for all
30141ff93d1SMatti Vaittinen  * RGBC and IR settings even though they are all changed at the one go.
30241ff93d1SMatti Vaittinen  */
30341ff93d1SMatti Vaittinen #define BU27008_CHAN(color, data, separate_avail)				\
30441ff93d1SMatti Vaittinen {										\
30541ff93d1SMatti Vaittinen 	.type = IIO_INTENSITY,							\
30641ff93d1SMatti Vaittinen 	.modified = 1,								\
30741ff93d1SMatti Vaittinen 	.channel2 = IIO_MOD_LIGHT_##color,					\
30841ff93d1SMatti Vaittinen 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |				\
30941ff93d1SMatti Vaittinen 			      BIT(IIO_CHAN_INFO_SCALE),				\
31041ff93d1SMatti Vaittinen 	.info_mask_separate_available = (separate_avail),			\
31141ff93d1SMatti Vaittinen 	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),			\
31241ff93d1SMatti Vaittinen 	.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),	\
31341ff93d1SMatti Vaittinen 	.address = BU27008_REG_##data##_LO,					\
31441ff93d1SMatti Vaittinen 	.scan_index = BU27008_##color,						\
31541ff93d1SMatti Vaittinen 	.scan_type = {								\
31695fb1e7bSMatti Vaittinen 		.sign = 'u',							\
31741ff93d1SMatti Vaittinen 		.realbits = 16,							\
31841ff93d1SMatti Vaittinen 		.storagebits = 16,						\
31941ff93d1SMatti Vaittinen 		.endianness = IIO_LE,						\
32041ff93d1SMatti Vaittinen 	},									\
32141ff93d1SMatti Vaittinen }
32241ff93d1SMatti Vaittinen 
32341ff93d1SMatti Vaittinen /* For raw reads we always configure DATA3 for CLEAR */
32441ff93d1SMatti Vaittinen static const struct iio_chan_spec bu27008_channels[] = {
32541ff93d1SMatti Vaittinen 	BU27008_CHAN(RED, DATA0, BIT(IIO_CHAN_INFO_SCALE)),
32641ff93d1SMatti Vaittinen 	BU27008_CHAN(GREEN, DATA1, BIT(IIO_CHAN_INFO_SCALE)),
32741ff93d1SMatti Vaittinen 	BU27008_CHAN(BLUE, DATA2, BIT(IIO_CHAN_INFO_SCALE)),
32841ff93d1SMatti Vaittinen 	BU27008_CHAN(CLEAR, DATA2, BIT(IIO_CHAN_INFO_SCALE)),
32941ff93d1SMatti Vaittinen 	/*
33041ff93d1SMatti Vaittinen 	 * We don't allow setting scale for IR (because of shared gain bits).
33141ff93d1SMatti Vaittinen 	 * Hence we don't advertise available ones either.
33241ff93d1SMatti Vaittinen 	 */
33341ff93d1SMatti Vaittinen 	BU27008_CHAN(IR, DATA3, 0),
33441ff93d1SMatti Vaittinen 	IIO_CHAN_SOFT_TIMESTAMP(BU27008_NUM_CHANS),
33541ff93d1SMatti Vaittinen };
33641ff93d1SMatti Vaittinen 
337ccca97fbSMatti Vaittinen struct bu27008_data;
338ccca97fbSMatti Vaittinen 
339ccca97fbSMatti Vaittinen struct bu27_chip_data {
340ccca97fbSMatti Vaittinen 	const char *name;
341ccca97fbSMatti Vaittinen 	int (*chip_init)(struct bu27008_data *data);
342ccca97fbSMatti Vaittinen 	int (*get_gain_sel)(struct bu27008_data *data, int *sel);
343ccca97fbSMatti Vaittinen 	int (*write_gain_sel)(struct bu27008_data *data, int sel);
344ccca97fbSMatti Vaittinen 	const struct regmap_config *regmap_cfg;
345ccca97fbSMatti Vaittinen 	const struct iio_gain_sel_pair *gains;
346ccca97fbSMatti Vaittinen 	const struct iio_gain_sel_pair *gains_ir;
347ccca97fbSMatti Vaittinen 	const struct iio_itime_sel_mul *itimes;
348ccca97fbSMatti Vaittinen 	int num_gains;
349ccca97fbSMatti Vaittinen 	int num_gains_ir;
350ccca97fbSMatti Vaittinen 	int num_itimes;
351ccca97fbSMatti Vaittinen 	int scale1x;
352ccca97fbSMatti Vaittinen 
353ccca97fbSMatti Vaittinen 	int drdy_en_reg;
354ccca97fbSMatti Vaittinen 	int drdy_en_mask;
355ccca97fbSMatti Vaittinen 	int meas_en_reg;
356ccca97fbSMatti Vaittinen 	int meas_en_mask;
357ccca97fbSMatti Vaittinen 	int valid_reg;
358ccca97fbSMatti Vaittinen 	int chan_sel_reg;
359ccca97fbSMatti Vaittinen 	int chan_sel_mask;
360ccca97fbSMatti Vaittinen 	int int_time_mask;
361ccca97fbSMatti Vaittinen 	u8 part_id;
362ccca97fbSMatti Vaittinen };
363ccca97fbSMatti Vaittinen 
36441ff93d1SMatti Vaittinen struct bu27008_data {
365ccca97fbSMatti Vaittinen 	const struct bu27_chip_data *cd;
36641ff93d1SMatti Vaittinen 	struct regmap *regmap;
36741ff93d1SMatti Vaittinen 	struct iio_trigger *trig;
36841ff93d1SMatti Vaittinen 	struct device *dev;
36941ff93d1SMatti Vaittinen 	struct iio_gts gts;
37041ff93d1SMatti Vaittinen 	struct iio_gts gts_ir;
37141ff93d1SMatti Vaittinen 	int irq;
37241ff93d1SMatti Vaittinen 
37341ff93d1SMatti Vaittinen 	/*
37441ff93d1SMatti Vaittinen 	 * Prevent changing gain/time config when scale is read/written.
37541ff93d1SMatti Vaittinen 	 * Similarly, protect the integration_time read/change sequence.
37641ff93d1SMatti Vaittinen 	 * Prevent changing gain/time when data is read.
37741ff93d1SMatti Vaittinen 	 */
37841ff93d1SMatti Vaittinen 	struct mutex mutex;
37941ff93d1SMatti Vaittinen };
38041ff93d1SMatti Vaittinen 
38141ff93d1SMatti Vaittinen static const struct regmap_range bu27008_volatile_ranges[] = {
38241ff93d1SMatti Vaittinen 	{
38341ff93d1SMatti Vaittinen 		.range_min = BU27008_REG_SYSTEM_CONTROL,	/* SWRESET */
38441ff93d1SMatti Vaittinen 		.range_max = BU27008_REG_SYSTEM_CONTROL,
38541ff93d1SMatti Vaittinen 	}, {
38641ff93d1SMatti Vaittinen 		.range_min = BU27008_REG_MODE_CONTROL3,		/* VALID */
38741ff93d1SMatti Vaittinen 		.range_max = BU27008_REG_MODE_CONTROL3,
38841ff93d1SMatti Vaittinen 	}, {
38941ff93d1SMatti Vaittinen 		.range_min = BU27008_REG_DATA0_LO,		/* DATA */
39041ff93d1SMatti Vaittinen 		.range_max = BU27008_REG_DATA3_HI,
39141ff93d1SMatti Vaittinen 	},
39241ff93d1SMatti Vaittinen };
39341ff93d1SMatti Vaittinen 
394*fdb48f9dSMatti Vaittinen static const struct regmap_range bu27010_volatile_ranges[] = {
395*fdb48f9dSMatti Vaittinen 	{
396*fdb48f9dSMatti Vaittinen 		.range_min = BU27010_REG_RESET,			/* RSTB */
397*fdb48f9dSMatti Vaittinen 		.range_max = BU27008_REG_SYSTEM_CONTROL,	/* RESET */
398*fdb48f9dSMatti Vaittinen 	}, {
399*fdb48f9dSMatti Vaittinen 		.range_min = BU27010_REG_MODE_CONTROL5,		/* VALID bits */
400*fdb48f9dSMatti Vaittinen 		.range_max = BU27010_REG_MODE_CONTROL5,
401*fdb48f9dSMatti Vaittinen 	}, {
402*fdb48f9dSMatti Vaittinen 		.range_min = BU27008_REG_DATA0_LO,
403*fdb48f9dSMatti Vaittinen 		.range_max = BU27010_REG_FIFO_DATA_HI,
404*fdb48f9dSMatti Vaittinen 	},
405*fdb48f9dSMatti Vaittinen };
406*fdb48f9dSMatti Vaittinen 
40741ff93d1SMatti Vaittinen static const struct regmap_access_table bu27008_volatile_regs = {
40841ff93d1SMatti Vaittinen 	.yes_ranges = &bu27008_volatile_ranges[0],
40941ff93d1SMatti Vaittinen 	.n_yes_ranges = ARRAY_SIZE(bu27008_volatile_ranges),
41041ff93d1SMatti Vaittinen };
41141ff93d1SMatti Vaittinen 
412*fdb48f9dSMatti Vaittinen static const struct regmap_access_table bu27010_volatile_regs = {
413*fdb48f9dSMatti Vaittinen 	.yes_ranges = &bu27010_volatile_ranges[0],
414*fdb48f9dSMatti Vaittinen 	.n_yes_ranges = ARRAY_SIZE(bu27010_volatile_ranges),
415*fdb48f9dSMatti Vaittinen };
416*fdb48f9dSMatti Vaittinen 
41741ff93d1SMatti Vaittinen static const struct regmap_range bu27008_read_only_ranges[] = {
41841ff93d1SMatti Vaittinen 	{
41941ff93d1SMatti Vaittinen 		.range_min = BU27008_REG_DATA0_LO,
42041ff93d1SMatti Vaittinen 		.range_max = BU27008_REG_DATA3_HI,
42141ff93d1SMatti Vaittinen 	}, {
42241ff93d1SMatti Vaittinen 		.range_min = BU27008_REG_MANUFACTURER_ID,
42341ff93d1SMatti Vaittinen 		.range_max = BU27008_REG_MANUFACTURER_ID,
42441ff93d1SMatti Vaittinen 	},
42541ff93d1SMatti Vaittinen };
42641ff93d1SMatti Vaittinen 
427*fdb48f9dSMatti Vaittinen static const struct regmap_range bu27010_read_only_ranges[] = {
428*fdb48f9dSMatti Vaittinen 	{
429*fdb48f9dSMatti Vaittinen 		.range_min = BU27008_REG_DATA0_LO,
430*fdb48f9dSMatti Vaittinen 		.range_max = BU27010_REG_FIFO_DATA_HI,
431*fdb48f9dSMatti Vaittinen 	}, {
432*fdb48f9dSMatti Vaittinen 		.range_min = BU27010_REG_MANUFACTURER_ID,
433*fdb48f9dSMatti Vaittinen 		.range_max = BU27010_REG_MANUFACTURER_ID,
434*fdb48f9dSMatti Vaittinen 	}
435*fdb48f9dSMatti Vaittinen };
436*fdb48f9dSMatti Vaittinen 
43741ff93d1SMatti Vaittinen static const struct regmap_access_table bu27008_ro_regs = {
43841ff93d1SMatti Vaittinen 	.no_ranges = &bu27008_read_only_ranges[0],
43941ff93d1SMatti Vaittinen 	.n_no_ranges = ARRAY_SIZE(bu27008_read_only_ranges),
44041ff93d1SMatti Vaittinen };
44141ff93d1SMatti Vaittinen 
442*fdb48f9dSMatti Vaittinen static const struct regmap_access_table bu27010_ro_regs = {
443*fdb48f9dSMatti Vaittinen 	.no_ranges = &bu27010_read_only_ranges[0],
444*fdb48f9dSMatti Vaittinen 	.n_no_ranges = ARRAY_SIZE(bu27010_read_only_ranges),
445*fdb48f9dSMatti Vaittinen };
446*fdb48f9dSMatti Vaittinen 
44741ff93d1SMatti Vaittinen static const struct regmap_config bu27008_regmap = {
44841ff93d1SMatti Vaittinen 	.reg_bits = 8,
44941ff93d1SMatti Vaittinen 	.val_bits = 8,
45041ff93d1SMatti Vaittinen 	.max_register = BU27008_REG_MAX,
45141ff93d1SMatti Vaittinen 	.cache_type = REGCACHE_RBTREE,
45241ff93d1SMatti Vaittinen 	.volatile_table = &bu27008_volatile_regs,
45341ff93d1SMatti Vaittinen 	.wr_table = &bu27008_ro_regs,
45441ff93d1SMatti Vaittinen 	/*
45541ff93d1SMatti Vaittinen 	 * All register writes are serialized by the mutex which protects the
45641ff93d1SMatti Vaittinen 	 * scale setting/getting. This is needed because scale is combined by
45741ff93d1SMatti Vaittinen 	 * gain and integration time settings and we need to ensure those are
45841ff93d1SMatti Vaittinen 	 * not read / written when scale is being computed.
45941ff93d1SMatti Vaittinen 	 *
46041ff93d1SMatti Vaittinen 	 * As a result of this serializing, we don't need regmap locking. Note,
46141ff93d1SMatti Vaittinen 	 * this is not true if we add any configurations which are not
46241ff93d1SMatti Vaittinen 	 * serialized by the mutex and which may need for example a protected
46341ff93d1SMatti Vaittinen 	 * read-modify-write cycle (eg. regmap_update_bits()). Please, revise
46441ff93d1SMatti Vaittinen 	 * this when adding features to the driver.
46541ff93d1SMatti Vaittinen 	 */
46641ff93d1SMatti Vaittinen 	.disable_locking = true,
46741ff93d1SMatti Vaittinen };
46841ff93d1SMatti Vaittinen 
469*fdb48f9dSMatti Vaittinen static const struct regmap_config bu27010_regmap = {
470*fdb48f9dSMatti Vaittinen 	.reg_bits	= 8,
471*fdb48f9dSMatti Vaittinen 	.val_bits	= 8,
472*fdb48f9dSMatti Vaittinen 
473*fdb48f9dSMatti Vaittinen 	.max_register	= BU27010_REG_MAX,
474*fdb48f9dSMatti Vaittinen 	.cache_type	= REGCACHE_RBTREE,
475*fdb48f9dSMatti Vaittinen 	.volatile_table = &bu27010_volatile_regs,
476*fdb48f9dSMatti Vaittinen 	.wr_table	= &bu27010_ro_regs,
477*fdb48f9dSMatti Vaittinen 	.disable_locking = true,
478*fdb48f9dSMatti Vaittinen };
479*fdb48f9dSMatti Vaittinen 
bu27008_write_gain_sel(struct bu27008_data * data,int sel)48041ff93d1SMatti Vaittinen static int bu27008_write_gain_sel(struct bu27008_data *data, int sel)
48141ff93d1SMatti Vaittinen {
48241ff93d1SMatti Vaittinen 	int regval;
48341ff93d1SMatti Vaittinen 
48441ff93d1SMatti Vaittinen 	regval = FIELD_PREP(BU27008_MASK_RGBC_GAIN, sel);
48541ff93d1SMatti Vaittinen 
48641ff93d1SMatti Vaittinen 	/*
48741ff93d1SMatti Vaittinen 	 * We do always set also the LOW bits of IR-gain because othervice we
48841ff93d1SMatti Vaittinen 	 * would risk resulting an invalid GAIN register value.
48941ff93d1SMatti Vaittinen 	 *
49041ff93d1SMatti Vaittinen 	 * We could allow setting separate gains for RGBC and IR when the
49141ff93d1SMatti Vaittinen 	 * values were such that HW could support both gain settings.
49241ff93d1SMatti Vaittinen 	 * Eg, when the shared bits were same for both gain values.
49341ff93d1SMatti Vaittinen 	 *
49441ff93d1SMatti Vaittinen 	 * This, however, has a negligible benefit compared to the increased
49541ff93d1SMatti Vaittinen 	 * software complexity when we would need to go through the gains
49641ff93d1SMatti Vaittinen 	 * for both channels separately when the integration time changes.
49741ff93d1SMatti Vaittinen 	 * This would end up with nasty logic for computing gain values for
49841ff93d1SMatti Vaittinen 	 * both channels - and rejecting them if shared bits changed.
49941ff93d1SMatti Vaittinen 	 *
50041ff93d1SMatti Vaittinen 	 * We should then build the logic by guessing what a user prefers.
50141ff93d1SMatti Vaittinen 	 * RGBC or IR gains correctly set while other jumps to odd value?
50241ff93d1SMatti Vaittinen 	 * Maybe look-up a value where both gains are somehow optimized
50341ff93d1SMatti Vaittinen 	 * <what this somehow is, is ATM unknown to us>. Or maybe user would
50441ff93d1SMatti Vaittinen 	 * expect us to reject changes when optimal gains can't be set to both
50541ff93d1SMatti Vaittinen 	 * channels w/given integration time. At best that would result
50641ff93d1SMatti Vaittinen 	 * solution that works well for a very specific subset of
50741ff93d1SMatti Vaittinen 	 * configurations but causes unexpected corner-cases.
50841ff93d1SMatti Vaittinen 	 *
50941ff93d1SMatti Vaittinen 	 * So, we keep it simple. Always set same selector to IR and RGBC.
51041ff93d1SMatti Vaittinen 	 * We disallow setting IR (as I expect that most of the users are
51141ff93d1SMatti Vaittinen 	 * interested in RGBC). This way we can show the user that the scales
51241ff93d1SMatti Vaittinen 	 * for RGBC and IR channels are different (1X Vs 2X with sel 0) while
51341ff93d1SMatti Vaittinen 	 * still keeping the operation deterministic.
51441ff93d1SMatti Vaittinen 	 */
51541ff93d1SMatti Vaittinen 	regval |= FIELD_PREP(BU27008_MASK_IR_GAIN_LO, sel);
51641ff93d1SMatti Vaittinen 
51741ff93d1SMatti Vaittinen 	return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL2,
51841ff93d1SMatti Vaittinen 				  BU27008_MASK_RGBC_GAIN, regval);
51941ff93d1SMatti Vaittinen }
52041ff93d1SMatti Vaittinen 
bu27010_write_gain_sel(struct bu27008_data * data,int sel)521*fdb48f9dSMatti Vaittinen static int bu27010_write_gain_sel(struct bu27008_data *data, int sel)
522*fdb48f9dSMatti Vaittinen {
523*fdb48f9dSMatti Vaittinen 	unsigned int regval;
524*fdb48f9dSMatti Vaittinen 	int ret, chan_selector;
525*fdb48f9dSMatti Vaittinen 
526*fdb48f9dSMatti Vaittinen 	/*
527*fdb48f9dSMatti Vaittinen 	 * Gain 'selector' is composed of two registers. Selector is 6bit value,
528*fdb48f9dSMatti Vaittinen 	 * 4 high bits being the RGBC gain fieild in MODE_CONTROL1 register and
529*fdb48f9dSMatti Vaittinen 	 * two low bits being the channel specific gain in MODE_CONTROL2.
530*fdb48f9dSMatti Vaittinen 	 *
531*fdb48f9dSMatti Vaittinen 	 * Let's take the 4 high bits of whole 6 bit selector, and prepare
532*fdb48f9dSMatti Vaittinen 	 * the MODE_CONTROL1 value (RGBC gain part).
533*fdb48f9dSMatti Vaittinen 	 */
534*fdb48f9dSMatti Vaittinen 	regval = FIELD_PREP(BU27010_MASK_RGBC_GAIN, (sel >> 2));
535*fdb48f9dSMatti Vaittinen 
536*fdb48f9dSMatti Vaittinen 	ret = regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1,
537*fdb48f9dSMatti Vaittinen 				  BU27010_MASK_RGBC_GAIN, regval);
538*fdb48f9dSMatti Vaittinen 	if (ret)
539*fdb48f9dSMatti Vaittinen 		return ret;
540*fdb48f9dSMatti Vaittinen 
541*fdb48f9dSMatti Vaittinen 	/*
542*fdb48f9dSMatti Vaittinen 	 * Two low two bits of the selector must be written for all 4
543*fdb48f9dSMatti Vaittinen 	 * channels in the MODE_CONTROL2 register. Copy these two bits for
544*fdb48f9dSMatti Vaittinen 	 * all channels.
545*fdb48f9dSMatti Vaittinen 	 */
546*fdb48f9dSMatti Vaittinen 	chan_selector = sel & GENMASK(1, 0);
547*fdb48f9dSMatti Vaittinen 
548*fdb48f9dSMatti Vaittinen 	regval = FIELD_PREP(BU27010_MASK_DATA0_GAIN, chan_selector);
549*fdb48f9dSMatti Vaittinen 	regval |= FIELD_PREP(BU27010_MASK_DATA1_GAIN, chan_selector);
550*fdb48f9dSMatti Vaittinen 	regval |= FIELD_PREP(BU27010_MASK_DATA2_GAIN, chan_selector);
551*fdb48f9dSMatti Vaittinen 	regval |= FIELD_PREP(BU27010_MASK_DATA3_GAIN, chan_selector);
552*fdb48f9dSMatti Vaittinen 
553*fdb48f9dSMatti Vaittinen 	return regmap_write(data->regmap, BU27008_REG_MODE_CONTROL2, regval);
554*fdb48f9dSMatti Vaittinen }
555*fdb48f9dSMatti Vaittinen 
bu27008_get_gain_sel(struct bu27008_data * data,int * sel)556ccca97fbSMatti Vaittinen static int bu27008_get_gain_sel(struct bu27008_data *data, int *sel)
557ccca97fbSMatti Vaittinen {
558ccca97fbSMatti Vaittinen 	int ret;
559ccca97fbSMatti Vaittinen 
560ccca97fbSMatti Vaittinen 	/*
561ccca97fbSMatti Vaittinen 	 * If we always "lock" the gain selectors for all channels to prevent
562ccca97fbSMatti Vaittinen 	 * unsupported configs, then it does not matter which channel is used
563ccca97fbSMatti Vaittinen 	 * we can just return selector from any of them.
564ccca97fbSMatti Vaittinen 	 *
565ccca97fbSMatti Vaittinen 	 * This, however is not true if we decide to support only 4X and 16X
566ccca97fbSMatti Vaittinen 	 * and then individual gains for channels. Currently this is not the
567ccca97fbSMatti Vaittinen 	 * case.
568ccca97fbSMatti Vaittinen 	 *
569ccca97fbSMatti Vaittinen 	 * If we some day decide to support individual gains, then we need to
570ccca97fbSMatti Vaittinen 	 * have channel information here.
571ccca97fbSMatti Vaittinen 	 */
572ccca97fbSMatti Vaittinen 
573ccca97fbSMatti Vaittinen 	ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL2, sel);
574ccca97fbSMatti Vaittinen 	if (ret)
575ccca97fbSMatti Vaittinen 		return ret;
576ccca97fbSMatti Vaittinen 
577ccca97fbSMatti Vaittinen 	*sel = FIELD_GET(BU27008_MASK_RGBC_GAIN, *sel);
578ccca97fbSMatti Vaittinen 
579ccca97fbSMatti Vaittinen 	return 0;
580ccca97fbSMatti Vaittinen }
581ccca97fbSMatti Vaittinen 
bu27010_get_gain_sel(struct bu27008_data * data,int * sel)582*fdb48f9dSMatti Vaittinen static int bu27010_get_gain_sel(struct bu27008_data *data, int *sel)
583*fdb48f9dSMatti Vaittinen {
584*fdb48f9dSMatti Vaittinen 	int ret, tmp;
585*fdb48f9dSMatti Vaittinen 
586*fdb48f9dSMatti Vaittinen 	/*
587*fdb48f9dSMatti Vaittinen 	 * We always "lock" the gain selectors for all channels to prevent
588*fdb48f9dSMatti Vaittinen 	 * unsupported configs. It does not matter which channel is used
589*fdb48f9dSMatti Vaittinen 	 * we can just return selector from any of them.
590*fdb48f9dSMatti Vaittinen 	 *
591*fdb48f9dSMatti Vaittinen 	 * Read the channel0 gain.
592*fdb48f9dSMatti Vaittinen 	 */
593*fdb48f9dSMatti Vaittinen 	ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL2, sel);
594*fdb48f9dSMatti Vaittinen 	if (ret)
595*fdb48f9dSMatti Vaittinen 		return ret;
596*fdb48f9dSMatti Vaittinen 
597*fdb48f9dSMatti Vaittinen 	*sel = FIELD_GET(BU27010_MASK_DATA0_GAIN, *sel);
598*fdb48f9dSMatti Vaittinen 
599*fdb48f9dSMatti Vaittinen 	/* Read the shared gain */
600*fdb48f9dSMatti Vaittinen 	ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL1, &tmp);
601*fdb48f9dSMatti Vaittinen 	if (ret)
602*fdb48f9dSMatti Vaittinen 		return ret;
603*fdb48f9dSMatti Vaittinen 
604*fdb48f9dSMatti Vaittinen 	/*
605*fdb48f9dSMatti Vaittinen 	 * The gain selector is made as a combination of common RGBC gain and
606*fdb48f9dSMatti Vaittinen 	 * the channel specific gain. The channel specific gain forms the low
607*fdb48f9dSMatti Vaittinen 	 * bits of selector and RGBC gain is appended right after it.
608*fdb48f9dSMatti Vaittinen 	 *
609*fdb48f9dSMatti Vaittinen 	 * Compose the selector from channel0 gain and shared RGBC gain.
610*fdb48f9dSMatti Vaittinen 	 */
611*fdb48f9dSMatti Vaittinen 	*sel |= FIELD_GET(BU27010_MASK_RGBC_GAIN, tmp) << fls(BU27010_MASK_DATA0_GAIN);
612*fdb48f9dSMatti Vaittinen 
613*fdb48f9dSMatti Vaittinen 	return ret;
614*fdb48f9dSMatti Vaittinen }
615*fdb48f9dSMatti Vaittinen 
bu27008_chip_init(struct bu27008_data * data)616ccca97fbSMatti Vaittinen static int bu27008_chip_init(struct bu27008_data *data)
617ccca97fbSMatti Vaittinen {
618ccca97fbSMatti Vaittinen 	int ret;
619ccca97fbSMatti Vaittinen 
620ccca97fbSMatti Vaittinen 	ret = regmap_write_bits(data->regmap, BU27008_REG_SYSTEM_CONTROL,
621ccca97fbSMatti Vaittinen 				BU27008_MASK_SW_RESET, BU27008_MASK_SW_RESET);
622ccca97fbSMatti Vaittinen 	if (ret)
623ccca97fbSMatti Vaittinen 		return dev_err_probe(data->dev, ret, "Sensor reset failed\n");
624ccca97fbSMatti Vaittinen 
625ccca97fbSMatti Vaittinen 	/*
626ccca97fbSMatti Vaittinen 	 * The data-sheet does not tell how long performing the IC reset takes.
627ccca97fbSMatti Vaittinen 	 * However, the data-sheet says the minimum time it takes the IC to be
628ccca97fbSMatti Vaittinen 	 * able to take inputs after power is applied, is 100 uS. I'd assume
629ccca97fbSMatti Vaittinen 	 * > 1 mS is enough.
630ccca97fbSMatti Vaittinen 	 */
631ccca97fbSMatti Vaittinen 	msleep(1);
632ccca97fbSMatti Vaittinen 
633ccca97fbSMatti Vaittinen 	ret = regmap_reinit_cache(data->regmap, data->cd->regmap_cfg);
634ccca97fbSMatti Vaittinen 	if (ret)
635ccca97fbSMatti Vaittinen 		dev_err(data->dev, "Failed to reinit reg cache\n");
636ccca97fbSMatti Vaittinen 
637ccca97fbSMatti Vaittinen 	return ret;
638ccca97fbSMatti Vaittinen }
639ccca97fbSMatti Vaittinen 
bu27010_chip_init(struct bu27008_data * data)640*fdb48f9dSMatti Vaittinen static int bu27010_chip_init(struct bu27008_data *data)
641*fdb48f9dSMatti Vaittinen {
642*fdb48f9dSMatti Vaittinen 	int ret;
643*fdb48f9dSMatti Vaittinen 
644*fdb48f9dSMatti Vaittinen 	ret = regmap_write_bits(data->regmap, BU27008_REG_SYSTEM_CONTROL,
645*fdb48f9dSMatti Vaittinen 				BU27010_MASK_SW_RESET, BU27010_MASK_SW_RESET);
646*fdb48f9dSMatti Vaittinen 	if (ret)
647*fdb48f9dSMatti Vaittinen 		return dev_err_probe(data->dev, ret, "Sensor reset failed\n");
648*fdb48f9dSMatti Vaittinen 
649*fdb48f9dSMatti Vaittinen 	msleep(1);
650*fdb48f9dSMatti Vaittinen 
651*fdb48f9dSMatti Vaittinen 	/* Power ON*/
652*fdb48f9dSMatti Vaittinen 	ret = regmap_write_bits(data->regmap, BU27010_REG_POWER,
653*fdb48f9dSMatti Vaittinen 				BU27010_MASK_POWER, BU27010_MASK_POWER);
654*fdb48f9dSMatti Vaittinen 	if (ret)
655*fdb48f9dSMatti Vaittinen 		return dev_err_probe(data->dev, ret, "Sensor power-on failed\n");
656*fdb48f9dSMatti Vaittinen 
657*fdb48f9dSMatti Vaittinen 	msleep(1);
658*fdb48f9dSMatti Vaittinen 
659*fdb48f9dSMatti Vaittinen 	/* Release blocks from reset */
660*fdb48f9dSMatti Vaittinen 	ret = regmap_write_bits(data->regmap, BU27010_REG_RESET,
661*fdb48f9dSMatti Vaittinen 				BU27010_MASK_RESET, BU27010_RESET_RELEASE);
662*fdb48f9dSMatti Vaittinen 	if (ret)
663*fdb48f9dSMatti Vaittinen 		return dev_err_probe(data->dev, ret, "Sensor powering failed\n");
664*fdb48f9dSMatti Vaittinen 
665*fdb48f9dSMatti Vaittinen 	msleep(1);
666*fdb48f9dSMatti Vaittinen 
667*fdb48f9dSMatti Vaittinen 	/*
668*fdb48f9dSMatti Vaittinen 	 * The IRQ enabling on BU27010 is done in a peculiar way. The IRQ
669*fdb48f9dSMatti Vaittinen 	 * enabling is not a bit mask where individual IRQs could be enabled but
670*fdb48f9dSMatti Vaittinen 	 * a field which values are:
671*fdb48f9dSMatti Vaittinen 	 * 00 => IRQs disabled
672*fdb48f9dSMatti Vaittinen 	 * 01 => Data-ready (RGBC/IR)
673*fdb48f9dSMatti Vaittinen 	 * 10 => Data-ready (flicker)
674*fdb48f9dSMatti Vaittinen 	 * 11 => Flicker FIFO
675*fdb48f9dSMatti Vaittinen 	 *
676*fdb48f9dSMatti Vaittinen 	 * So, only one IRQ can be enabled at a time and enabling for example
677*fdb48f9dSMatti Vaittinen 	 * flicker FIFO would automagically disable data-ready IRQ.
678*fdb48f9dSMatti Vaittinen 	 *
679*fdb48f9dSMatti Vaittinen 	 * Currently the driver does not support the flicker. Hence, we can
680*fdb48f9dSMatti Vaittinen 	 * just treat the RGBC data-ready as single bit which can be enabled /
681*fdb48f9dSMatti Vaittinen 	 * disabled. This works for as long as the second bit in the field
682*fdb48f9dSMatti Vaittinen 	 * stays zero. Here we ensure it gets zeroed.
683*fdb48f9dSMatti Vaittinen 	 */
684*fdb48f9dSMatti Vaittinen 	return regmap_clear_bits(data->regmap, BU27010_REG_MODE_CONTROL4,
685*fdb48f9dSMatti Vaittinen 				 BU27010_IRQ_DIS_ALL);
686*fdb48f9dSMatti Vaittinen }
687*fdb48f9dSMatti Vaittinen 
688*fdb48f9dSMatti Vaittinen static const struct bu27_chip_data bu27010_chip = {
689*fdb48f9dSMatti Vaittinen 	.name = "bu27010",
690*fdb48f9dSMatti Vaittinen 	.chip_init = bu27010_chip_init,
691*fdb48f9dSMatti Vaittinen 	.get_gain_sel = bu27010_get_gain_sel,
692*fdb48f9dSMatti Vaittinen 	.write_gain_sel = bu27010_write_gain_sel,
693*fdb48f9dSMatti Vaittinen 	.regmap_cfg = &bu27010_regmap,
694*fdb48f9dSMatti Vaittinen 	.gains = &bu27010_gains[0],
695*fdb48f9dSMatti Vaittinen 	.gains_ir = &bu27010_gains_ir[0],
696*fdb48f9dSMatti Vaittinen 	.itimes = &bu27010_itimes[0],
697*fdb48f9dSMatti Vaittinen 	.num_gains = ARRAY_SIZE(bu27010_gains),
698*fdb48f9dSMatti Vaittinen 	.num_gains_ir = ARRAY_SIZE(bu27010_gains_ir),
699*fdb48f9dSMatti Vaittinen 	.num_itimes = ARRAY_SIZE(bu27010_itimes),
700*fdb48f9dSMatti Vaittinen 	.scale1x = BU27010_SCALE_1X,
701*fdb48f9dSMatti Vaittinen 	.drdy_en_reg = BU27010_REG_MODE_CONTROL4,
702*fdb48f9dSMatti Vaittinen 	.drdy_en_mask = BU27010_DRDY_EN,
703*fdb48f9dSMatti Vaittinen 	.meas_en_reg = BU27010_REG_MODE_CONTROL5,
704*fdb48f9dSMatti Vaittinen 	.meas_en_mask = BU27010_MASK_MEAS_EN,
705*fdb48f9dSMatti Vaittinen 	.valid_reg = BU27010_REG_MODE_CONTROL5,
706*fdb48f9dSMatti Vaittinen 	.chan_sel_reg = BU27008_REG_MODE_CONTROL1,
707*fdb48f9dSMatti Vaittinen 	.chan_sel_mask = BU27010_MASK_CHAN_SEL,
708*fdb48f9dSMatti Vaittinen 	.int_time_mask = BU27010_MASK_MEAS_MODE,
709*fdb48f9dSMatti Vaittinen 	.part_id = BU27010_ID,
710*fdb48f9dSMatti Vaittinen };
711*fdb48f9dSMatti Vaittinen 
712ccca97fbSMatti Vaittinen static const struct bu27_chip_data bu27008_chip = {
713ccca97fbSMatti Vaittinen 	.name = "bu27008",
714ccca97fbSMatti Vaittinen 	.chip_init = bu27008_chip_init,
715ccca97fbSMatti Vaittinen 	.get_gain_sel = bu27008_get_gain_sel,
716ccca97fbSMatti Vaittinen 	.write_gain_sel = bu27008_write_gain_sel,
717ccca97fbSMatti Vaittinen 	.regmap_cfg = &bu27008_regmap,
718ccca97fbSMatti Vaittinen 	.gains = &bu27008_gains[0],
719ccca97fbSMatti Vaittinen 	.gains_ir = &bu27008_gains_ir[0],
720ccca97fbSMatti Vaittinen 	.itimes = &bu27008_itimes[0],
721ccca97fbSMatti Vaittinen 	.num_gains = ARRAY_SIZE(bu27008_gains),
722ccca97fbSMatti Vaittinen 	.num_gains_ir = ARRAY_SIZE(bu27008_gains_ir),
723ccca97fbSMatti Vaittinen 	.num_itimes = ARRAY_SIZE(bu27008_itimes),
724ccca97fbSMatti Vaittinen 	.scale1x = BU27008_SCALE_1X,
725ccca97fbSMatti Vaittinen 	.drdy_en_reg = BU27008_REG_MODE_CONTROL3,
726ccca97fbSMatti Vaittinen 	.drdy_en_mask = BU27008_MASK_INT_EN,
727ccca97fbSMatti Vaittinen 	.valid_reg = BU27008_REG_MODE_CONTROL3,
728ccca97fbSMatti Vaittinen 	.meas_en_reg = BU27008_REG_MODE_CONTROL3,
729ccca97fbSMatti Vaittinen 	.meas_en_mask = BU27008_MASK_MEAS_EN,
730ccca97fbSMatti Vaittinen 	.chan_sel_reg = BU27008_REG_MODE_CONTROL3,
731ccca97fbSMatti Vaittinen 	.chan_sel_mask = BU27008_MASK_CHAN_SEL,
732ccca97fbSMatti Vaittinen 	.int_time_mask = BU27008_MASK_MEAS_MODE,
733ccca97fbSMatti Vaittinen 	.part_id = BU27008_ID,
734ccca97fbSMatti Vaittinen };
735ccca97fbSMatti Vaittinen 
736ccca97fbSMatti Vaittinen #define BU27008_MAX_VALID_RESULT_WAIT_US	50000
737ccca97fbSMatti Vaittinen #define BU27008_VALID_RESULT_WAIT_QUANTA_US	1000
738ccca97fbSMatti Vaittinen 
bu27008_chan_read_data(struct bu27008_data * data,int reg,int * val)739ccca97fbSMatti Vaittinen static int bu27008_chan_read_data(struct bu27008_data *data, int reg, int *val)
740ccca97fbSMatti Vaittinen {
741ccca97fbSMatti Vaittinen 	int ret, valid;
742ccca97fbSMatti Vaittinen 	__le16 tmp;
743ccca97fbSMatti Vaittinen 
744ccca97fbSMatti Vaittinen 	ret = regmap_read_poll_timeout(data->regmap, data->cd->valid_reg,
745ccca97fbSMatti Vaittinen 				       valid, (valid & BU27008_MASK_VALID),
746ccca97fbSMatti Vaittinen 				       BU27008_VALID_RESULT_WAIT_QUANTA_US,
747ccca97fbSMatti Vaittinen 				       BU27008_MAX_VALID_RESULT_WAIT_US);
748ccca97fbSMatti Vaittinen 	if (ret)
749ccca97fbSMatti Vaittinen 		return ret;
750ccca97fbSMatti Vaittinen 
751ccca97fbSMatti Vaittinen 	ret = regmap_bulk_read(data->regmap, reg, &tmp, sizeof(tmp));
752ccca97fbSMatti Vaittinen 	if (ret)
753ccca97fbSMatti Vaittinen 		dev_err(data->dev, "Reading channel data failed\n");
754ccca97fbSMatti Vaittinen 
755ccca97fbSMatti Vaittinen 	*val = le16_to_cpu(tmp);
756ccca97fbSMatti Vaittinen 
757ccca97fbSMatti Vaittinen 	return ret;
758ccca97fbSMatti Vaittinen }
759ccca97fbSMatti Vaittinen 
bu27008_get_gain(struct bu27008_data * data,struct iio_gts * gts,int * gain)760ccca97fbSMatti Vaittinen static int bu27008_get_gain(struct bu27008_data *data, struct iio_gts *gts, int *gain)
761ccca97fbSMatti Vaittinen {
762ccca97fbSMatti Vaittinen 	int ret, sel;
763ccca97fbSMatti Vaittinen 
764ccca97fbSMatti Vaittinen 	ret = data->cd->get_gain_sel(data, &sel);
765ccca97fbSMatti Vaittinen 	if (ret)
766ccca97fbSMatti Vaittinen 		return ret;
767ccca97fbSMatti Vaittinen 
768ccca97fbSMatti Vaittinen 	ret = iio_gts_find_gain_by_sel(gts, sel);
769ccca97fbSMatti Vaittinen 	if (ret < 0) {
770ccca97fbSMatti Vaittinen 		dev_err(data->dev, "unknown gain value 0x%x\n", sel);
771ccca97fbSMatti Vaittinen 		return ret;
772ccca97fbSMatti Vaittinen 	}
773ccca97fbSMatti Vaittinen 
774ccca97fbSMatti Vaittinen 	*gain = ret;
775ccca97fbSMatti Vaittinen 
776ccca97fbSMatti Vaittinen 	return 0;
777ccca97fbSMatti Vaittinen }
778ccca97fbSMatti Vaittinen 
bu27008_set_gain(struct bu27008_data * data,int gain)77941ff93d1SMatti Vaittinen static int bu27008_set_gain(struct bu27008_data *data, int gain)
78041ff93d1SMatti Vaittinen {
78141ff93d1SMatti Vaittinen 	int ret;
78241ff93d1SMatti Vaittinen 
78341ff93d1SMatti Vaittinen 	ret = iio_gts_find_sel_by_gain(&data->gts, gain);
78441ff93d1SMatti Vaittinen 	if (ret < 0)
78541ff93d1SMatti Vaittinen 		return ret;
78641ff93d1SMatti Vaittinen 
787ccca97fbSMatti Vaittinen 	return data->cd->write_gain_sel(data, ret);
78841ff93d1SMatti Vaittinen }
78941ff93d1SMatti Vaittinen 
bu27008_get_int_time_sel(struct bu27008_data * data,int * sel)79041ff93d1SMatti Vaittinen static int bu27008_get_int_time_sel(struct bu27008_data *data, int *sel)
79141ff93d1SMatti Vaittinen {
79241ff93d1SMatti Vaittinen 	int ret, val;
79341ff93d1SMatti Vaittinen 
79441ff93d1SMatti Vaittinen 	ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL1, &val);
795ccca97fbSMatti Vaittinen 	if (ret)
79641ff93d1SMatti Vaittinen 		return ret;
797ccca97fbSMatti Vaittinen 
798ccca97fbSMatti Vaittinen 	val &= data->cd->int_time_mask;
799ccca97fbSMatti Vaittinen 	val >>= ffs(data->cd->int_time_mask) - 1;
800ccca97fbSMatti Vaittinen 
801ccca97fbSMatti Vaittinen 	*sel = val;
802ccca97fbSMatti Vaittinen 
803ccca97fbSMatti Vaittinen 	return 0;
80441ff93d1SMatti Vaittinen }
80541ff93d1SMatti Vaittinen 
bu27008_set_int_time_sel(struct bu27008_data * data,int sel)80641ff93d1SMatti Vaittinen static int bu27008_set_int_time_sel(struct bu27008_data *data, int sel)
80741ff93d1SMatti Vaittinen {
808ccca97fbSMatti Vaittinen 	sel <<= ffs(data->cd->int_time_mask) - 1;
809ccca97fbSMatti Vaittinen 
81041ff93d1SMatti Vaittinen 	return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1,
811ccca97fbSMatti Vaittinen 				  data->cd->int_time_mask, sel);
81241ff93d1SMatti Vaittinen }
81341ff93d1SMatti Vaittinen 
bu27008_get_int_time_us(struct bu27008_data * data)81441ff93d1SMatti Vaittinen static int bu27008_get_int_time_us(struct bu27008_data *data)
81541ff93d1SMatti Vaittinen {
81641ff93d1SMatti Vaittinen 	int ret, sel;
81741ff93d1SMatti Vaittinen 
81841ff93d1SMatti Vaittinen 	ret = bu27008_get_int_time_sel(data, &sel);
81941ff93d1SMatti Vaittinen 	if (ret)
82041ff93d1SMatti Vaittinen 		return ret;
82141ff93d1SMatti Vaittinen 
82241ff93d1SMatti Vaittinen 	return iio_gts_find_int_time_by_sel(&data->gts, sel);
82341ff93d1SMatti Vaittinen }
82441ff93d1SMatti Vaittinen 
_bu27008_get_scale(struct bu27008_data * data,bool ir,int * val,int * val2)82541ff93d1SMatti Vaittinen static int _bu27008_get_scale(struct bu27008_data *data, bool ir, int *val,
82641ff93d1SMatti Vaittinen 			      int *val2)
82741ff93d1SMatti Vaittinen {
82841ff93d1SMatti Vaittinen 	struct iio_gts *gts;
82941ff93d1SMatti Vaittinen 	int gain, ret;
83041ff93d1SMatti Vaittinen 
83141ff93d1SMatti Vaittinen 	if (ir)
83241ff93d1SMatti Vaittinen 		gts = &data->gts_ir;
83341ff93d1SMatti Vaittinen 	else
83441ff93d1SMatti Vaittinen 		gts = &data->gts;
83541ff93d1SMatti Vaittinen 
83641ff93d1SMatti Vaittinen 	ret = bu27008_get_gain(data, gts, &gain);
83741ff93d1SMatti Vaittinen 	if (ret)
83841ff93d1SMatti Vaittinen 		return ret;
83941ff93d1SMatti Vaittinen 
84041ff93d1SMatti Vaittinen 	ret = bu27008_get_int_time_us(data);
84141ff93d1SMatti Vaittinen 	if (ret < 0)
84241ff93d1SMatti Vaittinen 		return ret;
84341ff93d1SMatti Vaittinen 
84441ff93d1SMatti Vaittinen 	return iio_gts_get_scale(gts, gain, ret, val, val2);
84541ff93d1SMatti Vaittinen }
84641ff93d1SMatti Vaittinen 
bu27008_get_scale(struct bu27008_data * data,bool ir,int * val,int * val2)84741ff93d1SMatti Vaittinen static int bu27008_get_scale(struct bu27008_data *data, bool ir, int *val,
84841ff93d1SMatti Vaittinen 			     int *val2)
84941ff93d1SMatti Vaittinen {
85041ff93d1SMatti Vaittinen 	int ret;
85141ff93d1SMatti Vaittinen 
85241ff93d1SMatti Vaittinen 	mutex_lock(&data->mutex);
85341ff93d1SMatti Vaittinen 	ret = _bu27008_get_scale(data, ir, val, val2);
85441ff93d1SMatti Vaittinen 	mutex_unlock(&data->mutex);
85541ff93d1SMatti Vaittinen 
85641ff93d1SMatti Vaittinen 	return ret;
85741ff93d1SMatti Vaittinen }
85841ff93d1SMatti Vaittinen 
bu27008_set_int_time(struct bu27008_data * data,int time)85941ff93d1SMatti Vaittinen static int bu27008_set_int_time(struct bu27008_data *data, int time)
86041ff93d1SMatti Vaittinen {
86141ff93d1SMatti Vaittinen 	int ret;
86241ff93d1SMatti Vaittinen 
86341ff93d1SMatti Vaittinen 	ret = iio_gts_find_sel_by_int_time(&data->gts, time);
86441ff93d1SMatti Vaittinen 	if (ret < 0)
86541ff93d1SMatti Vaittinen 		return ret;
86641ff93d1SMatti Vaittinen 
867ccca97fbSMatti Vaittinen 	return bu27008_set_int_time_sel(data, ret);
86841ff93d1SMatti Vaittinen }
86941ff93d1SMatti Vaittinen 
87041ff93d1SMatti Vaittinen /* Try to change the time so that the scale is maintained */
bu27008_try_set_int_time(struct bu27008_data * data,int int_time_new)87141ff93d1SMatti Vaittinen static int bu27008_try_set_int_time(struct bu27008_data *data, int int_time_new)
87241ff93d1SMatti Vaittinen {
87341ff93d1SMatti Vaittinen 	int ret, old_time_sel, new_time_sel,  old_gain, new_gain;
87441ff93d1SMatti Vaittinen 
87541ff93d1SMatti Vaittinen 	mutex_lock(&data->mutex);
87641ff93d1SMatti Vaittinen 
87741ff93d1SMatti Vaittinen 	ret = bu27008_get_int_time_sel(data, &old_time_sel);
87841ff93d1SMatti Vaittinen 	if (ret < 0)
87941ff93d1SMatti Vaittinen 		goto unlock_out;
88041ff93d1SMatti Vaittinen 
88141ff93d1SMatti Vaittinen 	if (!iio_gts_valid_time(&data->gts, int_time_new)) {
88241ff93d1SMatti Vaittinen 		dev_dbg(data->dev, "Unsupported integration time %u\n",
88341ff93d1SMatti Vaittinen 			int_time_new);
88441ff93d1SMatti Vaittinen 
88541ff93d1SMatti Vaittinen 		ret = -EINVAL;
88641ff93d1SMatti Vaittinen 		goto unlock_out;
88741ff93d1SMatti Vaittinen 	}
88841ff93d1SMatti Vaittinen 
88941ff93d1SMatti Vaittinen 	/* If we already use requested time, then we're done */
89041ff93d1SMatti Vaittinen 	new_time_sel = iio_gts_find_sel_by_int_time(&data->gts, int_time_new);
89141ff93d1SMatti Vaittinen 	if (new_time_sel == old_time_sel)
89241ff93d1SMatti Vaittinen 		goto unlock_out;
89341ff93d1SMatti Vaittinen 
89441ff93d1SMatti Vaittinen 	ret = bu27008_get_gain(data, &data->gts, &old_gain);
89541ff93d1SMatti Vaittinen 	if (ret)
89641ff93d1SMatti Vaittinen 		goto unlock_out;
89741ff93d1SMatti Vaittinen 
89841ff93d1SMatti Vaittinen 	ret = iio_gts_find_new_gain_sel_by_old_gain_time(&data->gts, old_gain,
89941ff93d1SMatti Vaittinen 				old_time_sel, new_time_sel, &new_gain);
90041ff93d1SMatti Vaittinen 	if (ret) {
90141ff93d1SMatti Vaittinen 		int scale1, scale2;
90241ff93d1SMatti Vaittinen 		bool ok;
90341ff93d1SMatti Vaittinen 
90441ff93d1SMatti Vaittinen 		_bu27008_get_scale(data, false, &scale1, &scale2);
90541ff93d1SMatti Vaittinen 		dev_dbg(data->dev,
90641ff93d1SMatti Vaittinen 			"Can't support time %u with current scale %u %u\n",
90741ff93d1SMatti Vaittinen 			int_time_new, scale1, scale2);
90841ff93d1SMatti Vaittinen 
90941ff93d1SMatti Vaittinen 		if (new_gain < 0)
91041ff93d1SMatti Vaittinen 			goto unlock_out;
91141ff93d1SMatti Vaittinen 
91241ff93d1SMatti Vaittinen 		/*
91341ff93d1SMatti Vaittinen 		 * If caller requests for integration time change and we
91441ff93d1SMatti Vaittinen 		 * can't support the scale - then the caller should be
91541ff93d1SMatti Vaittinen 		 * prepared to 'pick up the pieces and deal with the
91641ff93d1SMatti Vaittinen 		 * fact that the scale changed'.
91741ff93d1SMatti Vaittinen 		 */
91841ff93d1SMatti Vaittinen 		ret = iio_find_closest_gain_low(&data->gts, new_gain, &ok);
91941ff93d1SMatti Vaittinen 		if (!ok)
92041ff93d1SMatti Vaittinen 			dev_dbg(data->dev, "optimal gain out of range\n");
92141ff93d1SMatti Vaittinen 
92241ff93d1SMatti Vaittinen 		if (ret < 0) {
92341ff93d1SMatti Vaittinen 			dev_dbg(data->dev,
92441ff93d1SMatti Vaittinen 				 "Total gain increase. Risk of saturation");
92541ff93d1SMatti Vaittinen 			ret = iio_gts_get_min_gain(&data->gts);
92641ff93d1SMatti Vaittinen 			if (ret < 0)
92741ff93d1SMatti Vaittinen 				goto unlock_out;
92841ff93d1SMatti Vaittinen 		}
92941ff93d1SMatti Vaittinen 		new_gain = ret;
93041ff93d1SMatti Vaittinen 		dev_dbg(data->dev, "scale changed, new gain %u\n", new_gain);
93141ff93d1SMatti Vaittinen 	}
93241ff93d1SMatti Vaittinen 
93341ff93d1SMatti Vaittinen 	ret = bu27008_set_gain(data, new_gain);
93441ff93d1SMatti Vaittinen 	if (ret)
93541ff93d1SMatti Vaittinen 		goto unlock_out;
93641ff93d1SMatti Vaittinen 
93741ff93d1SMatti Vaittinen 	ret = bu27008_set_int_time(data, int_time_new);
93841ff93d1SMatti Vaittinen 
93941ff93d1SMatti Vaittinen unlock_out:
94041ff93d1SMatti Vaittinen 	mutex_unlock(&data->mutex);
94141ff93d1SMatti Vaittinen 
94241ff93d1SMatti Vaittinen 	return ret;
94341ff93d1SMatti Vaittinen }
94441ff93d1SMatti Vaittinen 
bu27008_meas_set(struct bu27008_data * data,bool enable)945ccca97fbSMatti Vaittinen static int bu27008_meas_set(struct bu27008_data *data, bool enable)
94641ff93d1SMatti Vaittinen {
947ccca97fbSMatti Vaittinen 	if (enable)
948ccca97fbSMatti Vaittinen 		return regmap_set_bits(data->regmap, data->cd->meas_en_reg,
949ccca97fbSMatti Vaittinen 				       data->cd->meas_en_mask);
950ccca97fbSMatti Vaittinen 	return regmap_clear_bits(data->regmap, data->cd->meas_en_reg,
951ccca97fbSMatti Vaittinen 				 data->cd->meas_en_mask);
95241ff93d1SMatti Vaittinen }
95341ff93d1SMatti Vaittinen 
bu27008_chan_cfg(struct bu27008_data * data,struct iio_chan_spec const * chan)95441ff93d1SMatti Vaittinen static int bu27008_chan_cfg(struct bu27008_data *data,
95541ff93d1SMatti Vaittinen 			    struct iio_chan_spec const *chan)
95641ff93d1SMatti Vaittinen {
95741ff93d1SMatti Vaittinen 	int chan_sel;
95841ff93d1SMatti Vaittinen 
95941ff93d1SMatti Vaittinen 	if (chan->scan_index == BU27008_BLUE)
96041ff93d1SMatti Vaittinen 		chan_sel = BU27008_BLUE2_CLEAR3;
96141ff93d1SMatti Vaittinen 	else
96241ff93d1SMatti Vaittinen 		chan_sel = BU27008_CLEAR2_IR3;
96341ff93d1SMatti Vaittinen 
964ccca97fbSMatti Vaittinen 	/*
965ccca97fbSMatti Vaittinen 	 * prepare bitfield for channel sel. The FIELD_PREP works only when
966ccca97fbSMatti Vaittinen 	 * mask is constant. In our case the mask is assigned based on the
967ccca97fbSMatti Vaittinen 	 * chip type. Hence the open-coded FIELD_PREP here. We don't bother
968ccca97fbSMatti Vaittinen 	 * zeroing the irrelevant bits though - update_bits takes care of that.
969ccca97fbSMatti Vaittinen 	 */
970ccca97fbSMatti Vaittinen 	chan_sel <<= ffs(data->cd->chan_sel_mask) - 1;
97141ff93d1SMatti Vaittinen 
972ccca97fbSMatti Vaittinen 	return regmap_update_bits(data->regmap, data->cd->chan_sel_reg,
97341ff93d1SMatti Vaittinen 				  BU27008_MASK_CHAN_SEL, chan_sel);
97441ff93d1SMatti Vaittinen }
97541ff93d1SMatti Vaittinen 
bu27008_read_one(struct bu27008_data * data,struct iio_dev * idev,struct iio_chan_spec const * chan,int * val,int * val2)97641ff93d1SMatti Vaittinen static int bu27008_read_one(struct bu27008_data *data, struct iio_dev *idev,
97741ff93d1SMatti Vaittinen 			    struct iio_chan_spec const *chan, int *val, int *val2)
97841ff93d1SMatti Vaittinen {
97941ff93d1SMatti Vaittinen 	int ret, int_time;
98041ff93d1SMatti Vaittinen 
98141ff93d1SMatti Vaittinen 	ret = bu27008_chan_cfg(data, chan);
98241ff93d1SMatti Vaittinen 	if (ret)
98341ff93d1SMatti Vaittinen 		return ret;
98441ff93d1SMatti Vaittinen 
985ccca97fbSMatti Vaittinen 	ret = bu27008_meas_set(data, true);
98641ff93d1SMatti Vaittinen 	if (ret)
98741ff93d1SMatti Vaittinen 		return ret;
98841ff93d1SMatti Vaittinen 
98941ff93d1SMatti Vaittinen 	ret = bu27008_get_int_time_us(data);
99041ff93d1SMatti Vaittinen 	if (ret < 0)
99141ff93d1SMatti Vaittinen 		int_time = BU27008_MEAS_TIME_MAX_MS;
99241ff93d1SMatti Vaittinen 	else
99341ff93d1SMatti Vaittinen 		int_time = ret / USEC_PER_MSEC;
99441ff93d1SMatti Vaittinen 
99541ff93d1SMatti Vaittinen 	msleep(int_time);
99641ff93d1SMatti Vaittinen 
99741ff93d1SMatti Vaittinen 	ret = bu27008_chan_read_data(data, chan->address, val);
99841ff93d1SMatti Vaittinen 	if (!ret)
99941ff93d1SMatti Vaittinen 		ret = IIO_VAL_INT;
100041ff93d1SMatti Vaittinen 
1001ccca97fbSMatti Vaittinen 	if (bu27008_meas_set(data, false))
100241ff93d1SMatti Vaittinen 		dev_warn(data->dev, "measurement disabling failed\n");
100341ff93d1SMatti Vaittinen 
100441ff93d1SMatti Vaittinen 	return ret;
100541ff93d1SMatti Vaittinen }
100641ff93d1SMatti Vaittinen 
bu27008_read_raw(struct iio_dev * idev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)100741ff93d1SMatti Vaittinen static int bu27008_read_raw(struct iio_dev *idev,
100841ff93d1SMatti Vaittinen 			   struct iio_chan_spec const *chan,
100941ff93d1SMatti Vaittinen 			   int *val, int *val2, long mask)
101041ff93d1SMatti Vaittinen {
101141ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_priv(idev);
101241ff93d1SMatti Vaittinen 	int busy, ret;
101341ff93d1SMatti Vaittinen 
101441ff93d1SMatti Vaittinen 	switch (mask) {
101541ff93d1SMatti Vaittinen 	case IIO_CHAN_INFO_RAW:
101641ff93d1SMatti Vaittinen 		busy = iio_device_claim_direct_mode(idev);
101741ff93d1SMatti Vaittinen 		if (busy)
101841ff93d1SMatti Vaittinen 			return -EBUSY;
101941ff93d1SMatti Vaittinen 
102041ff93d1SMatti Vaittinen 		mutex_lock(&data->mutex);
102141ff93d1SMatti Vaittinen 		ret = bu27008_read_one(data, idev, chan, val, val2);
102241ff93d1SMatti Vaittinen 		mutex_unlock(&data->mutex);
102341ff93d1SMatti Vaittinen 
102441ff93d1SMatti Vaittinen 		iio_device_release_direct_mode(idev);
102541ff93d1SMatti Vaittinen 
102641ff93d1SMatti Vaittinen 		return ret;
102741ff93d1SMatti Vaittinen 
102841ff93d1SMatti Vaittinen 	case IIO_CHAN_INFO_SCALE:
102941ff93d1SMatti Vaittinen 		ret = bu27008_get_scale(data, chan->scan_index == BU27008_IR,
103041ff93d1SMatti Vaittinen 					val, val2);
103141ff93d1SMatti Vaittinen 		if (ret)
103241ff93d1SMatti Vaittinen 			return ret;
103341ff93d1SMatti Vaittinen 
103441ff93d1SMatti Vaittinen 		return IIO_VAL_INT_PLUS_NANO;
103541ff93d1SMatti Vaittinen 
103641ff93d1SMatti Vaittinen 	case IIO_CHAN_INFO_INT_TIME:
103741ff93d1SMatti Vaittinen 		ret = bu27008_get_int_time_us(data);
103841ff93d1SMatti Vaittinen 		if (ret < 0)
103941ff93d1SMatti Vaittinen 			return ret;
104041ff93d1SMatti Vaittinen 
104141ff93d1SMatti Vaittinen 		*val = 0;
104241ff93d1SMatti Vaittinen 		*val2 = ret;
104341ff93d1SMatti Vaittinen 
104441ff93d1SMatti Vaittinen 		return IIO_VAL_INT_PLUS_MICRO;
104541ff93d1SMatti Vaittinen 
104641ff93d1SMatti Vaittinen 	default:
104741ff93d1SMatti Vaittinen 		return -EINVAL;
104841ff93d1SMatti Vaittinen 	}
104941ff93d1SMatti Vaittinen }
105041ff93d1SMatti Vaittinen 
105141ff93d1SMatti Vaittinen /* Called if the new scale could not be supported with existing int-time */
bu27008_try_find_new_time_gain(struct bu27008_data * data,int val,int val2,int * gain_sel)105241ff93d1SMatti Vaittinen static int bu27008_try_find_new_time_gain(struct bu27008_data *data, int val,
105341ff93d1SMatti Vaittinen 					  int val2, int *gain_sel)
105441ff93d1SMatti Vaittinen {
105541ff93d1SMatti Vaittinen 	int i, ret, new_time_sel;
105641ff93d1SMatti Vaittinen 
105741ff93d1SMatti Vaittinen 	for (i = 0; i < data->gts.num_itime; i++) {
105841ff93d1SMatti Vaittinen 		new_time_sel = data->gts.itime_table[i].sel;
105941ff93d1SMatti Vaittinen 		ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts,
1060096649cdSMatti Vaittinen 					new_time_sel, val, val2, gain_sel);
106141ff93d1SMatti Vaittinen 		if (!ret)
106241ff93d1SMatti Vaittinen 			break;
106341ff93d1SMatti Vaittinen 	}
106441ff93d1SMatti Vaittinen 	if (i == data->gts.num_itime) {
106541ff93d1SMatti Vaittinen 		dev_err(data->dev, "Can't support scale %u %u\n", val, val2);
106641ff93d1SMatti Vaittinen 
106741ff93d1SMatti Vaittinen 		return -EINVAL;
106841ff93d1SMatti Vaittinen 	}
106941ff93d1SMatti Vaittinen 
107041ff93d1SMatti Vaittinen 	return bu27008_set_int_time_sel(data, new_time_sel);
107141ff93d1SMatti Vaittinen }
107241ff93d1SMatti Vaittinen 
bu27008_set_scale(struct bu27008_data * data,struct iio_chan_spec const * chan,int val,int val2)107341ff93d1SMatti Vaittinen static int bu27008_set_scale(struct bu27008_data *data,
107441ff93d1SMatti Vaittinen 			     struct iio_chan_spec const *chan,
107541ff93d1SMatti Vaittinen 			     int val, int val2)
107641ff93d1SMatti Vaittinen {
107741ff93d1SMatti Vaittinen 	int ret, gain_sel, time_sel;
107841ff93d1SMatti Vaittinen 
107941ff93d1SMatti Vaittinen 	if (chan->scan_index == BU27008_IR)
108041ff93d1SMatti Vaittinen 		return -EINVAL;
108141ff93d1SMatti Vaittinen 
108241ff93d1SMatti Vaittinen 	mutex_lock(&data->mutex);
108341ff93d1SMatti Vaittinen 
108441ff93d1SMatti Vaittinen 	ret = bu27008_get_int_time_sel(data, &time_sel);
108541ff93d1SMatti Vaittinen 	if (ret < 0)
108641ff93d1SMatti Vaittinen 		goto unlock_out;
108741ff93d1SMatti Vaittinen 
108841ff93d1SMatti Vaittinen 	ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel,
1089096649cdSMatti Vaittinen 						val, val2, &gain_sel);
109041ff93d1SMatti Vaittinen 	if (ret) {
109141ff93d1SMatti Vaittinen 		ret = bu27008_try_find_new_time_gain(data, val, val2, &gain_sel);
109241ff93d1SMatti Vaittinen 		if (ret)
109341ff93d1SMatti Vaittinen 			goto unlock_out;
109441ff93d1SMatti Vaittinen 
109541ff93d1SMatti Vaittinen 	}
1096ccca97fbSMatti Vaittinen 	ret = data->cd->write_gain_sel(data, gain_sel);
109741ff93d1SMatti Vaittinen 
109841ff93d1SMatti Vaittinen unlock_out:
109941ff93d1SMatti Vaittinen 	mutex_unlock(&data->mutex);
110041ff93d1SMatti Vaittinen 
110141ff93d1SMatti Vaittinen 	return ret;
110241ff93d1SMatti Vaittinen }
110341ff93d1SMatti Vaittinen 
bu27008_write_raw_get_fmt(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,long mask)1104096649cdSMatti Vaittinen static int bu27008_write_raw_get_fmt(struct iio_dev *indio_dev,
1105096649cdSMatti Vaittinen 				     struct iio_chan_spec const *chan,
1106096649cdSMatti Vaittinen 				     long mask)
1107096649cdSMatti Vaittinen {
1108096649cdSMatti Vaittinen 
1109096649cdSMatti Vaittinen 	switch (mask) {
1110096649cdSMatti Vaittinen 	case IIO_CHAN_INFO_SCALE:
1111096649cdSMatti Vaittinen 		return IIO_VAL_INT_PLUS_NANO;
1112096649cdSMatti Vaittinen 	case IIO_CHAN_INFO_INT_TIME:
1113096649cdSMatti Vaittinen 		return IIO_VAL_INT_PLUS_MICRO;
1114096649cdSMatti Vaittinen 	default:
1115096649cdSMatti Vaittinen 		return -EINVAL;
1116096649cdSMatti Vaittinen 	}
1117096649cdSMatti Vaittinen }
1118096649cdSMatti Vaittinen 
bu27008_write_raw(struct iio_dev * idev,struct iio_chan_spec const * chan,int val,int val2,long mask)111941ff93d1SMatti Vaittinen static int bu27008_write_raw(struct iio_dev *idev,
112041ff93d1SMatti Vaittinen 			     struct iio_chan_spec const *chan,
112141ff93d1SMatti Vaittinen 			     int val, int val2, long mask)
112241ff93d1SMatti Vaittinen {
112341ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_priv(idev);
112441ff93d1SMatti Vaittinen 	int ret;
112541ff93d1SMatti Vaittinen 
112641ff93d1SMatti Vaittinen 	/*
112741ff93d1SMatti Vaittinen 	 * Do not allow changing scale when measurement is ongoing as doing so
112841ff93d1SMatti Vaittinen 	 * could make values in the buffer inconsistent.
112941ff93d1SMatti Vaittinen 	 */
113041ff93d1SMatti Vaittinen 	ret = iio_device_claim_direct_mode(idev);
113141ff93d1SMatti Vaittinen 	if (ret)
113241ff93d1SMatti Vaittinen 		return ret;
113341ff93d1SMatti Vaittinen 
113441ff93d1SMatti Vaittinen 	switch (mask) {
113541ff93d1SMatti Vaittinen 	case IIO_CHAN_INFO_SCALE:
113641ff93d1SMatti Vaittinen 		ret = bu27008_set_scale(data, chan, val, val2);
113741ff93d1SMatti Vaittinen 		break;
113841ff93d1SMatti Vaittinen 	case IIO_CHAN_INFO_INT_TIME:
113941ff93d1SMatti Vaittinen 		if (val) {
114041ff93d1SMatti Vaittinen 			ret = -EINVAL;
114141ff93d1SMatti Vaittinen 			break;
114241ff93d1SMatti Vaittinen 		}
114341ff93d1SMatti Vaittinen 		ret = bu27008_try_set_int_time(data, val2);
114441ff93d1SMatti Vaittinen 		break;
114541ff93d1SMatti Vaittinen 	default:
114641ff93d1SMatti Vaittinen 		ret = -EINVAL;
114741ff93d1SMatti Vaittinen 		break;
114841ff93d1SMatti Vaittinen 	}
114941ff93d1SMatti Vaittinen 	iio_device_release_direct_mode(idev);
115041ff93d1SMatti Vaittinen 
115141ff93d1SMatti Vaittinen 	return ret;
115241ff93d1SMatti Vaittinen }
115341ff93d1SMatti Vaittinen 
bu27008_read_avail(struct iio_dev * idev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)115441ff93d1SMatti Vaittinen static int bu27008_read_avail(struct iio_dev *idev,
115541ff93d1SMatti Vaittinen 			      struct iio_chan_spec const *chan, const int **vals,
115641ff93d1SMatti Vaittinen 			      int *type, int *length, long mask)
115741ff93d1SMatti Vaittinen {
115841ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_priv(idev);
115941ff93d1SMatti Vaittinen 
116041ff93d1SMatti Vaittinen 	switch (mask) {
116141ff93d1SMatti Vaittinen 	case IIO_CHAN_INFO_INT_TIME:
116241ff93d1SMatti Vaittinen 		return iio_gts_avail_times(&data->gts, vals, type, length);
116341ff93d1SMatti Vaittinen 	case IIO_CHAN_INFO_SCALE:
116441ff93d1SMatti Vaittinen 		if (chan->channel2 == IIO_MOD_LIGHT_IR)
116541ff93d1SMatti Vaittinen 			return iio_gts_all_avail_scales(&data->gts_ir, vals,
116641ff93d1SMatti Vaittinen 							type, length);
116741ff93d1SMatti Vaittinen 		return iio_gts_all_avail_scales(&data->gts, vals, type, length);
116841ff93d1SMatti Vaittinen 	default:
116941ff93d1SMatti Vaittinen 		return -EINVAL;
117041ff93d1SMatti Vaittinen 	}
117141ff93d1SMatti Vaittinen }
117241ff93d1SMatti Vaittinen 
bu27008_update_scan_mode(struct iio_dev * idev,const unsigned long * scan_mask)117341ff93d1SMatti Vaittinen static int bu27008_update_scan_mode(struct iio_dev *idev,
117441ff93d1SMatti Vaittinen 				    const unsigned long *scan_mask)
117541ff93d1SMatti Vaittinen {
117641ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_priv(idev);
117741ff93d1SMatti Vaittinen 	int chan_sel;
117841ff93d1SMatti Vaittinen 
117941ff93d1SMatti Vaittinen 	/* Configure channel selection */
118041ff93d1SMatti Vaittinen 	if (test_bit(BU27008_BLUE, idev->active_scan_mask)) {
118141ff93d1SMatti Vaittinen 		if (test_bit(BU27008_CLEAR, idev->active_scan_mask))
118241ff93d1SMatti Vaittinen 			chan_sel = BU27008_BLUE2_CLEAR3;
118341ff93d1SMatti Vaittinen 		else
118441ff93d1SMatti Vaittinen 			chan_sel = BU27008_BLUE2_IR3;
118541ff93d1SMatti Vaittinen 	} else {
118641ff93d1SMatti Vaittinen 		chan_sel = BU27008_CLEAR2_IR3;
118741ff93d1SMatti Vaittinen 	}
118841ff93d1SMatti Vaittinen 
1189ccca97fbSMatti Vaittinen 	chan_sel <<= ffs(data->cd->chan_sel_mask) - 1;
119041ff93d1SMatti Vaittinen 
1191ccca97fbSMatti Vaittinen 	return regmap_update_bits(data->regmap, data->cd->chan_sel_reg,
1192ccca97fbSMatti Vaittinen 				  data->cd->chan_sel_mask, chan_sel);
119341ff93d1SMatti Vaittinen }
119441ff93d1SMatti Vaittinen 
119541ff93d1SMatti Vaittinen static const struct iio_info bu27008_info = {
119641ff93d1SMatti Vaittinen 	.read_raw = &bu27008_read_raw,
119741ff93d1SMatti Vaittinen 	.write_raw = &bu27008_write_raw,
1198096649cdSMatti Vaittinen 	.write_raw_get_fmt = &bu27008_write_raw_get_fmt,
119941ff93d1SMatti Vaittinen 	.read_avail = &bu27008_read_avail,
120041ff93d1SMatti Vaittinen 	.update_scan_mode = bu27008_update_scan_mode,
120141ff93d1SMatti Vaittinen 	.validate_trigger = iio_validate_own_trigger,
120241ff93d1SMatti Vaittinen };
120341ff93d1SMatti Vaittinen 
bu27008_trigger_set_state(struct iio_trigger * trig,bool state)1204ccca97fbSMatti Vaittinen static int bu27008_trigger_set_state(struct iio_trigger *trig, bool state)
120541ff93d1SMatti Vaittinen {
120641ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_trigger_get_drvdata(trig);
120741ff93d1SMatti Vaittinen 	int ret;
120841ff93d1SMatti Vaittinen 
1209ccca97fbSMatti Vaittinen 
121041ff93d1SMatti Vaittinen 	if (state)
1211ccca97fbSMatti Vaittinen 		ret = regmap_set_bits(data->regmap, data->cd->drdy_en_reg,
1212ccca97fbSMatti Vaittinen 				      data->cd->drdy_en_mask);
121341ff93d1SMatti Vaittinen 	else
1214ccca97fbSMatti Vaittinen 		ret = regmap_clear_bits(data->regmap, data->cd->drdy_en_reg,
1215ccca97fbSMatti Vaittinen 					data->cd->drdy_en_mask);
121641ff93d1SMatti Vaittinen 	if (ret)
121741ff93d1SMatti Vaittinen 		dev_err(data->dev, "Failed to set trigger state\n");
121841ff93d1SMatti Vaittinen 
121941ff93d1SMatti Vaittinen 	return ret;
122041ff93d1SMatti Vaittinen }
122141ff93d1SMatti Vaittinen 
bu27008_trigger_reenable(struct iio_trigger * trig)122241ff93d1SMatti Vaittinen static void bu27008_trigger_reenable(struct iio_trigger *trig)
122341ff93d1SMatti Vaittinen {
122441ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_trigger_get_drvdata(trig);
122541ff93d1SMatti Vaittinen 
122641ff93d1SMatti Vaittinen 	enable_irq(data->irq);
122741ff93d1SMatti Vaittinen }
122841ff93d1SMatti Vaittinen 
122941ff93d1SMatti Vaittinen static const struct iio_trigger_ops bu27008_trigger_ops = {
123041ff93d1SMatti Vaittinen 	.set_trigger_state = bu27008_trigger_set_state,
123141ff93d1SMatti Vaittinen 	.reenable = bu27008_trigger_reenable,
123241ff93d1SMatti Vaittinen };
123341ff93d1SMatti Vaittinen 
bu27008_trigger_handler(int irq,void * p)123441ff93d1SMatti Vaittinen static irqreturn_t bu27008_trigger_handler(int irq, void *p)
123541ff93d1SMatti Vaittinen {
123641ff93d1SMatti Vaittinen 	struct iio_poll_func *pf = p;
123741ff93d1SMatti Vaittinen 	struct iio_dev *idev = pf->indio_dev;
123841ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_priv(idev);
123941ff93d1SMatti Vaittinen 	struct {
124041ff93d1SMatti Vaittinen 		__le16 chan[BU27008_NUM_HW_CHANS];
124141ff93d1SMatti Vaittinen 		s64 ts __aligned(8);
124241ff93d1SMatti Vaittinen 	} raw;
124341ff93d1SMatti Vaittinen 	int ret, dummy;
124441ff93d1SMatti Vaittinen 
124541ff93d1SMatti Vaittinen 	memset(&raw, 0, sizeof(raw));
124641ff93d1SMatti Vaittinen 
124741ff93d1SMatti Vaittinen 	/*
124841ff93d1SMatti Vaittinen 	 * After some measurements, it seems reading the
124941ff93d1SMatti Vaittinen 	 * BU27008_REG_MODE_CONTROL3 debounces the IRQ line
125041ff93d1SMatti Vaittinen 	 */
1251ccca97fbSMatti Vaittinen 	ret = regmap_read(data->regmap, data->cd->valid_reg, &dummy);
125241ff93d1SMatti Vaittinen 	if (ret < 0)
125341ff93d1SMatti Vaittinen 		goto err_read;
125441ff93d1SMatti Vaittinen 
125541ff93d1SMatti Vaittinen 	ret = regmap_bulk_read(data->regmap, BU27008_REG_DATA0_LO, &raw.chan,
125641ff93d1SMatti Vaittinen 			       sizeof(raw.chan));
125741ff93d1SMatti Vaittinen 	if (ret < 0)
125841ff93d1SMatti Vaittinen 		goto err_read;
125941ff93d1SMatti Vaittinen 
126041ff93d1SMatti Vaittinen 	iio_push_to_buffers_with_timestamp(idev, &raw, pf->timestamp);
126141ff93d1SMatti Vaittinen err_read:
126241ff93d1SMatti Vaittinen 	iio_trigger_notify_done(idev->trig);
126341ff93d1SMatti Vaittinen 
126441ff93d1SMatti Vaittinen 	return IRQ_HANDLED;
126541ff93d1SMatti Vaittinen }
126641ff93d1SMatti Vaittinen 
bu27008_buffer_preenable(struct iio_dev * idev)126741ff93d1SMatti Vaittinen static int bu27008_buffer_preenable(struct iio_dev *idev)
126841ff93d1SMatti Vaittinen {
126941ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_priv(idev);
127041ff93d1SMatti Vaittinen 
1271ccca97fbSMatti Vaittinen 	return bu27008_meas_set(data, true);
127241ff93d1SMatti Vaittinen }
127341ff93d1SMatti Vaittinen 
bu27008_buffer_postdisable(struct iio_dev * idev)127441ff93d1SMatti Vaittinen static int bu27008_buffer_postdisable(struct iio_dev *idev)
127541ff93d1SMatti Vaittinen {
127641ff93d1SMatti Vaittinen 	struct bu27008_data *data = iio_priv(idev);
127741ff93d1SMatti Vaittinen 
1278ccca97fbSMatti Vaittinen 	return bu27008_meas_set(data, false);
127941ff93d1SMatti Vaittinen }
128041ff93d1SMatti Vaittinen 
128141ff93d1SMatti Vaittinen static const struct iio_buffer_setup_ops bu27008_buffer_ops = {
128241ff93d1SMatti Vaittinen 	.preenable = bu27008_buffer_preenable,
128341ff93d1SMatti Vaittinen 	.postdisable = bu27008_buffer_postdisable,
128441ff93d1SMatti Vaittinen };
128541ff93d1SMatti Vaittinen 
bu27008_data_rdy_poll(int irq,void * private)128641ff93d1SMatti Vaittinen static irqreturn_t bu27008_data_rdy_poll(int irq, void *private)
128741ff93d1SMatti Vaittinen {
128841ff93d1SMatti Vaittinen 	/*
128941ff93d1SMatti Vaittinen 	 * The BU27008 keeps IRQ asserted until we read the VALID bit from
129041ff93d1SMatti Vaittinen 	 * a register. We need to keep the IRQ disabled until then.
129141ff93d1SMatti Vaittinen 	 */
129241ff93d1SMatti Vaittinen 	disable_irq_nosync(irq);
129341ff93d1SMatti Vaittinen 	iio_trigger_poll(private);
129441ff93d1SMatti Vaittinen 
129541ff93d1SMatti Vaittinen 	return IRQ_HANDLED;
129641ff93d1SMatti Vaittinen }
129741ff93d1SMatti Vaittinen 
bu27008_setup_trigger(struct bu27008_data * data,struct iio_dev * idev)129841ff93d1SMatti Vaittinen static int bu27008_setup_trigger(struct bu27008_data *data, struct iio_dev *idev)
129941ff93d1SMatti Vaittinen {
130041ff93d1SMatti Vaittinen 	struct iio_trigger *itrig;
130141ff93d1SMatti Vaittinen 	char *name;
130241ff93d1SMatti Vaittinen 	int ret;
130341ff93d1SMatti Vaittinen 
130441ff93d1SMatti Vaittinen 	ret = devm_iio_triggered_buffer_setup(data->dev, idev,
130541ff93d1SMatti Vaittinen 					      &iio_pollfunc_store_time,
130641ff93d1SMatti Vaittinen 					      bu27008_trigger_handler,
130741ff93d1SMatti Vaittinen 					      &bu27008_buffer_ops);
130841ff93d1SMatti Vaittinen 	if (ret)
130941ff93d1SMatti Vaittinen 		return dev_err_probe(data->dev, ret,
131041ff93d1SMatti Vaittinen 			     "iio_triggered_buffer_setup_ext FAIL\n");
131141ff93d1SMatti Vaittinen 
131241ff93d1SMatti Vaittinen 	itrig = devm_iio_trigger_alloc(data->dev, "%sdata-rdy-dev%d",
131341ff93d1SMatti Vaittinen 				       idev->name, iio_device_id(idev));
131441ff93d1SMatti Vaittinen 	if (!itrig)
131541ff93d1SMatti Vaittinen 		return -ENOMEM;
131641ff93d1SMatti Vaittinen 
131741ff93d1SMatti Vaittinen 	data->trig = itrig;
131841ff93d1SMatti Vaittinen 
131941ff93d1SMatti Vaittinen 	itrig->ops = &bu27008_trigger_ops;
132041ff93d1SMatti Vaittinen 	iio_trigger_set_drvdata(itrig, data);
132141ff93d1SMatti Vaittinen 
132241ff93d1SMatti Vaittinen 	name = devm_kasprintf(data->dev, GFP_KERNEL, "%s-bu27008",
132341ff93d1SMatti Vaittinen 			      dev_name(data->dev));
132441ff93d1SMatti Vaittinen 
132541ff93d1SMatti Vaittinen 	ret = devm_request_irq(data->dev, data->irq,
132641ff93d1SMatti Vaittinen 			       &bu27008_data_rdy_poll,
132741ff93d1SMatti Vaittinen 			       0, name, itrig);
132841ff93d1SMatti Vaittinen 	if (ret)
132941ff93d1SMatti Vaittinen 		return dev_err_probe(data->dev, ret, "Could not request IRQ\n");
133041ff93d1SMatti Vaittinen 
133141ff93d1SMatti Vaittinen 	ret = devm_iio_trigger_register(data->dev, itrig);
133241ff93d1SMatti Vaittinen 	if (ret)
133341ff93d1SMatti Vaittinen 		return dev_err_probe(data->dev, ret,
133441ff93d1SMatti Vaittinen 				     "Trigger registration failed\n");
133541ff93d1SMatti Vaittinen 
133641ff93d1SMatti Vaittinen 	/* set default trigger */
133741ff93d1SMatti Vaittinen 	idev->trig = iio_trigger_get(itrig);
133841ff93d1SMatti Vaittinen 
133941ff93d1SMatti Vaittinen 	return 0;
134041ff93d1SMatti Vaittinen }
134141ff93d1SMatti Vaittinen 
bu27008_probe(struct i2c_client * i2c)134241ff93d1SMatti Vaittinen static int bu27008_probe(struct i2c_client *i2c)
134341ff93d1SMatti Vaittinen {
134441ff93d1SMatti Vaittinen 	struct device *dev = &i2c->dev;
134541ff93d1SMatti Vaittinen 	struct bu27008_data *data;
134641ff93d1SMatti Vaittinen 	struct regmap *regmap;
134741ff93d1SMatti Vaittinen 	unsigned int part_id, reg;
134841ff93d1SMatti Vaittinen 	struct iio_dev *idev;
134941ff93d1SMatti Vaittinen 	int ret;
135041ff93d1SMatti Vaittinen 
135141ff93d1SMatti Vaittinen 	idev = devm_iio_device_alloc(dev, sizeof(*data));
135241ff93d1SMatti Vaittinen 	if (!idev)
135341ff93d1SMatti Vaittinen 		return -ENOMEM;
135441ff93d1SMatti Vaittinen 
135541ff93d1SMatti Vaittinen 	ret = devm_regulator_get_enable(dev, "vdd");
135641ff93d1SMatti Vaittinen 	if (ret)
135741ff93d1SMatti Vaittinen 		return dev_err_probe(dev, ret, "Failed to get regulator\n");
135841ff93d1SMatti Vaittinen 
135941ff93d1SMatti Vaittinen 	data = iio_priv(idev);
136041ff93d1SMatti Vaittinen 
1361ccca97fbSMatti Vaittinen 	data->cd = device_get_match_data(&i2c->dev);
1362ccca97fbSMatti Vaittinen 	if (!data->cd)
1363ccca97fbSMatti Vaittinen 		return -ENODEV;
1364ccca97fbSMatti Vaittinen 
1365ccca97fbSMatti Vaittinen 	regmap = devm_regmap_init_i2c(i2c, data->cd->regmap_cfg);
1366ccca97fbSMatti Vaittinen 	if (IS_ERR(regmap))
1367ccca97fbSMatti Vaittinen 		return dev_err_probe(dev, PTR_ERR(regmap),
1368ccca97fbSMatti Vaittinen 				     "Failed to initialize Regmap\n");
1369ccca97fbSMatti Vaittinen 
1370ccca97fbSMatti Vaittinen 
137141ff93d1SMatti Vaittinen 	ret = regmap_read(regmap, BU27008_REG_SYSTEM_CONTROL, &reg);
137241ff93d1SMatti Vaittinen 	if (ret)
137341ff93d1SMatti Vaittinen 		return dev_err_probe(dev, ret, "Failed to access sensor\n");
137441ff93d1SMatti Vaittinen 
137541ff93d1SMatti Vaittinen 	part_id = FIELD_GET(BU27008_MASK_PART_ID, reg);
137641ff93d1SMatti Vaittinen 
1377ccca97fbSMatti Vaittinen 	if (part_id != data->cd->part_id)
137841ff93d1SMatti Vaittinen 		dev_warn(dev, "unknown device 0x%x\n", part_id);
137941ff93d1SMatti Vaittinen 
1380ccca97fbSMatti Vaittinen 	ret = devm_iio_init_iio_gts(dev, data->cd->scale1x, 0, data->cd->gains,
1381ccca97fbSMatti Vaittinen 				    data->cd->num_gains, data->cd->itimes,
1382ccca97fbSMatti Vaittinen 				    data->cd->num_itimes, &data->gts);
138341ff93d1SMatti Vaittinen 	if (ret)
138441ff93d1SMatti Vaittinen 		return ret;
138541ff93d1SMatti Vaittinen 
1386ccca97fbSMatti Vaittinen 	ret = devm_iio_init_iio_gts(dev, data->cd->scale1x, 0, data->cd->gains_ir,
1387ccca97fbSMatti Vaittinen 				    data->cd->num_gains_ir, data->cd->itimes,
1388ccca97fbSMatti Vaittinen 				    data->cd->num_itimes, &data->gts_ir);
138941ff93d1SMatti Vaittinen 	if (ret)
139041ff93d1SMatti Vaittinen 		return ret;
139141ff93d1SMatti Vaittinen 
139241ff93d1SMatti Vaittinen 	mutex_init(&data->mutex);
139341ff93d1SMatti Vaittinen 	data->regmap = regmap;
139441ff93d1SMatti Vaittinen 	data->dev = dev;
139541ff93d1SMatti Vaittinen 	data->irq = i2c->irq;
139641ff93d1SMatti Vaittinen 
139741ff93d1SMatti Vaittinen 	idev->channels = bu27008_channels;
139841ff93d1SMatti Vaittinen 	idev->num_channels = ARRAY_SIZE(bu27008_channels);
1399ccca97fbSMatti Vaittinen 	idev->name = data->cd->name;
140041ff93d1SMatti Vaittinen 	idev->info = &bu27008_info;
140141ff93d1SMatti Vaittinen 	idev->modes = INDIO_DIRECT_MODE;
140241ff93d1SMatti Vaittinen 	idev->available_scan_masks = bu27008_scan_masks;
140341ff93d1SMatti Vaittinen 
1404ccca97fbSMatti Vaittinen 	ret = data->cd->chip_init(data);
140541ff93d1SMatti Vaittinen 	if (ret)
140641ff93d1SMatti Vaittinen 		return ret;
140741ff93d1SMatti Vaittinen 
140841ff93d1SMatti Vaittinen 	if (i2c->irq) {
140941ff93d1SMatti Vaittinen 		ret = bu27008_setup_trigger(data, idev);
141041ff93d1SMatti Vaittinen 		if (ret)
141141ff93d1SMatti Vaittinen 			return ret;
141241ff93d1SMatti Vaittinen 	} else {
141341ff93d1SMatti Vaittinen 		dev_info(dev, "No IRQ, buffered mode disabled\n");
141441ff93d1SMatti Vaittinen 	}
141541ff93d1SMatti Vaittinen 
141641ff93d1SMatti Vaittinen 	ret = devm_iio_device_register(dev, idev);
141741ff93d1SMatti Vaittinen 	if (ret)
141841ff93d1SMatti Vaittinen 		return dev_err_probe(dev, ret,
141941ff93d1SMatti Vaittinen 				     "Unable to register iio device\n");
142041ff93d1SMatti Vaittinen 
142141ff93d1SMatti Vaittinen 	return 0;
142241ff93d1SMatti Vaittinen }
142341ff93d1SMatti Vaittinen 
142441ff93d1SMatti Vaittinen static const struct of_device_id bu27008_of_match[] = {
1425ccca97fbSMatti Vaittinen 	{ .compatible = "rohm,bu27008", .data = &bu27008_chip },
1426*fdb48f9dSMatti Vaittinen 	{ .compatible = "rohm,bu27010", .data = &bu27010_chip },
142741ff93d1SMatti Vaittinen 	{ }
142841ff93d1SMatti Vaittinen };
142941ff93d1SMatti Vaittinen MODULE_DEVICE_TABLE(of, bu27008_of_match);
143041ff93d1SMatti Vaittinen 
143141ff93d1SMatti Vaittinen static struct i2c_driver bu27008_i2c_driver = {
143241ff93d1SMatti Vaittinen 	.driver = {
143341ff93d1SMatti Vaittinen 		.name = "bu27008",
143441ff93d1SMatti Vaittinen 		.of_match_table = bu27008_of_match,
143541ff93d1SMatti Vaittinen 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
143641ff93d1SMatti Vaittinen 	},
143741ff93d1SMatti Vaittinen 	.probe = bu27008_probe,
143841ff93d1SMatti Vaittinen };
143941ff93d1SMatti Vaittinen module_i2c_driver(bu27008_i2c_driver);
144041ff93d1SMatti Vaittinen 
1441*fdb48f9dSMatti Vaittinen MODULE_DESCRIPTION("ROHM BU27008 and BU27010 colour sensor driver");
144241ff93d1SMatti Vaittinen MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
144341ff93d1SMatti Vaittinen MODULE_LICENSE("GPL");
144441ff93d1SMatti Vaittinen MODULE_IMPORT_NS(IIO_GTS_HELPER);
1445