brintos

brintos / linux-shallow public Read only

0
0
Text · 13.9 KiB · dd480a4 Raw
585 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * MMC35240 - MEMSIC 3-axis Magnetic Sensor4 *5 * Copyright (c) 2015, Intel Corporation.6 *7 * IIO driver for MMC35240 (7-bit I2C slave address 0x30).8 *9 * TODO: offset, ACPI, continuous measurement mode, PM10 */11 12#include <linux/module.h>13#include <linux/mod_devicetable.h>14#include <linux/init.h>15#include <linux/i2c.h>16#include <linux/delay.h>17#include <linux/regmap.h>18#include <linux/pm.h>19 20#include <linux/iio/iio.h>21#include <linux/iio/sysfs.h>22 23#define MMC35240_DRV_NAME "mmc35240"24#define MMC35240_REGMAP_NAME "mmc35240_regmap"25 26#define MMC35240_REG_XOUT_L	0x0027#define MMC35240_REG_XOUT_H	0x0128#define MMC35240_REG_YOUT_L	0x0229#define MMC35240_REG_YOUT_H	0x0330#define MMC35240_REG_ZOUT_L	0x0431#define MMC35240_REG_ZOUT_H	0x0532 33#define MMC35240_REG_STATUS	0x0634#define MMC35240_REG_CTRL0	0x0735#define MMC35240_REG_CTRL1	0x0836 37#define MMC35240_REG_ID		0x2038 39#define MMC35240_STATUS_MEAS_DONE_BIT	BIT(0)40 41#define MMC35240_CTRL0_REFILL_BIT	BIT(7)42#define MMC35240_CTRL0_RESET_BIT	BIT(6)43#define MMC35240_CTRL0_SET_BIT		BIT(5)44#define MMC35240_CTRL0_CMM_BIT		BIT(1)45#define MMC35240_CTRL0_TM_BIT		BIT(0)46 47/* output resolution bits */48#define MMC35240_CTRL1_BW0_BIT		BIT(0)49#define MMC35240_CTRL1_BW1_BIT		BIT(1)50 51#define MMC35240_CTRL1_BW_MASK	 (MMC35240_CTRL1_BW0_BIT | \52		 MMC35240_CTRL1_BW1_BIT)53#define MMC35240_CTRL1_BW_SHIFT		054 55#define MMC35240_WAIT_CHARGE_PUMP	50000	/* us */56#define MMC35240_WAIT_SET_RESET		1000	/* us */57 58/*59 * Memsic OTP process code piece is put here for reference:60 *61 * #define OTP_CONVERT(REG)  ((float)((REG) >=32 ? (32 - (REG)) : (REG)) * 0.00662 * 1) For X axis, the COEFFICIENT is always 1.63 * 2) For Y axis, the COEFFICIENT is as below:64 *    f_OTP_matrix[4] = OTP_CONVERT(((reg_data[1] & 0x03) << 4) |65 *                                   (reg_data[2] >> 4)) + 1.0;66 * 3) For Z axis, the COEFFICIENT is as below:67 *    f_OTP_matrix[8] = (OTP_CONVERT(reg_data[3] & 0x3f) + 1) * 1.35;68 * We implemented the OTP logic into driver.69 */70 71/* scale = 1000 here for Y otp */72#define MMC35240_OTP_CONVERT_Y(REG) (((REG) >= 32 ? (32 - (REG)) : (REG)) * 6)73 74/* 0.6 * 1.35 = 0.81, scale 10000 for Z otp */75#define MMC35240_OTP_CONVERT_Z(REG) (((REG) >= 32 ? (32 - (REG)) : (REG)) * 81)76 77#define MMC35240_X_COEFF(x)	(x)78#define MMC35240_Y_COEFF(y)	(y + 1000)79#define MMC35240_Z_COEFF(z)	(z + 13500)80 81#define MMC35240_OTP_START_ADDR		0x1B82 83enum mmc35240_resolution {84	MMC35240_16_BITS_SLOW = 0, /* 7.92 ms */85	MMC35240_16_BITS_FAST,     /* 4.08 ms */86	MMC35240_14_BITS,          /* 2.16 ms */87	MMC35240_12_BITS,          /* 1.20 ms */88};89 90enum mmc35240_axis {91	AXIS_X = 0,92	AXIS_Y,93	AXIS_Z,94};95 96static const struct {97	int sens[3]; /* sensitivity per X, Y, Z axis */98	int nfo; /* null field output */99} mmc35240_props_table[] = {100	/* 16 bits, 125Hz ODR */101	{102		{1024, 1024, 1024},103		32768,104	},105	/* 16 bits, 250Hz ODR */106	{107		{1024, 1024, 770},108		32768,109	},110	/* 14 bits, 450Hz ODR */111	{112		{256, 256, 193},113		8192,114	},115	/* 12 bits, 800Hz ODR */116	{117		{64, 64, 48},118		2048,119	},120};121 122struct mmc35240_data {123	struct i2c_client *client;124	struct mutex mutex;125	struct regmap *regmap;126	enum mmc35240_resolution res;127 128	/* OTP compensation */129	int axis_coef[3];130	int axis_scale[3];131};132 133static const struct {134	int val;135	int val2;136} mmc35240_samp_freq[] = { {1, 500000},137			   {13, 0},138			   {25, 0},139			   {50, 0} };140 141static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("1.5 13 25 50");142 143#define MMC35240_CHANNEL(_axis) { \144	.type = IIO_MAGN, \145	.modified = 1, \146	.channel2 = IIO_MOD_ ## _axis, \147	.address = AXIS_ ## _axis, \148	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \149	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \150			BIT(IIO_CHAN_INFO_SCALE), \151}152 153static const struct iio_chan_spec mmc35240_channels[] = {154	MMC35240_CHANNEL(X),155	MMC35240_CHANNEL(Y),156	MMC35240_CHANNEL(Z),157};158 159static struct attribute *mmc35240_attributes[] = {160	&iio_const_attr_sampling_frequency_available.dev_attr.attr,161	NULL162};163 164static const struct attribute_group mmc35240_attribute_group = {165	.attrs = mmc35240_attributes,166};167 168static int mmc35240_get_samp_freq_index(struct mmc35240_data *data,169					int val, int val2)170{171	int i;172 173	for (i = 0; i < ARRAY_SIZE(mmc35240_samp_freq); i++)174		if (mmc35240_samp_freq[i].val == val &&175		    mmc35240_samp_freq[i].val2 == val2)176			return i;177	return -EINVAL;178}179 180static int mmc35240_hw_set(struct mmc35240_data *data, bool set)181{182	int ret;183	u8 coil_bit;184 185	/*186	 * Recharge the capacitor at VCAP pin, requested to be issued187	 * before a SET/RESET command.188	 */189	ret = regmap_set_bits(data->regmap, MMC35240_REG_CTRL0,190			      MMC35240_CTRL0_REFILL_BIT);191	if (ret < 0)192		return ret;193	usleep_range(MMC35240_WAIT_CHARGE_PUMP, MMC35240_WAIT_CHARGE_PUMP + 1);194 195	if (set)196		coil_bit = MMC35240_CTRL0_SET_BIT;197	else198		coil_bit = MMC35240_CTRL0_RESET_BIT;199 200	return regmap_set_bits(data->regmap, MMC35240_REG_CTRL0, coil_bit);201 202}203 204static int mmc35240_init(struct mmc35240_data *data)205{206	int ret, y_convert, z_convert;207	unsigned int reg_id;208	u8 otp_data[6];209 210	ret = regmap_read(data->regmap, MMC35240_REG_ID, &reg_id);211	if (ret < 0) {212		dev_err(&data->client->dev, "Error reading product id\n");213		return ret;214	}215 216	dev_dbg(&data->client->dev, "MMC35240 chip id %x\n", reg_id);217 218	/*219	 * make sure we restore sensor characteristics, by doing220	 * a SET/RESET sequence, the axis polarity being naturally221	 * aligned after RESET222	 */223	ret = mmc35240_hw_set(data, true);224	if (ret < 0)225		return ret;226	usleep_range(MMC35240_WAIT_SET_RESET, MMC35240_WAIT_SET_RESET + 1);227 228	ret = mmc35240_hw_set(data, false);229	if (ret < 0)230		return ret;231 232	/* set default sampling frequency */233	ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL1,234				 MMC35240_CTRL1_BW_MASK,235				 data->res << MMC35240_CTRL1_BW_SHIFT);236	if (ret < 0)237		return ret;238 239	ret = regmap_bulk_read(data->regmap, MMC35240_OTP_START_ADDR,240			       otp_data, sizeof(otp_data));241	if (ret < 0)242		return ret;243 244	y_convert = MMC35240_OTP_CONVERT_Y(((otp_data[1] & 0x03) << 4) |245					   (otp_data[2] >> 4));246	z_convert = MMC35240_OTP_CONVERT_Z(otp_data[3] & 0x3f);247 248	data->axis_coef[0] = MMC35240_X_COEFF(1);249	data->axis_coef[1] = MMC35240_Y_COEFF(y_convert);250	data->axis_coef[2] = MMC35240_Z_COEFF(z_convert);251 252	data->axis_scale[0] = 1;253	data->axis_scale[1] = 1000;254	data->axis_scale[2] = 10000;255 256	return 0;257}258 259static int mmc35240_take_measurement(struct mmc35240_data *data)260{261	int ret, tries = 100;262	unsigned int reg_status;263 264	ret = regmap_write(data->regmap, MMC35240_REG_CTRL0,265			   MMC35240_CTRL0_TM_BIT);266	if (ret < 0)267		return ret;268 269	while (tries-- > 0) {270		ret = regmap_read(data->regmap, MMC35240_REG_STATUS,271				  &reg_status);272		if (ret < 0)273			return ret;274		if (reg_status & MMC35240_STATUS_MEAS_DONE_BIT)275			break;276		/* minimum wait time to complete measurement is 10 ms */277		usleep_range(10000, 11000);278	}279 280	if (tries < 0) {281		dev_err(&data->client->dev, "data not ready\n");282		return -EIO;283	}284 285	return 0;286}287 288static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3])289{290	int ret;291 292	ret = mmc35240_take_measurement(data);293	if (ret < 0)294		return ret;295 296	return regmap_bulk_read(data->regmap, MMC35240_REG_XOUT_L, buf,297				3 * sizeof(__le16));298}299 300/**301 * mmc35240_raw_to_mgauss - convert raw readings to milli gauss. Also apply302 *			    compensation for output value.303 *304 * @data: device private data305 * @index: axis index for which we want the conversion306 * @buf: raw data to be converted, 2 bytes in little endian format307 * @val: compensated output reading (unit is milli gauss)308 *309 * Returns: 0 in case of success, -EINVAL when @index is not valid310 */311static int mmc35240_raw_to_mgauss(struct mmc35240_data *data, int index,312				  __le16 buf[], int *val)313{314	int raw[3];315	int sens[3];316	int nfo;317 318	raw[AXIS_X] = le16_to_cpu(buf[AXIS_X]);319	raw[AXIS_Y] = le16_to_cpu(buf[AXIS_Y]);320	raw[AXIS_Z] = le16_to_cpu(buf[AXIS_Z]);321 322	sens[AXIS_X] = mmc35240_props_table[data->res].sens[AXIS_X];323	sens[AXIS_Y] = mmc35240_props_table[data->res].sens[AXIS_Y];324	sens[AXIS_Z] = mmc35240_props_table[data->res].sens[AXIS_Z];325 326	nfo = mmc35240_props_table[data->res].nfo;327 328	switch (index) {329	case AXIS_X:330		*val = (raw[AXIS_X] - nfo) * 1000 / sens[AXIS_X];331		break;332	case AXIS_Y:333		*val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] -334			(raw[AXIS_Z] - nfo)  * 1000 / sens[AXIS_Z];335		break;336	case AXIS_Z:337		*val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] +338			(raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z];339		break;340	default:341		return -EINVAL;342	}343	/* apply OTP compensation */344	*val = (*val) * data->axis_coef[index] / data->axis_scale[index];345 346	return 0;347}348 349static int mmc35240_read_raw(struct iio_dev *indio_dev,350			     struct iio_chan_spec const *chan, int *val,351			     int *val2, long mask)352{353	struct mmc35240_data *data = iio_priv(indio_dev);354	int ret, i;355	unsigned int reg;356	__le16 buf[3];357 358	switch (mask) {359	case IIO_CHAN_INFO_RAW:360		mutex_lock(&data->mutex);361		ret = mmc35240_read_measurement(data, buf);362		mutex_unlock(&data->mutex);363		if (ret < 0)364			return ret;365		ret = mmc35240_raw_to_mgauss(data, chan->address, buf, val);366		if (ret < 0)367			return ret;368		return IIO_VAL_INT;369	case IIO_CHAN_INFO_SCALE:370		*val = 0;371		*val2 = 1000;372		return IIO_VAL_INT_PLUS_MICRO;373	case IIO_CHAN_INFO_SAMP_FREQ:374		mutex_lock(&data->mutex);375		ret = regmap_read(data->regmap, MMC35240_REG_CTRL1, &reg);376		mutex_unlock(&data->mutex);377		if (ret < 0)378			return ret;379 380		i = (reg & MMC35240_CTRL1_BW_MASK) >> MMC35240_CTRL1_BW_SHIFT;381		if (i < 0 || i >= ARRAY_SIZE(mmc35240_samp_freq))382			return -EINVAL;383 384		*val = mmc35240_samp_freq[i].val;385		*val2 = mmc35240_samp_freq[i].val2;386		return IIO_VAL_INT_PLUS_MICRO;387	default:388		return -EINVAL;389	}390}391 392static int mmc35240_write_raw(struct iio_dev *indio_dev,393			      struct iio_chan_spec const *chan, int val,394			      int val2, long mask)395{396	struct mmc35240_data *data = iio_priv(indio_dev);397	int i, ret;398 399	switch (mask) {400	case IIO_CHAN_INFO_SAMP_FREQ:401		i = mmc35240_get_samp_freq_index(data, val, val2);402		if (i < 0)403			return -EINVAL;404		mutex_lock(&data->mutex);405		ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL1,406					 MMC35240_CTRL1_BW_MASK,407					 i << MMC35240_CTRL1_BW_SHIFT);408		mutex_unlock(&data->mutex);409		return ret;410	default:411		return -EINVAL;412	}413}414 415static const struct iio_info mmc35240_info = {416	.read_raw	= mmc35240_read_raw,417	.write_raw	= mmc35240_write_raw,418	.attrs		= &mmc35240_attribute_group,419};420 421static bool mmc35240_is_writeable_reg(struct device *dev, unsigned int reg)422{423	switch (reg) {424	case MMC35240_REG_CTRL0:425	case MMC35240_REG_CTRL1:426		return true;427	default:428		return false;429	}430}431 432static bool mmc35240_is_readable_reg(struct device *dev, unsigned int reg)433{434	switch (reg) {435	case MMC35240_REG_XOUT_L:436	case MMC35240_REG_XOUT_H:437	case MMC35240_REG_YOUT_L:438	case MMC35240_REG_YOUT_H:439	case MMC35240_REG_ZOUT_L:440	case MMC35240_REG_ZOUT_H:441	case MMC35240_REG_STATUS:442	case MMC35240_REG_ID:443		return true;444	default:445		return false;446	}447}448 449static bool mmc35240_is_volatile_reg(struct device *dev, unsigned int reg)450{451	switch (reg) {452	case MMC35240_REG_CTRL0:453	case MMC35240_REG_CTRL1:454		return false;455	default:456		return true;457	}458}459 460static const struct reg_default mmc35240_reg_defaults[] = {461	{ MMC35240_REG_CTRL0,  0x00 },462	{ MMC35240_REG_CTRL1,  0x00 },463};464 465static const struct regmap_config mmc35240_regmap_config = {466	.name = MMC35240_REGMAP_NAME,467 468	.reg_bits = 8,469	.val_bits = 8,470 471	.max_register = MMC35240_REG_ID,472	.cache_type = REGCACHE_FLAT,473 474	.writeable_reg = mmc35240_is_writeable_reg,475	.readable_reg = mmc35240_is_readable_reg,476	.volatile_reg = mmc35240_is_volatile_reg,477 478	.reg_defaults = mmc35240_reg_defaults,479	.num_reg_defaults = ARRAY_SIZE(mmc35240_reg_defaults),480};481 482static int mmc35240_probe(struct i2c_client *client)483{484	struct mmc35240_data *data;485	struct iio_dev *indio_dev;486	struct regmap *regmap;487	int ret;488 489	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));490	if (!indio_dev)491		return -ENOMEM;492 493	regmap = devm_regmap_init_i2c(client, &mmc35240_regmap_config);494	if (IS_ERR(regmap)) {495		dev_err(&client->dev, "regmap initialization failed\n");496		return PTR_ERR(regmap);497	}498 499	data = iio_priv(indio_dev);500	i2c_set_clientdata(client, indio_dev);501	data->client = client;502	data->regmap = regmap;503	data->res = MMC35240_16_BITS_SLOW;504 505	mutex_init(&data->mutex);506 507	indio_dev->info = &mmc35240_info;508	indio_dev->name = MMC35240_DRV_NAME;509	indio_dev->channels = mmc35240_channels;510	indio_dev->num_channels = ARRAY_SIZE(mmc35240_channels);511	indio_dev->modes = INDIO_DIRECT_MODE;512 513	ret = mmc35240_init(data);514	if (ret < 0) {515		dev_err(&client->dev, "mmc35240 chip init failed\n");516		return ret;517	}518	return devm_iio_device_register(&client->dev, indio_dev);519}520 521static int mmc35240_suspend(struct device *dev)522{523	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));524	struct mmc35240_data *data = iio_priv(indio_dev);525 526	regcache_cache_only(data->regmap, true);527 528	return 0;529}530 531static int mmc35240_resume(struct device *dev)532{533	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));534	struct mmc35240_data *data = iio_priv(indio_dev);535	int ret;536 537	regcache_mark_dirty(data->regmap);538	ret = regcache_sync_region(data->regmap, MMC35240_REG_CTRL0,539				   MMC35240_REG_CTRL1);540	if (ret < 0)541		dev_err(dev, "Failed to restore control registers\n");542 543	regcache_cache_only(data->regmap, false);544 545	return 0;546}547 548static DEFINE_SIMPLE_DEV_PM_OPS(mmc35240_pm_ops, mmc35240_suspend,549				mmc35240_resume);550 551static const struct of_device_id mmc35240_of_match[] = {552	{ .compatible = "memsic,mmc35240", },553	{ }554};555MODULE_DEVICE_TABLE(of, mmc35240_of_match);556 557static const struct acpi_device_id mmc35240_acpi_match[] = {558	{"MMC35240", 0},559	{ },560};561MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match);562 563static const struct i2c_device_id mmc35240_id[] = {564	{ "mmc35240" },565	{}566};567MODULE_DEVICE_TABLE(i2c, mmc35240_id);568 569static struct i2c_driver mmc35240_driver = {570	.driver = {571		.name = MMC35240_DRV_NAME,572		.of_match_table = mmc35240_of_match,573		.pm = pm_sleep_ptr(&mmc35240_pm_ops),574		.acpi_match_table = mmc35240_acpi_match,575	},576	.probe		= mmc35240_probe,577	.id_table	= mmc35240_id,578};579 580module_i2c_driver(mmc35240_driver);581 582MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");583MODULE_DESCRIPTION("MEMSIC MMC35240 magnetic sensor driver");584MODULE_LICENSE("GPL v2");585