162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Bosch BMC150 three-axis magnetic field sensor driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2015, Intel Corporation. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This code is based on bmm050_api.c authored by contact@bosch.sensortec.com: 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * (C) Copyright 2011~2014 Bosch Sensortec GmbH All Rights Reserved 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/i2c.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/acpi.h> 1862306a36Sopenharmony_ci#include <linux/pm.h> 1962306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2062306a36Sopenharmony_ci#include <linux/iio/iio.h> 2162306a36Sopenharmony_ci#include <linux/iio/sysfs.h> 2262306a36Sopenharmony_ci#include <linux/iio/buffer.h> 2362306a36Sopenharmony_ci#include <linux/iio/events.h> 2462306a36Sopenharmony_ci#include <linux/iio/trigger.h> 2562306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h> 2662306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h> 2762306a36Sopenharmony_ci#include <linux/regmap.h> 2862306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "bmc150_magn.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define BMC150_MAGN_DRV_NAME "bmc150_magn" 3362306a36Sopenharmony_ci#define BMC150_MAGN_IRQ_NAME "bmc150_magn_event" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define BMC150_MAGN_REG_CHIP_ID 0x40 3662306a36Sopenharmony_ci#define BMC150_MAGN_CHIP_ID_VAL 0x32 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define BMC150_MAGN_REG_X_L 0x42 3962306a36Sopenharmony_ci#define BMC150_MAGN_REG_X_M 0x43 4062306a36Sopenharmony_ci#define BMC150_MAGN_REG_Y_L 0x44 4162306a36Sopenharmony_ci#define BMC150_MAGN_REG_Y_M 0x45 4262306a36Sopenharmony_ci#define BMC150_MAGN_SHIFT_XY_L 3 4362306a36Sopenharmony_ci#define BMC150_MAGN_REG_Z_L 0x46 4462306a36Sopenharmony_ci#define BMC150_MAGN_REG_Z_M 0x47 4562306a36Sopenharmony_ci#define BMC150_MAGN_SHIFT_Z_L 1 4662306a36Sopenharmony_ci#define BMC150_MAGN_REG_RHALL_L 0x48 4762306a36Sopenharmony_ci#define BMC150_MAGN_REG_RHALL_M 0x49 4862306a36Sopenharmony_ci#define BMC150_MAGN_SHIFT_RHALL_L 2 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define BMC150_MAGN_REG_INT_STATUS 0x4A 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define BMC150_MAGN_REG_POWER 0x4B 5362306a36Sopenharmony_ci#define BMC150_MAGN_MASK_POWER_CTL BIT(0) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define BMC150_MAGN_REG_OPMODE_ODR 0x4C 5662306a36Sopenharmony_ci#define BMC150_MAGN_MASK_OPMODE GENMASK(2, 1) 5762306a36Sopenharmony_ci#define BMC150_MAGN_SHIFT_OPMODE 1 5862306a36Sopenharmony_ci#define BMC150_MAGN_MODE_NORMAL 0x00 5962306a36Sopenharmony_ci#define BMC150_MAGN_MODE_FORCED 0x01 6062306a36Sopenharmony_ci#define BMC150_MAGN_MODE_SLEEP 0x03 6162306a36Sopenharmony_ci#define BMC150_MAGN_MASK_ODR GENMASK(5, 3) 6262306a36Sopenharmony_ci#define BMC150_MAGN_SHIFT_ODR 3 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define BMC150_MAGN_REG_INT 0x4D 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define BMC150_MAGN_REG_INT_DRDY 0x4E 6762306a36Sopenharmony_ci#define BMC150_MAGN_MASK_DRDY_EN BIT(7) 6862306a36Sopenharmony_ci#define BMC150_MAGN_SHIFT_DRDY_EN 7 6962306a36Sopenharmony_ci#define BMC150_MAGN_MASK_DRDY_INT3 BIT(6) 7062306a36Sopenharmony_ci#define BMC150_MAGN_MASK_DRDY_Z_EN BIT(5) 7162306a36Sopenharmony_ci#define BMC150_MAGN_MASK_DRDY_Y_EN BIT(4) 7262306a36Sopenharmony_ci#define BMC150_MAGN_MASK_DRDY_X_EN BIT(3) 7362306a36Sopenharmony_ci#define BMC150_MAGN_MASK_DRDY_DR_POLARITY BIT(2) 7462306a36Sopenharmony_ci#define BMC150_MAGN_MASK_DRDY_LATCHING BIT(1) 7562306a36Sopenharmony_ci#define BMC150_MAGN_MASK_DRDY_INT3_POLARITY BIT(0) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define BMC150_MAGN_REG_LOW_THRESH 0x4F 7862306a36Sopenharmony_ci#define BMC150_MAGN_REG_HIGH_THRESH 0x50 7962306a36Sopenharmony_ci#define BMC150_MAGN_REG_REP_XY 0x51 8062306a36Sopenharmony_ci#define BMC150_MAGN_REG_REP_Z 0x52 8162306a36Sopenharmony_ci#define BMC150_MAGN_REG_REP_DATAMASK GENMASK(7, 0) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define BMC150_MAGN_REG_TRIM_START 0x5D 8462306a36Sopenharmony_ci#define BMC150_MAGN_REG_TRIM_END 0x71 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define BMC150_MAGN_XY_OVERFLOW_VAL -4096 8762306a36Sopenharmony_ci#define BMC150_MAGN_Z_OVERFLOW_VAL -16384 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* Time from SUSPEND to SLEEP */ 9062306a36Sopenharmony_ci#define BMC150_MAGN_START_UP_TIME_MS 3 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define BMC150_MAGN_AUTO_SUSPEND_DELAY_MS 2000 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define BMC150_MAGN_REGVAL_TO_REPXY(regval) (((regval) * 2) + 1) 9562306a36Sopenharmony_ci#define BMC150_MAGN_REGVAL_TO_REPZ(regval) ((regval) + 1) 9662306a36Sopenharmony_ci#define BMC150_MAGN_REPXY_TO_REGVAL(rep) (((rep) - 1) / 2) 9762306a36Sopenharmony_ci#define BMC150_MAGN_REPZ_TO_REGVAL(rep) ((rep) - 1) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cienum bmc150_magn_axis { 10062306a36Sopenharmony_ci AXIS_X, 10162306a36Sopenharmony_ci AXIS_Y, 10262306a36Sopenharmony_ci AXIS_Z, 10362306a36Sopenharmony_ci RHALL, 10462306a36Sopenharmony_ci AXIS_XYZ_MAX = RHALL, 10562306a36Sopenharmony_ci AXIS_XYZR_MAX, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cienum bmc150_magn_power_modes { 10962306a36Sopenharmony_ci BMC150_MAGN_POWER_MODE_SUSPEND, 11062306a36Sopenharmony_ci BMC150_MAGN_POWER_MODE_SLEEP, 11162306a36Sopenharmony_ci BMC150_MAGN_POWER_MODE_NORMAL, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistruct bmc150_magn_trim_regs { 11562306a36Sopenharmony_ci s8 x1; 11662306a36Sopenharmony_ci s8 y1; 11762306a36Sopenharmony_ci __le16 reserved1; 11862306a36Sopenharmony_ci u8 reserved2; 11962306a36Sopenharmony_ci __le16 z4; 12062306a36Sopenharmony_ci s8 x2; 12162306a36Sopenharmony_ci s8 y2; 12262306a36Sopenharmony_ci __le16 reserved3; 12362306a36Sopenharmony_ci __le16 z2; 12462306a36Sopenharmony_ci __le16 z1; 12562306a36Sopenharmony_ci __le16 xyz1; 12662306a36Sopenharmony_ci __le16 z3; 12762306a36Sopenharmony_ci s8 xy2; 12862306a36Sopenharmony_ci u8 xy1; 12962306a36Sopenharmony_ci} __packed; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct bmc150_magn_data { 13262306a36Sopenharmony_ci struct device *dev; 13362306a36Sopenharmony_ci /* 13462306a36Sopenharmony_ci * 1. Protect this structure. 13562306a36Sopenharmony_ci * 2. Serialize sequences that power on/off the device and access HW. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci struct mutex mutex; 13862306a36Sopenharmony_ci struct regmap *regmap; 13962306a36Sopenharmony_ci struct regulator_bulk_data regulators[2]; 14062306a36Sopenharmony_ci struct iio_mount_matrix orientation; 14162306a36Sopenharmony_ci /* Ensure timestamp is naturally aligned */ 14262306a36Sopenharmony_ci struct { 14362306a36Sopenharmony_ci s32 chans[3]; 14462306a36Sopenharmony_ci s64 timestamp __aligned(8); 14562306a36Sopenharmony_ci } scan; 14662306a36Sopenharmony_ci struct iio_trigger *dready_trig; 14762306a36Sopenharmony_ci bool dready_trigger_on; 14862306a36Sopenharmony_ci int max_odr; 14962306a36Sopenharmony_ci int irq; 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic const struct { 15362306a36Sopenharmony_ci int freq; 15462306a36Sopenharmony_ci u8 reg_val; 15562306a36Sopenharmony_ci} bmc150_magn_samp_freq_table[] = { {2, 0x01}, 15662306a36Sopenharmony_ci {6, 0x02}, 15762306a36Sopenharmony_ci {8, 0x03}, 15862306a36Sopenharmony_ci {10, 0x00}, 15962306a36Sopenharmony_ci {15, 0x04}, 16062306a36Sopenharmony_ci {20, 0x05}, 16162306a36Sopenharmony_ci {25, 0x06}, 16262306a36Sopenharmony_ci {30, 0x07} }; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cienum bmc150_magn_presets { 16562306a36Sopenharmony_ci LOW_POWER_PRESET, 16662306a36Sopenharmony_ci REGULAR_PRESET, 16762306a36Sopenharmony_ci ENHANCED_REGULAR_PRESET, 16862306a36Sopenharmony_ci HIGH_ACCURACY_PRESET 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic const struct bmc150_magn_preset { 17262306a36Sopenharmony_ci u8 rep_xy; 17362306a36Sopenharmony_ci u8 rep_z; 17462306a36Sopenharmony_ci u8 odr; 17562306a36Sopenharmony_ci} bmc150_magn_presets_table[] = { 17662306a36Sopenharmony_ci [LOW_POWER_PRESET] = {3, 3, 10}, 17762306a36Sopenharmony_ci [REGULAR_PRESET] = {9, 15, 10}, 17862306a36Sopenharmony_ci [ENHANCED_REGULAR_PRESET] = {15, 27, 10}, 17962306a36Sopenharmony_ci [HIGH_ACCURACY_PRESET] = {47, 83, 20}, 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci#define BMC150_MAGN_DEFAULT_PRESET REGULAR_PRESET 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic bool bmc150_magn_is_writeable_reg(struct device *dev, unsigned int reg) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci switch (reg) { 18762306a36Sopenharmony_ci case BMC150_MAGN_REG_POWER: 18862306a36Sopenharmony_ci case BMC150_MAGN_REG_OPMODE_ODR: 18962306a36Sopenharmony_ci case BMC150_MAGN_REG_INT: 19062306a36Sopenharmony_ci case BMC150_MAGN_REG_INT_DRDY: 19162306a36Sopenharmony_ci case BMC150_MAGN_REG_LOW_THRESH: 19262306a36Sopenharmony_ci case BMC150_MAGN_REG_HIGH_THRESH: 19362306a36Sopenharmony_ci case BMC150_MAGN_REG_REP_XY: 19462306a36Sopenharmony_ci case BMC150_MAGN_REG_REP_Z: 19562306a36Sopenharmony_ci return true; 19662306a36Sopenharmony_ci default: 19762306a36Sopenharmony_ci return false; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic bool bmc150_magn_is_volatile_reg(struct device *dev, unsigned int reg) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci switch (reg) { 20462306a36Sopenharmony_ci case BMC150_MAGN_REG_X_L: 20562306a36Sopenharmony_ci case BMC150_MAGN_REG_X_M: 20662306a36Sopenharmony_ci case BMC150_MAGN_REG_Y_L: 20762306a36Sopenharmony_ci case BMC150_MAGN_REG_Y_M: 20862306a36Sopenharmony_ci case BMC150_MAGN_REG_Z_L: 20962306a36Sopenharmony_ci case BMC150_MAGN_REG_Z_M: 21062306a36Sopenharmony_ci case BMC150_MAGN_REG_RHALL_L: 21162306a36Sopenharmony_ci case BMC150_MAGN_REG_RHALL_M: 21262306a36Sopenharmony_ci case BMC150_MAGN_REG_INT_STATUS: 21362306a36Sopenharmony_ci return true; 21462306a36Sopenharmony_ci default: 21562306a36Sopenharmony_ci return false; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ciconst struct regmap_config bmc150_magn_regmap_config = { 22062306a36Sopenharmony_ci .reg_bits = 8, 22162306a36Sopenharmony_ci .val_bits = 8, 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci .max_register = BMC150_MAGN_REG_TRIM_END, 22462306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci .writeable_reg = bmc150_magn_is_writeable_reg, 22762306a36Sopenharmony_ci .volatile_reg = bmc150_magn_is_volatile_reg, 22862306a36Sopenharmony_ci}; 22962306a36Sopenharmony_ciEXPORT_SYMBOL_NS(bmc150_magn_regmap_config, IIO_BMC150_MAGN); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int bmc150_magn_set_power_mode(struct bmc150_magn_data *data, 23262306a36Sopenharmony_ci enum bmc150_magn_power_modes mode, 23362306a36Sopenharmony_ci bool state) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci int ret; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci switch (mode) { 23862306a36Sopenharmony_ci case BMC150_MAGN_POWER_MODE_SUSPEND: 23962306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_POWER, 24062306a36Sopenharmony_ci BMC150_MAGN_MASK_POWER_CTL, !state); 24162306a36Sopenharmony_ci if (ret < 0) 24262306a36Sopenharmony_ci return ret; 24362306a36Sopenharmony_ci usleep_range(BMC150_MAGN_START_UP_TIME_MS * 1000, 20000); 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci case BMC150_MAGN_POWER_MODE_SLEEP: 24662306a36Sopenharmony_ci return regmap_update_bits(data->regmap, 24762306a36Sopenharmony_ci BMC150_MAGN_REG_OPMODE_ODR, 24862306a36Sopenharmony_ci BMC150_MAGN_MASK_OPMODE, 24962306a36Sopenharmony_ci BMC150_MAGN_MODE_SLEEP << 25062306a36Sopenharmony_ci BMC150_MAGN_SHIFT_OPMODE); 25162306a36Sopenharmony_ci case BMC150_MAGN_POWER_MODE_NORMAL: 25262306a36Sopenharmony_ci return regmap_update_bits(data->regmap, 25362306a36Sopenharmony_ci BMC150_MAGN_REG_OPMODE_ODR, 25462306a36Sopenharmony_ci BMC150_MAGN_MASK_OPMODE, 25562306a36Sopenharmony_ci BMC150_MAGN_MODE_NORMAL << 25662306a36Sopenharmony_ci BMC150_MAGN_SHIFT_OPMODE); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return -EINVAL; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int bmc150_magn_set_power_state(struct bmc150_magn_data *data, bool on) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci#ifdef CONFIG_PM 26562306a36Sopenharmony_ci int ret; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (on) { 26862306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(data->dev); 26962306a36Sopenharmony_ci } else { 27062306a36Sopenharmony_ci pm_runtime_mark_last_busy(data->dev); 27162306a36Sopenharmony_ci ret = pm_runtime_put_autosuspend(data->dev); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (ret < 0) { 27562306a36Sopenharmony_ci dev_err(data->dev, 27662306a36Sopenharmony_ci "failed to change power state to %d\n", on); 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci#endif 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int bmc150_magn_get_odr(struct bmc150_magn_data *data, int *val) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int ret, reg_val; 28762306a36Sopenharmony_ci u8 i, odr_val; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_MAGN_REG_OPMODE_ODR, ®_val); 29062306a36Sopenharmony_ci if (ret < 0) 29162306a36Sopenharmony_ci return ret; 29262306a36Sopenharmony_ci odr_val = (reg_val & BMC150_MAGN_MASK_ODR) >> BMC150_MAGN_SHIFT_ODR; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) 29562306a36Sopenharmony_ci if (bmc150_magn_samp_freq_table[i].reg_val == odr_val) { 29662306a36Sopenharmony_ci *val = bmc150_magn_samp_freq_table[i].freq; 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return -EINVAL; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int bmc150_magn_set_odr(struct bmc150_magn_data *data, int val) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci int ret; 30662306a36Sopenharmony_ci u8 i; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) { 30962306a36Sopenharmony_ci if (bmc150_magn_samp_freq_table[i].freq == val) { 31062306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, 31162306a36Sopenharmony_ci BMC150_MAGN_REG_OPMODE_ODR, 31262306a36Sopenharmony_ci BMC150_MAGN_MASK_ODR, 31362306a36Sopenharmony_ci bmc150_magn_samp_freq_table[i]. 31462306a36Sopenharmony_ci reg_val << 31562306a36Sopenharmony_ci BMC150_MAGN_SHIFT_ODR); 31662306a36Sopenharmony_ci if (ret < 0) 31762306a36Sopenharmony_ci return ret; 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return -EINVAL; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic int bmc150_magn_set_max_odr(struct bmc150_magn_data *data, int rep_xy, 32662306a36Sopenharmony_ci int rep_z, int odr) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci int ret, reg_val, max_odr; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (rep_xy <= 0) { 33162306a36Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_MAGN_REG_REP_XY, 33262306a36Sopenharmony_ci ®_val); 33362306a36Sopenharmony_ci if (ret < 0) 33462306a36Sopenharmony_ci return ret; 33562306a36Sopenharmony_ci rep_xy = BMC150_MAGN_REGVAL_TO_REPXY(reg_val); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci if (rep_z <= 0) { 33862306a36Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_MAGN_REG_REP_Z, 33962306a36Sopenharmony_ci ®_val); 34062306a36Sopenharmony_ci if (ret < 0) 34162306a36Sopenharmony_ci return ret; 34262306a36Sopenharmony_ci rep_z = BMC150_MAGN_REGVAL_TO_REPZ(reg_val); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci if (odr <= 0) { 34562306a36Sopenharmony_ci ret = bmc150_magn_get_odr(data, &odr); 34662306a36Sopenharmony_ci if (ret < 0) 34762306a36Sopenharmony_ci return ret; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci /* the maximum selectable read-out frequency from datasheet */ 35062306a36Sopenharmony_ci max_odr = 1000000 / (145 * rep_xy + 500 * rep_z + 980); 35162306a36Sopenharmony_ci if (odr > max_odr) { 35262306a36Sopenharmony_ci dev_err(data->dev, 35362306a36Sopenharmony_ci "Can't set oversampling with sampling freq %d\n", 35462306a36Sopenharmony_ci odr); 35562306a36Sopenharmony_ci return -EINVAL; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci data->max_odr = max_odr; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic s32 bmc150_magn_compensate_x(struct bmc150_magn_trim_regs *tregs, s16 x, 36362306a36Sopenharmony_ci u16 rhall) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci s16 val; 36662306a36Sopenharmony_ci u16 xyz1 = le16_to_cpu(tregs->xyz1); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (x == BMC150_MAGN_XY_OVERFLOW_VAL) 36962306a36Sopenharmony_ci return S32_MIN; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!rhall) 37262306a36Sopenharmony_ci rhall = xyz1; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci val = ((s16)(((u16)((((s32)xyz1) << 14) / rhall)) - ((u16)0x4000))); 37562306a36Sopenharmony_ci val = ((s16)((((s32)x) * ((((((((s32)tregs->xy2) * ((((s32)val) * 37662306a36Sopenharmony_ci ((s32)val)) >> 7)) + (((s32)val) * 37762306a36Sopenharmony_ci ((s32)(((s16)tregs->xy1) << 7)))) >> 9) + ((s32)0x100000)) * 37862306a36Sopenharmony_ci ((s32)(((s16)tregs->x2) + ((s16)0xA0)))) >> 12)) >> 13)) + 37962306a36Sopenharmony_ci (((s16)tregs->x1) << 3); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return (s32)val; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic s32 bmc150_magn_compensate_y(struct bmc150_magn_trim_regs *tregs, s16 y, 38562306a36Sopenharmony_ci u16 rhall) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci s16 val; 38862306a36Sopenharmony_ci u16 xyz1 = le16_to_cpu(tregs->xyz1); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (y == BMC150_MAGN_XY_OVERFLOW_VAL) 39162306a36Sopenharmony_ci return S32_MIN; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (!rhall) 39462306a36Sopenharmony_ci rhall = xyz1; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci val = ((s16)(((u16)((((s32)xyz1) << 14) / rhall)) - ((u16)0x4000))); 39762306a36Sopenharmony_ci val = ((s16)((((s32)y) * ((((((((s32)tregs->xy2) * ((((s32)val) * 39862306a36Sopenharmony_ci ((s32)val)) >> 7)) + (((s32)val) * 39962306a36Sopenharmony_ci ((s32)(((s16)tregs->xy1) << 7)))) >> 9) + ((s32)0x100000)) * 40062306a36Sopenharmony_ci ((s32)(((s16)tregs->y2) + ((s16)0xA0)))) >> 12)) >> 13)) + 40162306a36Sopenharmony_ci (((s16)tregs->y1) << 3); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return (s32)val; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic s32 bmc150_magn_compensate_z(struct bmc150_magn_trim_regs *tregs, s16 z, 40762306a36Sopenharmony_ci u16 rhall) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci s32 val; 41062306a36Sopenharmony_ci u16 xyz1 = le16_to_cpu(tregs->xyz1); 41162306a36Sopenharmony_ci u16 z1 = le16_to_cpu(tregs->z1); 41262306a36Sopenharmony_ci s16 z2 = le16_to_cpu(tregs->z2); 41362306a36Sopenharmony_ci s16 z3 = le16_to_cpu(tregs->z3); 41462306a36Sopenharmony_ci s16 z4 = le16_to_cpu(tregs->z4); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (z == BMC150_MAGN_Z_OVERFLOW_VAL) 41762306a36Sopenharmony_ci return S32_MIN; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci val = (((((s32)(z - z4)) << 15) - ((((s32)z3) * ((s32)(((s16)rhall) - 42062306a36Sopenharmony_ci ((s16)xyz1)))) >> 2)) / (z2 + ((s16)(((((s32)z1) * 42162306a36Sopenharmony_ci ((((s16)rhall) << 1))) + (1 << 15)) >> 16)))); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return val; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int bmc150_magn_read_xyz(struct bmc150_magn_data *data, s32 *buffer) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci int ret; 42962306a36Sopenharmony_ci __le16 values[AXIS_XYZR_MAX]; 43062306a36Sopenharmony_ci s16 raw_x, raw_y, raw_z; 43162306a36Sopenharmony_ci u16 rhall; 43262306a36Sopenharmony_ci struct bmc150_magn_trim_regs tregs; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci ret = regmap_bulk_read(data->regmap, BMC150_MAGN_REG_X_L, 43562306a36Sopenharmony_ci values, sizeof(values)); 43662306a36Sopenharmony_ci if (ret < 0) 43762306a36Sopenharmony_ci return ret; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci raw_x = (s16)le16_to_cpu(values[AXIS_X]) >> BMC150_MAGN_SHIFT_XY_L; 44062306a36Sopenharmony_ci raw_y = (s16)le16_to_cpu(values[AXIS_Y]) >> BMC150_MAGN_SHIFT_XY_L; 44162306a36Sopenharmony_ci raw_z = (s16)le16_to_cpu(values[AXIS_Z]) >> BMC150_MAGN_SHIFT_Z_L; 44262306a36Sopenharmony_ci rhall = le16_to_cpu(values[RHALL]) >> BMC150_MAGN_SHIFT_RHALL_L; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ret = regmap_bulk_read(data->regmap, BMC150_MAGN_REG_TRIM_START, 44562306a36Sopenharmony_ci &tregs, sizeof(tregs)); 44662306a36Sopenharmony_ci if (ret < 0) 44762306a36Sopenharmony_ci return ret; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci buffer[AXIS_X] = bmc150_magn_compensate_x(&tregs, raw_x, rhall); 45062306a36Sopenharmony_ci buffer[AXIS_Y] = bmc150_magn_compensate_y(&tregs, raw_y, rhall); 45162306a36Sopenharmony_ci buffer[AXIS_Z] = bmc150_magn_compensate_z(&tregs, raw_z, rhall); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int bmc150_magn_read_raw(struct iio_dev *indio_dev, 45762306a36Sopenharmony_ci struct iio_chan_spec const *chan, 45862306a36Sopenharmony_ci int *val, int *val2, long mask) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 46162306a36Sopenharmony_ci int ret, tmp; 46262306a36Sopenharmony_ci s32 values[AXIS_XYZ_MAX]; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci switch (mask) { 46562306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 46662306a36Sopenharmony_ci if (iio_buffer_enabled(indio_dev)) 46762306a36Sopenharmony_ci return -EBUSY; 46862306a36Sopenharmony_ci mutex_lock(&data->mutex); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ret = bmc150_magn_set_power_state(data, true); 47162306a36Sopenharmony_ci if (ret < 0) { 47262306a36Sopenharmony_ci mutex_unlock(&data->mutex); 47362306a36Sopenharmony_ci return ret; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci ret = bmc150_magn_read_xyz(data, values); 47762306a36Sopenharmony_ci if (ret < 0) { 47862306a36Sopenharmony_ci bmc150_magn_set_power_state(data, false); 47962306a36Sopenharmony_ci mutex_unlock(&data->mutex); 48062306a36Sopenharmony_ci return ret; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci *val = values[chan->scan_index]; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci ret = bmc150_magn_set_power_state(data, false); 48562306a36Sopenharmony_ci if (ret < 0) { 48662306a36Sopenharmony_ci mutex_unlock(&data->mutex); 48762306a36Sopenharmony_ci return ret; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci mutex_unlock(&data->mutex); 49162306a36Sopenharmony_ci return IIO_VAL_INT; 49262306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 49362306a36Sopenharmony_ci /* 49462306a36Sopenharmony_ci * The API/driver performs an off-chip temperature 49562306a36Sopenharmony_ci * compensation and outputs x/y/z magnetic field data in 49662306a36Sopenharmony_ci * 16 LSB/uT to the upper application layer. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci *val = 0; 49962306a36Sopenharmony_ci *val2 = 625; 50062306a36Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 50162306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 50262306a36Sopenharmony_ci ret = bmc150_magn_get_odr(data, val); 50362306a36Sopenharmony_ci if (ret < 0) 50462306a36Sopenharmony_ci return ret; 50562306a36Sopenharmony_ci return IIO_VAL_INT; 50662306a36Sopenharmony_ci case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 50762306a36Sopenharmony_ci switch (chan->channel2) { 50862306a36Sopenharmony_ci case IIO_MOD_X: 50962306a36Sopenharmony_ci case IIO_MOD_Y: 51062306a36Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_MAGN_REG_REP_XY, 51162306a36Sopenharmony_ci &tmp); 51262306a36Sopenharmony_ci if (ret < 0) 51362306a36Sopenharmony_ci return ret; 51462306a36Sopenharmony_ci *val = BMC150_MAGN_REGVAL_TO_REPXY(tmp); 51562306a36Sopenharmony_ci return IIO_VAL_INT; 51662306a36Sopenharmony_ci case IIO_MOD_Z: 51762306a36Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_MAGN_REG_REP_Z, 51862306a36Sopenharmony_ci &tmp); 51962306a36Sopenharmony_ci if (ret < 0) 52062306a36Sopenharmony_ci return ret; 52162306a36Sopenharmony_ci *val = BMC150_MAGN_REGVAL_TO_REPZ(tmp); 52262306a36Sopenharmony_ci return IIO_VAL_INT; 52362306a36Sopenharmony_ci default: 52462306a36Sopenharmony_ci return -EINVAL; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci default: 52762306a36Sopenharmony_ci return -EINVAL; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic int bmc150_magn_write_raw(struct iio_dev *indio_dev, 53262306a36Sopenharmony_ci struct iio_chan_spec const *chan, 53362306a36Sopenharmony_ci int val, int val2, long mask) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 53662306a36Sopenharmony_ci int ret; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci switch (mask) { 53962306a36Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 54062306a36Sopenharmony_ci if (val > data->max_odr) 54162306a36Sopenharmony_ci return -EINVAL; 54262306a36Sopenharmony_ci mutex_lock(&data->mutex); 54362306a36Sopenharmony_ci ret = bmc150_magn_set_odr(data, val); 54462306a36Sopenharmony_ci mutex_unlock(&data->mutex); 54562306a36Sopenharmony_ci return ret; 54662306a36Sopenharmony_ci case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 54762306a36Sopenharmony_ci switch (chan->channel2) { 54862306a36Sopenharmony_ci case IIO_MOD_X: 54962306a36Sopenharmony_ci case IIO_MOD_Y: 55062306a36Sopenharmony_ci if (val < 1 || val > 511) 55162306a36Sopenharmony_ci return -EINVAL; 55262306a36Sopenharmony_ci mutex_lock(&data->mutex); 55362306a36Sopenharmony_ci ret = bmc150_magn_set_max_odr(data, val, 0, 0); 55462306a36Sopenharmony_ci if (ret < 0) { 55562306a36Sopenharmony_ci mutex_unlock(&data->mutex); 55662306a36Sopenharmony_ci return ret; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, 55962306a36Sopenharmony_ci BMC150_MAGN_REG_REP_XY, 56062306a36Sopenharmony_ci BMC150_MAGN_REG_REP_DATAMASK, 56162306a36Sopenharmony_ci BMC150_MAGN_REPXY_TO_REGVAL 56262306a36Sopenharmony_ci (val)); 56362306a36Sopenharmony_ci mutex_unlock(&data->mutex); 56462306a36Sopenharmony_ci return ret; 56562306a36Sopenharmony_ci case IIO_MOD_Z: 56662306a36Sopenharmony_ci if (val < 1 || val > 256) 56762306a36Sopenharmony_ci return -EINVAL; 56862306a36Sopenharmony_ci mutex_lock(&data->mutex); 56962306a36Sopenharmony_ci ret = bmc150_magn_set_max_odr(data, 0, val, 0); 57062306a36Sopenharmony_ci if (ret < 0) { 57162306a36Sopenharmony_ci mutex_unlock(&data->mutex); 57262306a36Sopenharmony_ci return ret; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, 57562306a36Sopenharmony_ci BMC150_MAGN_REG_REP_Z, 57662306a36Sopenharmony_ci BMC150_MAGN_REG_REP_DATAMASK, 57762306a36Sopenharmony_ci BMC150_MAGN_REPZ_TO_REGVAL 57862306a36Sopenharmony_ci (val)); 57962306a36Sopenharmony_ci mutex_unlock(&data->mutex); 58062306a36Sopenharmony_ci return ret; 58162306a36Sopenharmony_ci default: 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci default: 58562306a36Sopenharmony_ci return -EINVAL; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic ssize_t bmc150_magn_show_samp_freq_avail(struct device *dev, 59062306a36Sopenharmony_ci struct device_attribute *attr, 59162306a36Sopenharmony_ci char *buf) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_to_iio_dev(dev); 59462306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 59562306a36Sopenharmony_ci size_t len = 0; 59662306a36Sopenharmony_ci u8 i; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bmc150_magn_samp_freq_table); i++) { 59962306a36Sopenharmony_ci if (bmc150_magn_samp_freq_table[i].freq > data->max_odr) 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", 60262306a36Sopenharmony_ci bmc150_magn_samp_freq_table[i].freq); 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci /* replace last space with a newline */ 60562306a36Sopenharmony_ci buf[len - 1] = '\n'; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return len; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic const struct iio_mount_matrix * 61162306a36Sopenharmony_cibmc150_magn_get_mount_matrix(const struct iio_dev *indio_dev, 61262306a36Sopenharmony_ci const struct iio_chan_spec *chan) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return &data->orientation; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic const struct iio_chan_spec_ext_info bmc150_magn_ext_info[] = { 62062306a36Sopenharmony_ci IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bmc150_magn_get_mount_matrix), 62162306a36Sopenharmony_ci { } 62262306a36Sopenharmony_ci}; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic IIO_DEV_ATTR_SAMP_FREQ_AVAIL(bmc150_magn_show_samp_freq_avail); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic struct attribute *bmc150_magn_attributes[] = { 62762306a36Sopenharmony_ci &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 62862306a36Sopenharmony_ci NULL, 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic const struct attribute_group bmc150_magn_attrs_group = { 63262306a36Sopenharmony_ci .attrs = bmc150_magn_attributes, 63362306a36Sopenharmony_ci}; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci#define BMC150_MAGN_CHANNEL(_axis) { \ 63662306a36Sopenharmony_ci .type = IIO_MAGN, \ 63762306a36Sopenharmony_ci .modified = 1, \ 63862306a36Sopenharmony_ci .channel2 = IIO_MOD_##_axis, \ 63962306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 64062306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ 64162306a36Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 64262306a36Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), \ 64362306a36Sopenharmony_ci .scan_index = AXIS_##_axis, \ 64462306a36Sopenharmony_ci .scan_type = { \ 64562306a36Sopenharmony_ci .sign = 's', \ 64662306a36Sopenharmony_ci .realbits = 32, \ 64762306a36Sopenharmony_ci .storagebits = 32, \ 64862306a36Sopenharmony_ci .endianness = IIO_LE \ 64962306a36Sopenharmony_ci }, \ 65062306a36Sopenharmony_ci .ext_info = bmc150_magn_ext_info, \ 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic const struct iio_chan_spec bmc150_magn_channels[] = { 65462306a36Sopenharmony_ci BMC150_MAGN_CHANNEL(X), 65562306a36Sopenharmony_ci BMC150_MAGN_CHANNEL(Y), 65662306a36Sopenharmony_ci BMC150_MAGN_CHANNEL(Z), 65762306a36Sopenharmony_ci IIO_CHAN_SOFT_TIMESTAMP(3), 65862306a36Sopenharmony_ci}; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic const struct iio_info bmc150_magn_info = { 66162306a36Sopenharmony_ci .attrs = &bmc150_magn_attrs_group, 66262306a36Sopenharmony_ci .read_raw = bmc150_magn_read_raw, 66362306a36Sopenharmony_ci .write_raw = bmc150_magn_write_raw, 66462306a36Sopenharmony_ci}; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic const unsigned long bmc150_magn_scan_masks[] = { 66762306a36Sopenharmony_ci BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), 66862306a36Sopenharmony_ci 0}; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct iio_poll_func *pf = p; 67362306a36Sopenharmony_ci struct iio_dev *indio_dev = pf->indio_dev; 67462306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 67562306a36Sopenharmony_ci int ret; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci mutex_lock(&data->mutex); 67862306a36Sopenharmony_ci ret = bmc150_magn_read_xyz(data, data->scan.chans); 67962306a36Sopenharmony_ci if (ret < 0) 68062306a36Sopenharmony_ci goto err; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, 68362306a36Sopenharmony_ci pf->timestamp); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cierr: 68662306a36Sopenharmony_ci mutex_unlock(&data->mutex); 68762306a36Sopenharmony_ci iio_trigger_notify_done(indio_dev->trig); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci return IRQ_HANDLED; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic int bmc150_magn_init(struct bmc150_magn_data *data) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci int ret, chip_id; 69562306a36Sopenharmony_ci struct bmc150_magn_preset preset; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators), 69862306a36Sopenharmony_ci data->regulators); 69962306a36Sopenharmony_ci if (ret < 0) { 70062306a36Sopenharmony_ci dev_err(data->dev, "Failed to enable regulators: %d\n", ret); 70162306a36Sopenharmony_ci return ret; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci /* 70462306a36Sopenharmony_ci * 3ms power-on time according to datasheet, let's better 70562306a36Sopenharmony_ci * be safe than sorry and set this delay to 5ms. 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci msleep(5); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, 71062306a36Sopenharmony_ci false); 71162306a36Sopenharmony_ci if (ret < 0) { 71262306a36Sopenharmony_ci dev_err(data->dev, 71362306a36Sopenharmony_ci "Failed to bring up device from suspend mode\n"); 71462306a36Sopenharmony_ci goto err_regulator_disable; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci ret = regmap_read(data->regmap, BMC150_MAGN_REG_CHIP_ID, &chip_id); 71862306a36Sopenharmony_ci if (ret < 0) { 71962306a36Sopenharmony_ci dev_err(data->dev, "Failed reading chip id\n"); 72062306a36Sopenharmony_ci goto err_poweroff; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci if (chip_id != BMC150_MAGN_CHIP_ID_VAL) { 72362306a36Sopenharmony_ci dev_err(data->dev, "Invalid chip id 0x%x\n", chip_id); 72462306a36Sopenharmony_ci ret = -ENODEV; 72562306a36Sopenharmony_ci goto err_poweroff; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci dev_dbg(data->dev, "Chip id %x\n", chip_id); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci preset = bmc150_magn_presets_table[BMC150_MAGN_DEFAULT_PRESET]; 73062306a36Sopenharmony_ci ret = bmc150_magn_set_odr(data, preset.odr); 73162306a36Sopenharmony_ci if (ret < 0) { 73262306a36Sopenharmony_ci dev_err(data->dev, "Failed to set ODR to %d\n", 73362306a36Sopenharmony_ci preset.odr); 73462306a36Sopenharmony_ci goto err_poweroff; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_MAGN_REG_REP_XY, 73862306a36Sopenharmony_ci BMC150_MAGN_REPXY_TO_REGVAL(preset.rep_xy)); 73962306a36Sopenharmony_ci if (ret < 0) { 74062306a36Sopenharmony_ci dev_err(data->dev, "Failed to set REP XY to %d\n", 74162306a36Sopenharmony_ci preset.rep_xy); 74262306a36Sopenharmony_ci goto err_poweroff; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci ret = regmap_write(data->regmap, BMC150_MAGN_REG_REP_Z, 74662306a36Sopenharmony_ci BMC150_MAGN_REPZ_TO_REGVAL(preset.rep_z)); 74762306a36Sopenharmony_ci if (ret < 0) { 74862306a36Sopenharmony_ci dev_err(data->dev, "Failed to set REP Z to %d\n", 74962306a36Sopenharmony_ci preset.rep_z); 75062306a36Sopenharmony_ci goto err_poweroff; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci ret = bmc150_magn_set_max_odr(data, preset.rep_xy, preset.rep_z, 75462306a36Sopenharmony_ci preset.odr); 75562306a36Sopenharmony_ci if (ret < 0) 75662306a36Sopenharmony_ci goto err_poweroff; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL, 75962306a36Sopenharmony_ci true); 76062306a36Sopenharmony_ci if (ret < 0) { 76162306a36Sopenharmony_ci dev_err(data->dev, "Failed to power on device\n"); 76262306a36Sopenharmony_ci goto err_poweroff; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci return 0; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cierr_poweroff: 76862306a36Sopenharmony_ci bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); 76962306a36Sopenharmony_cierr_regulator_disable: 77062306a36Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); 77162306a36Sopenharmony_ci return ret; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int bmc150_magn_reset_intr(struct bmc150_magn_data *data) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci int tmp; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* 77962306a36Sopenharmony_ci * Data Ready (DRDY) is always cleared after 78062306a36Sopenharmony_ci * readout of data registers ends. 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_ci return regmap_read(data->regmap, BMC150_MAGN_REG_X_L, &tmp); 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic void bmc150_magn_trig_reen(struct iio_trigger *trig) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 78862306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 78962306a36Sopenharmony_ci int ret; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (!data->dready_trigger_on) 79262306a36Sopenharmony_ci return; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci mutex_lock(&data->mutex); 79562306a36Sopenharmony_ci ret = bmc150_magn_reset_intr(data); 79662306a36Sopenharmony_ci mutex_unlock(&data->mutex); 79762306a36Sopenharmony_ci if (ret) 79862306a36Sopenharmony_ci dev_err(data->dev, "Failed to reset interrupt\n"); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig, 80262306a36Sopenharmony_ci bool state) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 80562306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 80662306a36Sopenharmony_ci int ret = 0; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci mutex_lock(&data->mutex); 80962306a36Sopenharmony_ci if (state == data->dready_trigger_on) 81062306a36Sopenharmony_ci goto err_unlock; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY, 81362306a36Sopenharmony_ci BMC150_MAGN_MASK_DRDY_EN, 81462306a36Sopenharmony_ci state << BMC150_MAGN_SHIFT_DRDY_EN); 81562306a36Sopenharmony_ci if (ret < 0) 81662306a36Sopenharmony_ci goto err_unlock; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci data->dready_trigger_on = state; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (state) { 82162306a36Sopenharmony_ci ret = bmc150_magn_reset_intr(data); 82262306a36Sopenharmony_ci if (ret < 0) 82362306a36Sopenharmony_ci goto err_unlock; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci mutex_unlock(&data->mutex); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cierr_unlock: 83062306a36Sopenharmony_ci mutex_unlock(&data->mutex); 83162306a36Sopenharmony_ci return ret; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic const struct iio_trigger_ops bmc150_magn_trigger_ops = { 83562306a36Sopenharmony_ci .set_trigger_state = bmc150_magn_data_rdy_trigger_set_state, 83662306a36Sopenharmony_ci .reenable = bmc150_magn_trig_reen, 83762306a36Sopenharmony_ci}; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic int bmc150_magn_buffer_preenable(struct iio_dev *indio_dev) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return bmc150_magn_set_power_state(data, true); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int bmc150_magn_buffer_postdisable(struct iio_dev *indio_dev) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci return bmc150_magn_set_power_state(data, false); 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = { 85462306a36Sopenharmony_ci .preenable = bmc150_magn_buffer_preenable, 85562306a36Sopenharmony_ci .postdisable = bmc150_magn_buffer_postdisable, 85662306a36Sopenharmony_ci}; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic const char *bmc150_magn_match_acpi_device(struct device *dev) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci const struct acpi_device_id *id; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci id = acpi_match_device(dev->driver->acpi_match_table, dev); 86362306a36Sopenharmony_ci if (!id) 86462306a36Sopenharmony_ci return NULL; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci return dev_name(dev); 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ciint bmc150_magn_probe(struct device *dev, struct regmap *regmap, 87062306a36Sopenharmony_ci int irq, const char *name) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci struct bmc150_magn_data *data; 87362306a36Sopenharmony_ci struct iio_dev *indio_dev; 87462306a36Sopenharmony_ci int ret; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 87762306a36Sopenharmony_ci if (!indio_dev) 87862306a36Sopenharmony_ci return -ENOMEM; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci data = iio_priv(indio_dev); 88162306a36Sopenharmony_ci dev_set_drvdata(dev, indio_dev); 88262306a36Sopenharmony_ci data->regmap = regmap; 88362306a36Sopenharmony_ci data->irq = irq; 88462306a36Sopenharmony_ci data->dev = dev; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci data->regulators[0].supply = "vdd"; 88762306a36Sopenharmony_ci data->regulators[1].supply = "vddio"; 88862306a36Sopenharmony_ci ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators), 88962306a36Sopenharmony_ci data->regulators); 89062306a36Sopenharmony_ci if (ret) 89162306a36Sopenharmony_ci return dev_err_probe(dev, ret, "failed to get regulators\n"); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci ret = iio_read_mount_matrix(dev, &data->orientation); 89462306a36Sopenharmony_ci if (ret) 89562306a36Sopenharmony_ci return ret; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (!name && ACPI_HANDLE(dev)) 89862306a36Sopenharmony_ci name = bmc150_magn_match_acpi_device(dev); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci mutex_init(&data->mutex); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci ret = bmc150_magn_init(data); 90362306a36Sopenharmony_ci if (ret < 0) 90462306a36Sopenharmony_ci return ret; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci indio_dev->channels = bmc150_magn_channels; 90762306a36Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(bmc150_magn_channels); 90862306a36Sopenharmony_ci indio_dev->available_scan_masks = bmc150_magn_scan_masks; 90962306a36Sopenharmony_ci indio_dev->name = name; 91062306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 91162306a36Sopenharmony_ci indio_dev->info = &bmc150_magn_info; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (irq > 0) { 91462306a36Sopenharmony_ci data->dready_trig = devm_iio_trigger_alloc(dev, 91562306a36Sopenharmony_ci "%s-dev%d", 91662306a36Sopenharmony_ci indio_dev->name, 91762306a36Sopenharmony_ci iio_device_id(indio_dev)); 91862306a36Sopenharmony_ci if (!data->dready_trig) { 91962306a36Sopenharmony_ci ret = -ENOMEM; 92062306a36Sopenharmony_ci dev_err(dev, "iio trigger alloc failed\n"); 92162306a36Sopenharmony_ci goto err_poweroff; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci data->dready_trig->ops = &bmc150_magn_trigger_ops; 92562306a36Sopenharmony_ci iio_trigger_set_drvdata(data->dready_trig, indio_dev); 92662306a36Sopenharmony_ci ret = iio_trigger_register(data->dready_trig); 92762306a36Sopenharmony_ci if (ret) { 92862306a36Sopenharmony_ci dev_err(dev, "iio trigger register failed\n"); 92962306a36Sopenharmony_ci goto err_poweroff; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci ret = request_threaded_irq(irq, 93362306a36Sopenharmony_ci iio_trigger_generic_data_rdy_poll, 93462306a36Sopenharmony_ci NULL, 93562306a36Sopenharmony_ci IRQF_TRIGGER_RISING | IRQF_ONESHOT, 93662306a36Sopenharmony_ci BMC150_MAGN_IRQ_NAME, 93762306a36Sopenharmony_ci data->dready_trig); 93862306a36Sopenharmony_ci if (ret < 0) { 93962306a36Sopenharmony_ci dev_err(dev, "request irq %d failed\n", irq); 94062306a36Sopenharmony_ci goto err_trigger_unregister; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci ret = iio_triggered_buffer_setup(indio_dev, 94562306a36Sopenharmony_ci iio_pollfunc_store_time, 94662306a36Sopenharmony_ci bmc150_magn_trigger_handler, 94762306a36Sopenharmony_ci &bmc150_magn_buffer_setup_ops); 94862306a36Sopenharmony_ci if (ret < 0) { 94962306a36Sopenharmony_ci dev_err(dev, "iio triggered buffer setup failed\n"); 95062306a36Sopenharmony_ci goto err_free_irq; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci ret = pm_runtime_set_active(dev); 95462306a36Sopenharmony_ci if (ret) 95562306a36Sopenharmony_ci goto err_buffer_cleanup; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci pm_runtime_enable(dev); 95862306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 95962306a36Sopenharmony_ci BMC150_MAGN_AUTO_SUSPEND_DELAY_MS); 96062306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci ret = iio_device_register(indio_dev); 96362306a36Sopenharmony_ci if (ret < 0) { 96462306a36Sopenharmony_ci dev_err(dev, "unable to register iio device\n"); 96562306a36Sopenharmony_ci goto err_pm_cleanup; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci dev_dbg(dev, "Registered device %s\n", name); 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cierr_pm_cleanup: 97262306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 97362306a36Sopenharmony_ci pm_runtime_disable(dev); 97462306a36Sopenharmony_cierr_buffer_cleanup: 97562306a36Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 97662306a36Sopenharmony_cierr_free_irq: 97762306a36Sopenharmony_ci if (irq > 0) 97862306a36Sopenharmony_ci free_irq(irq, data->dready_trig); 97962306a36Sopenharmony_cierr_trigger_unregister: 98062306a36Sopenharmony_ci if (data->dready_trig) 98162306a36Sopenharmony_ci iio_trigger_unregister(data->dready_trig); 98262306a36Sopenharmony_cierr_poweroff: 98362306a36Sopenharmony_ci bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); 98462306a36Sopenharmony_ci return ret; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ciEXPORT_SYMBOL_NS(bmc150_magn_probe, IIO_BMC150_MAGN); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_civoid bmc150_magn_remove(struct device *dev) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 99162306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci iio_device_unregister(indio_dev); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci pm_runtime_disable(dev); 99662306a36Sopenharmony_ci pm_runtime_set_suspended(dev); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci iio_triggered_buffer_cleanup(indio_dev); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (data->irq > 0) 100162306a36Sopenharmony_ci free_irq(data->irq, data->dready_trig); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (data->dready_trig) 100462306a36Sopenharmony_ci iio_trigger_unregister(data->dready_trig); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci mutex_lock(&data->mutex); 100762306a36Sopenharmony_ci bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); 100862306a36Sopenharmony_ci mutex_unlock(&data->mutex); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ciEXPORT_SYMBOL_NS(bmc150_magn_remove, IIO_BMC150_MAGN); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci#ifdef CONFIG_PM 101562306a36Sopenharmony_cistatic int bmc150_magn_runtime_suspend(struct device *dev) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 101862306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 101962306a36Sopenharmony_ci int ret; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci mutex_lock(&data->mutex); 102262306a36Sopenharmony_ci ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SLEEP, 102362306a36Sopenharmony_ci true); 102462306a36Sopenharmony_ci mutex_unlock(&data->mutex); 102562306a36Sopenharmony_ci if (ret < 0) { 102662306a36Sopenharmony_ci dev_err(dev, "powering off device failed\n"); 102762306a36Sopenharmony_ci return ret; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci return 0; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci/* 103362306a36Sopenharmony_ci * Should be called with data->mutex held. 103462306a36Sopenharmony_ci */ 103562306a36Sopenharmony_cistatic int bmc150_magn_runtime_resume(struct device *dev) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 103862306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci return bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL, 104162306a36Sopenharmony_ci true); 104262306a36Sopenharmony_ci} 104362306a36Sopenharmony_ci#endif 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 104662306a36Sopenharmony_cistatic int bmc150_magn_suspend(struct device *dev) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 104962306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 105062306a36Sopenharmony_ci int ret; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci mutex_lock(&data->mutex); 105362306a36Sopenharmony_ci ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SLEEP, 105462306a36Sopenharmony_ci true); 105562306a36Sopenharmony_ci mutex_unlock(&data->mutex); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci return ret; 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_cistatic int bmc150_magn_resume(struct device *dev) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 106362306a36Sopenharmony_ci struct bmc150_magn_data *data = iio_priv(indio_dev); 106462306a36Sopenharmony_ci int ret; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci mutex_lock(&data->mutex); 106762306a36Sopenharmony_ci ret = bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_NORMAL, 106862306a36Sopenharmony_ci true); 106962306a36Sopenharmony_ci mutex_unlock(&data->mutex); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci return ret; 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci#endif 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ciconst struct dev_pm_ops bmc150_magn_pm_ops = { 107662306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(bmc150_magn_suspend, bmc150_magn_resume) 107762306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(bmc150_magn_runtime_suspend, 107862306a36Sopenharmony_ci bmc150_magn_runtime_resume, NULL) 107962306a36Sopenharmony_ci}; 108062306a36Sopenharmony_ciEXPORT_SYMBOL_NS(bmc150_magn_pm_ops, IIO_BMC150_MAGN); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ciMODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); 108362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 108462306a36Sopenharmony_ciMODULE_DESCRIPTION("BMC150 magnetometer core driver"); 1085