brintos

brintos / linux-shallow public Read only

0
0
Text · 9.9 KiB · 4427409 Raw
423 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * hp206c.c - HOPERF HP206C precision barometer and altimeter sensor4 *5 * Copyright (c) 2016, Intel Corporation.6 *7 * (7-bit I2C slave address 0x76)8 *9 * Datasheet:10 *  http://www.hoperf.com/upload/sensor/HP206C_DataSheet_EN_V2.0.pdf11 */12 13#include <linux/module.h>14#include <linux/mod_devicetable.h>15#include <linux/i2c.h>16#include <linux/iio/iio.h>17#include <linux/iio/sysfs.h>18#include <linux/delay.h>19#include <linux/util_macros.h>20 21#include <linux/unaligned.h>22 23/* I2C commands: */24#define HP206C_CMD_SOFT_RST	0x0625 26#define HP206C_CMD_ADC_CVT	0x4027 28#define HP206C_CMD_ADC_CVT_OSR_4096	0x0029#define HP206C_CMD_ADC_CVT_OSR_2048	0x0430#define HP206C_CMD_ADC_CVT_OSR_1024	0x0831#define HP206C_CMD_ADC_CVT_OSR_512	0x0c32#define HP206C_CMD_ADC_CVT_OSR_256	0x1033#define HP206C_CMD_ADC_CVT_OSR_128	0x1434 35#define HP206C_CMD_ADC_CVT_CHNL_PT	0x0036#define HP206C_CMD_ADC_CVT_CHNL_T	0x0237 38#define HP206C_CMD_READ_P	0x3039#define HP206C_CMD_READ_T	0x3240 41#define HP206C_CMD_READ_REG	0x8042#define HP206C_CMD_WRITE_REG	0xc043 44#define HP206C_REG_INT_EN	0x0b45#define HP206C_REG_INT_CFG	0x0c46 47#define HP206C_REG_INT_SRC	0x0d48#define HP206C_FLAG_DEV_RDY	0x4049 50#define HP206C_REG_PARA		0x0f51#define HP206C_FLAG_CMPS_EN	0x8052 53/* Maximum spin for DEV_RDY */54#define HP206C_MAX_DEV_RDY_WAIT_COUNT 2055#define HP206C_DEV_RDY_WAIT_US    2000056 57struct hp206c_data {58	struct mutex mutex;59	struct i2c_client *client;60	int temp_osr_index;61	int pres_osr_index;62};63 64struct hp206c_osr_setting {65	u8 osr_mask;66	unsigned int temp_conv_time_us;67	unsigned int pres_conv_time_us;68};69 70/* Data from Table 5 in datasheet. */71static const struct hp206c_osr_setting hp206c_osr_settings[] = {72	{ HP206C_CMD_ADC_CVT_OSR_4096,	65600,	131100	},73	{ HP206C_CMD_ADC_CVT_OSR_2048,	32800,	65600	},74	{ HP206C_CMD_ADC_CVT_OSR_1024,	16400,	32800	},75	{ HP206C_CMD_ADC_CVT_OSR_512,	8200,	16400	},76	{ HP206C_CMD_ADC_CVT_OSR_256,	4100,	8200	},77	{ HP206C_CMD_ADC_CVT_OSR_128,	2100,	4100	},78};79static const int hp206c_osr_rates[] = { 4096, 2048, 1024, 512, 256, 128 };80static const char hp206c_osr_rates_str[] = "4096 2048 1024 512 256 128";81 82static inline int hp206c_read_reg(struct i2c_client *client, u8 reg)83{84	return i2c_smbus_read_byte_data(client, HP206C_CMD_READ_REG | reg);85}86 87static inline int hp206c_write_reg(struct i2c_client *client, u8 reg, u8 val)88{89	return i2c_smbus_write_byte_data(client,90			HP206C_CMD_WRITE_REG | reg, val);91}92 93static int hp206c_read_20bit(struct i2c_client *client, u8 cmd)94{95	int ret;96	u8 values[3];97 98	ret = i2c_smbus_read_i2c_block_data(client, cmd, sizeof(values), values);99	if (ret < 0)100		return ret;101	if (ret != sizeof(values))102		return -EIO;103	return get_unaligned_be24(&values[0]) & GENMASK(19, 0);104}105 106/* Spin for max 160ms until DEV_RDY is 1, or return error. */107static int hp206c_wait_dev_rdy(struct iio_dev *indio_dev)108{109	int ret;110	int count = 0;111	struct hp206c_data *data = iio_priv(indio_dev);112	struct i2c_client *client = data->client;113 114	while (++count <= HP206C_MAX_DEV_RDY_WAIT_COUNT) {115		ret = hp206c_read_reg(client, HP206C_REG_INT_SRC);116		if (ret < 0) {117			dev_err(&indio_dev->dev, "Failed READ_REG INT_SRC: %d\n", ret);118			return ret;119		}120		if (ret & HP206C_FLAG_DEV_RDY)121			return 0;122		usleep_range(HP206C_DEV_RDY_WAIT_US, HP206C_DEV_RDY_WAIT_US * 3 / 2);123	}124	return -ETIMEDOUT;125}126 127static int hp206c_set_compensation(struct i2c_client *client, bool enabled)128{129	int val;130 131	val = hp206c_read_reg(client, HP206C_REG_PARA);132	if (val < 0)133		return val;134	if (enabled)135		val |= HP206C_FLAG_CMPS_EN;136	else137		val &= ~HP206C_FLAG_CMPS_EN;138 139	return hp206c_write_reg(client, HP206C_REG_PARA, val);140}141 142/* Do a soft reset */143static int hp206c_soft_reset(struct iio_dev *indio_dev)144{145	int ret;146	struct hp206c_data *data = iio_priv(indio_dev);147	struct i2c_client *client = data->client;148 149	ret = i2c_smbus_write_byte(client, HP206C_CMD_SOFT_RST);150	if (ret) {151		dev_err(&client->dev, "Failed to reset device: %d\n", ret);152		return ret;153	}154 155	usleep_range(400, 600);156 157	ret = hp206c_wait_dev_rdy(indio_dev);158	if (ret) {159		dev_err(&client->dev, "Device not ready after soft reset: %d\n", ret);160		return ret;161	}162 163	ret = hp206c_set_compensation(client, true);164	if (ret)165		dev_err(&client->dev, "Failed to enable compensation: %d\n", ret);166	return ret;167}168 169static int hp206c_conv_and_read(struct iio_dev *indio_dev,170				u8 conv_cmd, u8 read_cmd,171				unsigned int sleep_us)172{173	int ret;174	struct hp206c_data *data = iio_priv(indio_dev);175	struct i2c_client *client = data->client;176 177	ret = hp206c_wait_dev_rdy(indio_dev);178	if (ret < 0) {179		dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);180		return ret;181	}182 183	ret = i2c_smbus_write_byte(client, conv_cmd);184	if (ret < 0) {185		dev_err(&indio_dev->dev, "Failed convert: %d\n", ret);186		return ret;187	}188 189	usleep_range(sleep_us, sleep_us * 3 / 2);190 191	ret = hp206c_wait_dev_rdy(indio_dev);192	if (ret < 0) {193		dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);194		return ret;195	}196 197	ret = hp206c_read_20bit(client, read_cmd);198	if (ret < 0)199		dev_err(&indio_dev->dev, "Failed read: %d\n", ret);200 201	return ret;202}203 204static int hp206c_read_raw(struct iio_dev *indio_dev,205			   struct iio_chan_spec const *chan, int *val,206			   int *val2, long mask)207{208	int ret;209	struct hp206c_data *data = iio_priv(indio_dev);210	const struct hp206c_osr_setting *osr_setting;211	u8 conv_cmd;212 213	mutex_lock(&data->mutex);214 215	switch (mask) {216	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:217		switch (chan->type) {218		case IIO_TEMP:219			*val = hp206c_osr_rates[data->temp_osr_index];220			ret = IIO_VAL_INT;221			break;222 223		case IIO_PRESSURE:224			*val = hp206c_osr_rates[data->pres_osr_index];225			ret = IIO_VAL_INT;226			break;227		default:228			ret = -EINVAL;229		}230		break;231 232	case IIO_CHAN_INFO_RAW:233		switch (chan->type) {234		case IIO_TEMP:235			osr_setting = &hp206c_osr_settings[data->temp_osr_index];236			conv_cmd = HP206C_CMD_ADC_CVT |237					osr_setting->osr_mask |238					HP206C_CMD_ADC_CVT_CHNL_T;239			ret = hp206c_conv_and_read(indio_dev,240					conv_cmd,241					HP206C_CMD_READ_T,242					osr_setting->temp_conv_time_us);243			if (ret >= 0) {244				/* 20 significant bits are provided.245				 * Extend sign over the rest.246				 */247				*val = sign_extend32(ret, 19);248				ret = IIO_VAL_INT;249			}250			break;251 252		case IIO_PRESSURE:253			osr_setting = &hp206c_osr_settings[data->pres_osr_index];254			conv_cmd = HP206C_CMD_ADC_CVT |255					osr_setting->osr_mask |256					HP206C_CMD_ADC_CVT_CHNL_PT;257			ret = hp206c_conv_and_read(indio_dev,258					conv_cmd,259					HP206C_CMD_READ_P,260					osr_setting->pres_conv_time_us);261			if (ret >= 0) {262				*val = ret;263				ret = IIO_VAL_INT;264			}265			break;266		default:267			ret = -EINVAL;268		}269		break;270 271	case IIO_CHAN_INFO_SCALE:272		switch (chan->type) {273		case IIO_TEMP:274			*val = 0;275			*val2 = 10000;276			ret = IIO_VAL_INT_PLUS_MICRO;277			break;278 279		case IIO_PRESSURE:280			*val = 0;281			*val2 = 1000;282			ret = IIO_VAL_INT_PLUS_MICRO;283			break;284		default:285			ret = -EINVAL;286		}287		break;288 289	default:290		ret = -EINVAL;291	}292 293	mutex_unlock(&data->mutex);294	return ret;295}296 297static int hp206c_write_raw(struct iio_dev *indio_dev,298			    struct iio_chan_spec const *chan,299			    int val, int val2, long mask)300{301	int ret = 0;302	struct hp206c_data *data = iio_priv(indio_dev);303 304	if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)305		return -EINVAL;306	mutex_lock(&data->mutex);307	switch (chan->type) {308	case IIO_TEMP:309		data->temp_osr_index = find_closest_descending(val,310			hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));311		break;312	case IIO_PRESSURE:313		data->pres_osr_index = find_closest_descending(val,314			hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));315		break;316	default:317		ret = -EINVAL;318	}319	mutex_unlock(&data->mutex);320	return ret;321}322 323static const struct iio_chan_spec hp206c_channels[] = {324	{325		.type = IIO_TEMP,326		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |327				      BIT(IIO_CHAN_INFO_SCALE) |328				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),329	},330	{331		.type = IIO_PRESSURE,332		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |333				      BIT(IIO_CHAN_INFO_SCALE) |334				      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),335	}336};337 338static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(hp206c_osr_rates_str);339 340static struct attribute *hp206c_attributes[] = {341	&iio_const_attr_sampling_frequency_available.dev_attr.attr,342	NULL,343};344 345static const struct attribute_group hp206c_attribute_group = {346	.attrs = hp206c_attributes,347};348 349static const struct iio_info hp206c_info = {350	.attrs = &hp206c_attribute_group,351	.read_raw = hp206c_read_raw,352	.write_raw = hp206c_write_raw,353};354 355static int hp206c_probe(struct i2c_client *client)356{357	const struct i2c_device_id *id = i2c_client_get_device_id(client);358	struct iio_dev *indio_dev;359	struct hp206c_data *data;360	int ret;361 362	if (!i2c_check_functionality(client->adapter,363				     I2C_FUNC_SMBUS_BYTE |364				     I2C_FUNC_SMBUS_BYTE_DATA |365				     I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {366		dev_err(&client->dev, "Adapter does not support "367				"all required i2c functionality\n");368		return -ENODEV;369	}370 371	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));372	if (!indio_dev)373		return -ENOMEM;374 375	data = iio_priv(indio_dev);376	data->client = client;377	mutex_init(&data->mutex);378 379	indio_dev->info = &hp206c_info;380	indio_dev->name = id->name;381	indio_dev->modes = INDIO_DIRECT_MODE;382	indio_dev->channels = hp206c_channels;383	indio_dev->num_channels = ARRAY_SIZE(hp206c_channels);384 385	i2c_set_clientdata(client, indio_dev);386 387	/* Do a soft reset on probe */388	ret = hp206c_soft_reset(indio_dev);389	if (ret) {390		dev_err(&client->dev, "Failed to reset on startup: %d\n", ret);391		return -ENODEV;392	}393 394	return devm_iio_device_register(&client->dev, indio_dev);395}396 397static const struct i2c_device_id hp206c_id[] = {398	{"hp206c"},399	{}400};401MODULE_DEVICE_TABLE(i2c, hp206c_id);402 403static const struct acpi_device_id hp206c_acpi_match[] = {404	{"HOP206C", 0},405	{ },406};407MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);408 409static struct i2c_driver hp206c_driver = {410	.probe = hp206c_probe,411	.id_table = hp206c_id,412	.driver = {413		.name = "hp206c",414		.acpi_match_table = hp206c_acpi_match,415	},416};417 418module_i2c_driver(hp206c_driver);419 420MODULE_DESCRIPTION("HOPERF HP206C precision barometer and altimeter sensor");421MODULE_AUTHOR("Leonard Crestez <leonard.crestez@intel.com>");422MODULE_LICENSE("GPL v2");423