brintos

brintos / linux-shallow public Read only

0
0
Text · 14.8 KiB · 87627d1 Raw
684 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * STMicroelectronics hts221 sensor driver4 *5 * Copyright 2016 STMicroelectronics Inc.6 *7 * Lorenzo Bianconi <lorenzo.bianconi@st.com>8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/device.h>13#include <linux/iio/sysfs.h>14#include <linux/delay.h>15#include <linux/pm.h>16#include <linux/regmap.h>17#include <linux/regulator/consumer.h>18#include <linux/bitfield.h>19 20#include "hts221.h"21 22#define HTS221_REG_WHOAMI_ADDR		0x0f23#define HTS221_REG_WHOAMI_VAL		0xbc24 25#define HTS221_REG_CNTRL1_ADDR		0x2026#define HTS221_REG_CNTRL2_ADDR		0x2127 28#define HTS221_ODR_MASK			0x0329#define HTS221_BDU_MASK			BIT(2)30#define HTS221_ENABLE_MASK		BIT(7)31 32/* calibration registers */33#define HTS221_REG_0RH_CAL_X_H		0x3634#define HTS221_REG_1RH_CAL_X_H		0x3a35#define HTS221_REG_0RH_CAL_Y_H		0x3036#define HTS221_REG_1RH_CAL_Y_H		0x3137#define HTS221_REG_0T_CAL_X_L		0x3c38#define HTS221_REG_1T_CAL_X_L		0x3e39#define HTS221_REG_0T_CAL_Y_H		0x3240#define HTS221_REG_1T_CAL_Y_H		0x3341#define HTS221_REG_T1_T0_CAL_Y_H	0x3542 43struct hts221_odr {44	u8 hz;45	u8 val;46};47 48#define HTS221_AVG_DEPTH		849struct hts221_avg {50	u8 addr;51	u8 mask;52	u16 avg_avl[HTS221_AVG_DEPTH];53};54 55static const struct hts221_odr hts221_odr_table[] = {56	{  1, 0x01 },	/* 1Hz */57	{  7, 0x02 },	/* 7Hz */58	{ 13, 0x03 },	/* 12.5Hz */59};60 61static const struct hts221_avg hts221_avg_list[] = {62	{63		.addr = 0x10,64		.mask = 0x07,65		.avg_avl = {66			4, /* 0.4 %RH */67			8, /* 0.3 %RH */68			16, /* 0.2 %RH */69			32, /* 0.15 %RH */70			64, /* 0.1 %RH */71			128, /* 0.07 %RH */72			256, /* 0.05 %RH */73			512, /* 0.03 %RH */74		},75	},76	{77		.addr = 0x10,78		.mask = 0x38,79		.avg_avl = {80			2, /* 0.08 degC */81			4, /* 0.05 degC */82			8, /* 0.04 degC */83			16, /* 0.03 degC */84			32, /* 0.02 degC */85			64, /* 0.015 degC */86			128, /* 0.01 degC */87			256, /* 0.007 degC */88		},89	},90};91 92static const struct iio_chan_spec hts221_channels[] = {93	{94		.type = IIO_HUMIDITYRELATIVE,95		.address = 0x28,96		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |97				      BIT(IIO_CHAN_INFO_OFFSET) |98				      BIT(IIO_CHAN_INFO_SCALE) |99				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),100		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),101		.scan_index = 0,102		.scan_type = {103			.sign = 's',104			.realbits = 16,105			.storagebits = 16,106			.endianness = IIO_LE,107		},108	},109	{110		.type = IIO_TEMP,111		.address = 0x2a,112		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |113				      BIT(IIO_CHAN_INFO_OFFSET) |114				      BIT(IIO_CHAN_INFO_SCALE) |115				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),116		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),117		.scan_index = 1,118		.scan_type = {119			.sign = 's',120			.realbits = 16,121			.storagebits = 16,122			.endianness = IIO_LE,123		},124	},125	IIO_CHAN_SOFT_TIMESTAMP(2),126};127 128static int hts221_check_whoami(struct hts221_hw *hw)129{130	int err, data;131 132	err = regmap_read(hw->regmap, HTS221_REG_WHOAMI_ADDR, &data);133	if (err < 0) {134		dev_err(hw->dev, "failed to read whoami register\n");135		return err;136	}137 138	if (data != HTS221_REG_WHOAMI_VAL) {139		dev_err(hw->dev, "wrong whoami {%02x vs %02x}\n",140			data, HTS221_REG_WHOAMI_VAL);141		return -ENODEV;142	}143 144	return 0;145}146 147static int hts221_update_odr(struct hts221_hw *hw, u8 odr)148{149	int i, err;150 151	for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)152		if (hts221_odr_table[i].hz == odr)153			break;154 155	if (i == ARRAY_SIZE(hts221_odr_table))156		return -EINVAL;157 158	err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,159				 HTS221_ODR_MASK,160				 FIELD_PREP(HTS221_ODR_MASK,161					    hts221_odr_table[i].val));162	if (err < 0)163		return err;164 165	hw->odr = odr;166 167	return 0;168}169 170static int hts221_update_avg(struct hts221_hw *hw,171			     enum hts221_sensor_type type,172			     u16 val)173{174	const struct hts221_avg *avg = &hts221_avg_list[type];175	int i, err, data;176 177	for (i = 0; i < HTS221_AVG_DEPTH; i++)178		if (avg->avg_avl[i] == val)179			break;180 181	if (i == HTS221_AVG_DEPTH)182		return -EINVAL;183 184	data = ((i << __ffs(avg->mask)) & avg->mask);185	err = regmap_update_bits(hw->regmap, avg->addr,186				 avg->mask, data);187	if (err < 0)188		return err;189 190	hw->sensors[type].cur_avg_idx = i;191 192	return 0;193}194 195static ssize_t hts221_sysfs_sampling_freq(struct device *dev,196					  struct device_attribute *attr,197					  char *buf)198{199	int i;200	ssize_t len = 0;201 202	for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)203		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",204				 hts221_odr_table[i].hz);205	buf[len - 1] = '\n';206 207	return len;208}209 210static ssize_t211hts221_sysfs_rh_oversampling_avail(struct device *dev,212				   struct device_attribute *attr,213				   char *buf)214{215	const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_H];216	ssize_t len = 0;217	int i;218 219	for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)220		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",221				 avg->avg_avl[i]);222	buf[len - 1] = '\n';223 224	return len;225}226 227static ssize_t228hts221_sysfs_temp_oversampling_avail(struct device *dev,229				     struct device_attribute *attr,230				     char *buf)231{232	const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_T];233	ssize_t len = 0;234	int i;235 236	for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)237		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",238				 avg->avg_avl[i]);239	buf[len - 1] = '\n';240 241	return len;242}243 244int hts221_set_enable(struct hts221_hw *hw, bool enable)245{246	int err;247 248	err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,249				 HTS221_ENABLE_MASK,250				 FIELD_PREP(HTS221_ENABLE_MASK, enable));251	if (err < 0)252		return err;253 254	hw->enabled = enable;255 256	return 0;257}258 259static int hts221_parse_temp_caldata(struct hts221_hw *hw)260{261	int err, *slope, *b_gen, cal0, cal1;262	s16 cal_x0, cal_x1, cal_y0, cal_y1;263	__le16 val;264 265	err = regmap_read(hw->regmap, HTS221_REG_0T_CAL_Y_H, &cal0);266	if (err < 0)267		return err;268 269	err = regmap_read(hw->regmap, HTS221_REG_T1_T0_CAL_Y_H, &cal1);270	if (err < 0)271		return err;272	cal_y0 = ((cal1 & 0x3) << 8) | cal0;273 274	err = regmap_read(hw->regmap, HTS221_REG_1T_CAL_Y_H, &cal0);275	if (err < 0)276		return err;277	cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0;278 279	err = regmap_bulk_read(hw->regmap, HTS221_REG_0T_CAL_X_L,280			       &val, sizeof(val));281	if (err < 0)282		return err;283	cal_x0 = le16_to_cpu(val);284 285	err = regmap_bulk_read(hw->regmap, HTS221_REG_1T_CAL_X_L,286			       &val, sizeof(val));287	if (err < 0)288		return err;289	cal_x1 = le16_to_cpu(val);290 291	slope = &hw->sensors[HTS221_SENSOR_T].slope;292	b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen;293 294	*slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0);295	*b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) /296		 (cal_x1 - cal_x0);297	*b_gen *= 8;298 299	return 0;300}301 302static int hts221_parse_rh_caldata(struct hts221_hw *hw)303{304	int err, *slope, *b_gen, data;305	s16 cal_x0, cal_x1, cal_y0, cal_y1;306	__le16 val;307 308	err = regmap_read(hw->regmap, HTS221_REG_0RH_CAL_Y_H, &data);309	if (err < 0)310		return err;311	cal_y0 = data;312 313	err = regmap_read(hw->regmap, HTS221_REG_1RH_CAL_Y_H, &data);314	if (err < 0)315		return err;316	cal_y1 = data;317 318	err = regmap_bulk_read(hw->regmap, HTS221_REG_0RH_CAL_X_H,319			       &val, sizeof(val));320	if (err < 0)321		return err;322	cal_x0 = le16_to_cpu(val);323 324	err = regmap_bulk_read(hw->regmap, HTS221_REG_1RH_CAL_X_H,325			       &val, sizeof(val));326	if (err < 0)327		return err;328	cal_x1 = le16_to_cpu(val);329 330	slope = &hw->sensors[HTS221_SENSOR_H].slope;331	b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen;332 333	*slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0);334	*b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) /335		 (cal_x1 - cal_x0);336	*b_gen *= 8;337 338	return 0;339}340 341static int hts221_get_sensor_scale(struct hts221_hw *hw,342				   enum iio_chan_type ch_type,343				   int *val, int *val2)344{345	s64 tmp;346	s32 rem, div, data;347 348	switch (ch_type) {349	case IIO_HUMIDITYRELATIVE:350		data = hw->sensors[HTS221_SENSOR_H].slope;351		div = (1 << 4) * 1000;352		break;353	case IIO_TEMP:354		data = hw->sensors[HTS221_SENSOR_T].slope;355		div = (1 << 6) * 1000;356		break;357	default:358		return -EINVAL;359	}360 361	tmp = div_s64(data * 1000000000LL, div);362	tmp = div_s64_rem(tmp, 1000000000LL, &rem);363 364	*val = tmp;365	*val2 = rem;366 367	return IIO_VAL_INT_PLUS_NANO;368}369 370static int hts221_get_sensor_offset(struct hts221_hw *hw,371				    enum iio_chan_type ch_type,372				    int *val, int *val2)373{374	s64 tmp;375	s32 rem, div, data;376 377	switch (ch_type) {378	case IIO_HUMIDITYRELATIVE:379		data = hw->sensors[HTS221_SENSOR_H].b_gen;380		div = hw->sensors[HTS221_SENSOR_H].slope;381		break;382	case IIO_TEMP:383		data = hw->sensors[HTS221_SENSOR_T].b_gen;384		div = hw->sensors[HTS221_SENSOR_T].slope;385		break;386	default:387		return -EINVAL;388	}389 390	tmp = div_s64(data * 1000000000LL, div);391	tmp = div_s64_rem(tmp, 1000000000LL, &rem);392 393	*val = tmp;394	*val2 = rem;395 396	return IIO_VAL_INT_PLUS_NANO;397}398 399static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)400{401	__le16 data;402	int err;403 404	err = hts221_set_enable(hw, true);405	if (err < 0)406		return err;407 408	msleep(50);409 410	err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data));411	if (err < 0)412		return err;413 414	hts221_set_enable(hw, false);415 416	*val = (s16)le16_to_cpu(data);417 418	return IIO_VAL_INT;419}420 421static int hts221_read_raw(struct iio_dev *iio_dev,422			   struct iio_chan_spec const *ch,423			   int *val, int *val2, long mask)424{425	struct hts221_hw *hw = iio_priv(iio_dev);426	int ret;427 428	ret = iio_device_claim_direct_mode(iio_dev);429	if (ret)430		return ret;431 432	switch (mask) {433	case IIO_CHAN_INFO_RAW:434		ret = hts221_read_oneshot(hw, ch->address, val);435		break;436	case IIO_CHAN_INFO_SCALE:437		ret = hts221_get_sensor_scale(hw, ch->type, val, val2);438		break;439	case IIO_CHAN_INFO_OFFSET:440		ret = hts221_get_sensor_offset(hw, ch->type, val, val2);441		break;442	case IIO_CHAN_INFO_SAMP_FREQ:443		*val = hw->odr;444		ret = IIO_VAL_INT;445		break;446	case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {447		u8 idx;448		const struct hts221_avg *avg;449 450		switch (ch->type) {451		case IIO_HUMIDITYRELATIVE:452			avg = &hts221_avg_list[HTS221_SENSOR_H];453			idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx;454			*val = avg->avg_avl[idx];455			ret = IIO_VAL_INT;456			break;457		case IIO_TEMP:458			avg = &hts221_avg_list[HTS221_SENSOR_T];459			idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx;460			*val = avg->avg_avl[idx];461			ret = IIO_VAL_INT;462			break;463		default:464			ret = -EINVAL;465			break;466		}467		break;468	}469	default:470		ret = -EINVAL;471		break;472	}473 474	iio_device_release_direct_mode(iio_dev);475 476	return ret;477}478 479static int hts221_write_raw(struct iio_dev *iio_dev,480			    struct iio_chan_spec const *chan,481			    int val, int val2, long mask)482{483	struct hts221_hw *hw = iio_priv(iio_dev);484	int ret;485 486	ret = iio_device_claim_direct_mode(iio_dev);487	if (ret)488		return ret;489 490	switch (mask) {491	case IIO_CHAN_INFO_SAMP_FREQ:492		ret = hts221_update_odr(hw, val);493		break;494	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:495		switch (chan->type) {496		case IIO_HUMIDITYRELATIVE:497			ret = hts221_update_avg(hw, HTS221_SENSOR_H, val);498			break;499		case IIO_TEMP:500			ret = hts221_update_avg(hw, HTS221_SENSOR_T, val);501			break;502		default:503			ret = -EINVAL;504			break;505		}506		break;507	default:508		ret = -EINVAL;509		break;510	}511 512	iio_device_release_direct_mode(iio_dev);513 514	return ret;515}516 517static int hts221_validate_trigger(struct iio_dev *iio_dev,518				   struct iio_trigger *trig)519{520	struct hts221_hw *hw = iio_priv(iio_dev);521 522	return hw->trig == trig ? 0 : -EINVAL;523}524 525static IIO_DEVICE_ATTR(in_humidity_oversampling_ratio_available, S_IRUGO,526		       hts221_sysfs_rh_oversampling_avail, NULL, 0);527static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, S_IRUGO,528		       hts221_sysfs_temp_oversampling_avail, NULL, 0);529static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hts221_sysfs_sampling_freq);530 531static struct attribute *hts221_attributes[] = {532	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,533	&iio_dev_attr_in_humidity_oversampling_ratio_available.dev_attr.attr,534	&iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr,535	NULL,536};537 538static const struct attribute_group hts221_attribute_group = {539	.attrs = hts221_attributes,540};541 542static const struct iio_info hts221_info = {543	.attrs = &hts221_attribute_group,544	.read_raw = hts221_read_raw,545	.write_raw = hts221_write_raw,546	.validate_trigger = hts221_validate_trigger,547};548 549static const unsigned long hts221_scan_masks[] = {0x3, 0x0};550 551static int hts221_init_regulators(struct device *dev)552{553	int err;554 555	err = devm_regulator_get_enable(dev, "vdd");556	if (err)557		return dev_err_probe(dev, err, "failed to get vdd regulator\n");558 559	msleep(50);560 561	return 0;562}563 564int hts221_probe(struct device *dev, int irq, const char *name,565		 struct regmap *regmap)566{567	struct iio_dev *iio_dev;568	struct hts221_hw *hw;569	int err;570	u8 data;571 572	iio_dev = devm_iio_device_alloc(dev, sizeof(*hw));573	if (!iio_dev)574		return -ENOMEM;575 576	dev_set_drvdata(dev, iio_dev);577 578	hw = iio_priv(iio_dev);579	hw->name = name;580	hw->dev = dev;581	hw->irq = irq;582	hw->regmap = regmap;583 584	err = hts221_init_regulators(dev);585	if (err)586		return err;587 588	err = hts221_check_whoami(hw);589	if (err < 0)590		return err;591 592	iio_dev->modes = INDIO_DIRECT_MODE;593	iio_dev->available_scan_masks = hts221_scan_masks;594	iio_dev->channels = hts221_channels;595	iio_dev->num_channels = ARRAY_SIZE(hts221_channels);596	iio_dev->name = HTS221_DEV_NAME;597	iio_dev->info = &hts221_info;598 599	/* enable Block Data Update */600	err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,601				 HTS221_BDU_MASK,602				 FIELD_PREP(HTS221_BDU_MASK, 1));603	if (err < 0)604		return err;605 606	err = hts221_update_odr(hw, hts221_odr_table[0].hz);607	if (err < 0)608		return err;609 610	/* configure humidity sensor */611	err = hts221_parse_rh_caldata(hw);612	if (err < 0) {613		dev_err(hw->dev, "failed to get rh calibration data\n");614		return err;615	}616 617	data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3];618	err = hts221_update_avg(hw, HTS221_SENSOR_H, data);619	if (err < 0) {620		dev_err(hw->dev, "failed to set rh oversampling ratio\n");621		return err;622	}623 624	/* configure temperature sensor */625	err = hts221_parse_temp_caldata(hw);626	if (err < 0) {627		dev_err(hw->dev,628			"failed to get temperature calibration data\n");629		return err;630	}631 632	data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3];633	err = hts221_update_avg(hw, HTS221_SENSOR_T, data);634	if (err < 0) {635		dev_err(hw->dev,636			"failed to set temperature oversampling ratio\n");637		return err;638	}639 640	if (hw->irq > 0) {641		err = hts221_allocate_buffers(iio_dev);642		if (err < 0)643			return err;644 645		err = hts221_allocate_trigger(iio_dev);646		if (err)647			return err;648	}649 650	return devm_iio_device_register(hw->dev, iio_dev);651}652EXPORT_SYMBOL_NS(hts221_probe, IIO_HTS221);653 654static int hts221_suspend(struct device *dev)655{656	struct iio_dev *iio_dev = dev_get_drvdata(dev);657	struct hts221_hw *hw = iio_priv(iio_dev);658 659	return regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,660				  HTS221_ENABLE_MASK,661				  FIELD_PREP(HTS221_ENABLE_MASK, false));662}663 664static int hts221_resume(struct device *dev)665{666	struct iio_dev *iio_dev = dev_get_drvdata(dev);667	struct hts221_hw *hw = iio_priv(iio_dev);668	int err = 0;669 670	if (hw->enabled)671		err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,672					 HTS221_ENABLE_MASK,673					 FIELD_PREP(HTS221_ENABLE_MASK,674						    true));675	return err;676}677 678EXPORT_NS_SIMPLE_DEV_PM_OPS(hts221_pm_ops, hts221_suspend, hts221_resume,679			    IIO_HTS221);680 681MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");682MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver");683MODULE_LICENSE("GPL v2");684