| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * ADXL345 3-Axis Digital Accelerometer IIO core driver
- *
- * Copyright (c) 2017 Eva Rachel Retuya <eraretuya@gmail.com>
- *
- * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
- */
- #include <linux/bitfield.h>
- #include <linux/bitops.h>
- #include <linux/interrupt.h>
- #include <linux/module.h>
- #include <linux/property.h>
- #include <linux/regmap.h>
- #include <linux/units.h>
- #include <linux/iio/iio.h>
- #include <linux/iio/sysfs.h>
- #include <linux/iio/buffer.h>
- #include <linux/iio/events.h>
- #include <linux/iio/kfifo_buf.h>
- #include "adxl345.h"
- #define ADXL345_FIFO_BYPASS 0
- #define ADXL345_FIFO_FIFO 1
- #define ADXL345_FIFO_STREAM 2
- #define ADXL345_DIRS 3
- #define ADXL345_INT_NONE 0xff
- #define ADXL345_INT1 0
- #define ADXL345_INT2 1
- #define ADXL345_REG_TAP_AXIS_MSK GENMASK(2, 0)
- #define ADXL345_REG_TAP_SUPPRESS_MSK BIT(3)
- #define ADXL345_REG_TAP_SUPPRESS BIT(3)
- #define ADXL345_POWER_CTL_INACT_MSK (ADXL345_POWER_CTL_AUTO_SLEEP | ADXL345_POWER_CTL_LINK)
- #define ADXL345_TAP_Z_EN BIT(0)
- #define ADXL345_TAP_Y_EN BIT(1)
- #define ADXL345_TAP_X_EN BIT(2)
- #define ADXL345_REG_TAP_SUPPRESS BIT(3)
- #define ADXL345_INACT_Z_EN BIT(0)
- #define ADXL345_INACT_Y_EN BIT(1)
- #define ADXL345_INACT_X_EN BIT(2)
- #define ADXL345_REG_INACT_ACDC BIT(3)
- #define ADXL345_ACT_INACT_NO_AXIS_EN 0x00
- #define ADXL345_INACT_XYZ_EN (ADXL345_INACT_Z_EN | ADXL345_INACT_Y_EN | ADXL345_INACT_X_EN)
- #define ADXL345_ACT_Z_EN BIT(4)
- #define ADXL345_ACT_Y_EN BIT(5)
- #define ADXL345_ACT_X_EN BIT(6)
- #define ADXL345_REG_ACT_ACDC BIT(7)
- #define ADXL345_ACT_XYZ_EN (ADXL345_ACT_Z_EN | ADXL345_ACT_Y_EN | ADXL345_ACT_X_EN)
- #define ADXL345_COUPLING_DC 0
- #define ADXL345_COUPLING_AC 1
- #define ADXL345_REG_NO_ACDC 0x00
- /* single/double tap */
- enum adxl345_tap_type {
- ADXL345_SINGLE_TAP,
- ADXL345_DOUBLE_TAP,
- };
- static const unsigned int adxl345_tap_int_reg[] = {
- [ADXL345_SINGLE_TAP] = ADXL345_INT_SINGLE_TAP,
- [ADXL345_DOUBLE_TAP] = ADXL345_INT_DOUBLE_TAP,
- };
- enum adxl345_tap_time_type {
- ADXL345_TAP_TIME_LATENT,
- ADXL345_TAP_TIME_WINDOW,
- ADXL345_TAP_TIME_DUR,
- };
- static const unsigned int adxl345_tap_time_reg[] = {
- [ADXL345_TAP_TIME_LATENT] = ADXL345_REG_LATENT,
- [ADXL345_TAP_TIME_WINDOW] = ADXL345_REG_WINDOW,
- [ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR,
- };
- /* activity/inactivity */
- enum adxl345_activity_type {
- ADXL345_ACTIVITY,
- ADXL345_INACTIVITY,
- ADXL345_ACTIVITY_AC,
- ADXL345_INACTIVITY_AC,
- ADXL345_INACTIVITY_FF,
- };
- static const unsigned int adxl345_act_int_reg[] = {
- [ADXL345_ACTIVITY] = ADXL345_INT_ACTIVITY,
- [ADXL345_INACTIVITY] = ADXL345_INT_INACTIVITY,
- [ADXL345_ACTIVITY_AC] = ADXL345_INT_ACTIVITY,
- [ADXL345_INACTIVITY_AC] = ADXL345_INT_INACTIVITY,
- [ADXL345_INACTIVITY_FF] = ADXL345_INT_FREE_FALL,
- };
- static const unsigned int adxl345_act_thresh_reg[] = {
- [ADXL345_ACTIVITY] = ADXL345_REG_THRESH_ACT,
- [ADXL345_INACTIVITY] = ADXL345_REG_THRESH_INACT,
- [ADXL345_ACTIVITY_AC] = ADXL345_REG_THRESH_ACT,
- [ADXL345_INACTIVITY_AC] = ADXL345_REG_THRESH_INACT,
- [ADXL345_INACTIVITY_FF] = ADXL345_REG_THRESH_FF,
- };
- static const unsigned int adxl345_act_acdc_msk[] = {
- [ADXL345_ACTIVITY] = ADXL345_REG_ACT_ACDC,
- [ADXL345_INACTIVITY] = ADXL345_REG_INACT_ACDC,
- [ADXL345_ACTIVITY_AC] = ADXL345_REG_ACT_ACDC,
- [ADXL345_INACTIVITY_AC] = ADXL345_REG_INACT_ACDC,
- [ADXL345_INACTIVITY_FF] = ADXL345_REG_NO_ACDC,
- };
- enum adxl345_odr {
- ADXL345_ODR_0P10HZ = 0,
- ADXL345_ODR_0P20HZ,
- ADXL345_ODR_0P39HZ,
- ADXL345_ODR_0P78HZ,
- ADXL345_ODR_1P56HZ,
- ADXL345_ODR_3P13HZ,
- ADXL345_ODR_6P25HZ,
- ADXL345_ODR_12P50HZ,
- ADXL345_ODR_25HZ,
- ADXL345_ODR_50HZ,
- ADXL345_ODR_100HZ,
- ADXL345_ODR_200HZ,
- ADXL345_ODR_400HZ,
- ADXL345_ODR_800HZ,
- ADXL345_ODR_1600HZ,
- ADXL345_ODR_3200HZ,
- };
- enum adxl345_range {
- ADXL345_2G_RANGE = 0,
- ADXL345_4G_RANGE,
- ADXL345_8G_RANGE,
- ADXL345_16G_RANGE,
- };
- /* Certain features recommend 12.5 Hz - 400 Hz ODR */
- static const int adxl345_odr_tbl[][2] = {
- [ADXL345_ODR_0P10HZ] = { 0, 97000 },
- [ADXL345_ODR_0P20HZ] = { 0, 195000 },
- [ADXL345_ODR_0P39HZ] = { 0, 390000 },
- [ADXL345_ODR_0P78HZ] = { 0, 781000 },
- [ADXL345_ODR_1P56HZ] = { 1, 562000 },
- [ADXL345_ODR_3P13HZ] = { 3, 125000 },
- [ADXL345_ODR_6P25HZ] = { 6, 250000 },
- [ADXL345_ODR_12P50HZ] = { 12, 500000 },
- [ADXL345_ODR_25HZ] = { 25, 0 },
- [ADXL345_ODR_50HZ] = { 50, 0 },
- [ADXL345_ODR_100HZ] = { 100, 0 },
- [ADXL345_ODR_200HZ] = { 200, 0 },
- [ADXL345_ODR_400HZ] = { 400, 0 },
- [ADXL345_ODR_800HZ] = { 800, 0 },
- [ADXL345_ODR_1600HZ] = { 1600, 0 },
- [ADXL345_ODR_3200HZ] = { 3200, 0 },
- };
- /*
- * Full resolution frequency table:
- * (g * 2 * 9.80665) / (2^(resolution) - 1)
- *
- * resolution := 13 (full)
- * g := 2|4|8|16
- *
- * 2g at 13bit: 0.004789
- * 4g at 13bit: 0.009578
- * 8g at 13bit: 0.019156
- * 16g at 16bit: 0.038312
- */
- static const int adxl345_fullres_range_tbl[][2] = {
- [ADXL345_2G_RANGE] = { 0, 4789 },
- [ADXL345_4G_RANGE] = { 0, 9578 },
- [ADXL345_8G_RANGE] = { 0, 19156 },
- [ADXL345_16G_RANGE] = { 0, 38312 },
- };
- /* scaling */
- static const int adxl345_range_factor_tbl[] = {
- [ADXL345_2G_RANGE] = 1,
- [ADXL345_4G_RANGE] = 2,
- [ADXL345_8G_RANGE] = 4,
- [ADXL345_16G_RANGE] = 8,
- };
- struct adxl345_state {
- const struct adxl345_chip_info *info;
- struct regmap *regmap;
- bool fifo_delay; /* delay: delay is needed for SPI */
- u8 watermark;
- u8 fifo_mode;
- u8 inact_threshold;
- u32 inact_time_ms;
- u32 tap_duration_us;
- u32 tap_latent_us;
- u32 tap_window_us;
- __le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN);
- };
- static const struct iio_event_spec adxl345_events[] = {
- {
- /* activity */
- .type = IIO_EV_TYPE_MAG,
- .dir = IIO_EV_DIR_RISING,
- .mask_shared_by_type =
- BIT(IIO_EV_INFO_ENABLE) |
- BIT(IIO_EV_INFO_VALUE),
- },
- {
- /* activity, ac bit set */
- .type = IIO_EV_TYPE_MAG_ADAPTIVE,
- .dir = IIO_EV_DIR_RISING,
- .mask_shared_by_type =
- BIT(IIO_EV_INFO_ENABLE) |
- BIT(IIO_EV_INFO_VALUE),
- },
- {
- /* single tap */
- .type = IIO_EV_TYPE_GESTURE,
- .dir = IIO_EV_DIR_SINGLETAP,
- .mask_separate = BIT(IIO_EV_INFO_ENABLE),
- .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_TIMEOUT),
- },
- {
- /* double tap */
- .type = IIO_EV_TYPE_GESTURE,
- .dir = IIO_EV_DIR_DOUBLETAP,
- .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
- BIT(IIO_EV_INFO_RESET_TIMEOUT) |
- BIT(IIO_EV_INFO_TAP2_MIN_DELAY),
- },
- };
- #define ADXL345_CHANNEL(index, reg, axis) { \
- .type = IIO_ACCEL, \
- .modified = 1, \
- .channel2 = IIO_MOD_##axis, \
- .address = (reg), \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_CALIBBIAS), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_SAMP_FREQ), \
- .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_SAMP_FREQ), \
- .scan_index = (index), \
- .scan_type = { \
- .sign = 's', \
- .realbits = 13, \
- .storagebits = 16, \
- .endianness = IIO_LE, \
- }, \
- .event_spec = adxl345_events, \
- .num_event_specs = ARRAY_SIZE(adxl345_events), \
- }
- enum adxl345_chans {
- chan_x, chan_y, chan_z,
- };
- static const struct iio_event_spec adxl345_fake_chan_events[] = {
- {
- /* inactivity */
- .type = IIO_EV_TYPE_MAG,
- .dir = IIO_EV_DIR_FALLING,
- .mask_separate = BIT(IIO_EV_INFO_ENABLE),
- .mask_shared_by_type =
- BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_PERIOD),
- },
- {
- /* inactivity, AC bit set */
- .type = IIO_EV_TYPE_MAG_ADAPTIVE,
- .dir = IIO_EV_DIR_FALLING,
- .mask_separate = BIT(IIO_EV_INFO_ENABLE),
- .mask_shared_by_type =
- BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_PERIOD),
- },
- };
- static const struct iio_chan_spec adxl345_channels[] = {
- ADXL345_CHANNEL(0, chan_x, X),
- ADXL345_CHANNEL(1, chan_y, Y),
- ADXL345_CHANNEL(2, chan_z, Z),
- {
- .type = IIO_ACCEL,
- .modified = 1,
- .channel2 = IIO_MOD_X_AND_Y_AND_Z,
- .scan_index = -1, /* Fake channel */
- .event_spec = adxl345_fake_chan_events,
- .num_event_specs = ARRAY_SIZE(adxl345_fake_chan_events),
- },
- };
- static const unsigned long adxl345_scan_masks[] = {
- BIT(chan_x) | BIT(chan_y) | BIT(chan_z),
- 0
- };
- bool adxl345_is_volatile_reg(struct device *dev, unsigned int reg)
- {
- switch (reg) {
- case ADXL345_REG_DATA_AXIS(0):
- case ADXL345_REG_DATA_AXIS(1):
- case ADXL345_REG_DATA_AXIS(2):
- case ADXL345_REG_DATA_AXIS(3):
- case ADXL345_REG_DATA_AXIS(4):
- case ADXL345_REG_DATA_AXIS(5):
- case ADXL345_REG_ACT_TAP_STATUS:
- case ADXL345_REG_FIFO_STATUS:
- case ADXL345_REG_INT_SOURCE:
- return true;
- default:
- return false;
- }
- }
- EXPORT_SYMBOL_NS_GPL(adxl345_is_volatile_reg, "IIO_ADXL345");
- /**
- * adxl345_set_measure_en() - Enable and disable measuring.
- *
- * @st: The device data.
- * @en: Enable measurements, else standby mode.
- *
- * For lowest power operation, standby mode can be used. In standby mode,
- * current consumption is supposed to be reduced to 0.1uA (typical). In this
- * mode no measurements are made. Placing the device into standby mode
- * preserves the contents of FIFO.
- *
- * Return: Returns 0 if successful, or a negative error value.
- */
- static int adxl345_set_measure_en(struct adxl345_state *st, bool en)
- {
- return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL,
- ADXL345_POWER_CTL_MEASURE, en);
- }
- /* activity / inactivity */
- static int adxl345_set_inact_threshold(struct adxl345_state *st,
- unsigned int threshold)
- {
- int ret;
- st->inact_threshold = min(U8_MAX, threshold);
- ret = regmap_write(st->regmap,
- adxl345_act_thresh_reg[ADXL345_INACTIVITY],
- st->inact_threshold);
- if (ret)
- return ret;
- return regmap_write(st->regmap,
- adxl345_act_thresh_reg[ADXL345_INACTIVITY_FF],
- st->inact_threshold);
- }
- static int adxl345_set_default_time(struct adxl345_state *st)
- {
- int max_boundary = U8_MAX;
- int min_boundary = 10;
- enum adxl345_odr odr;
- unsigned int regval;
- unsigned int val;
- int ret;
- /* Generated inactivity time based on ODR */
- ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
- if (ret)
- return ret;
- odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
- val = clamp(max_boundary - adxl345_odr_tbl[odr][0],
- min_boundary, max_boundary);
- st->inact_time_ms = MILLI * val;
- /* Inactivity time in s */
- return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val);
- }
- static int adxl345_set_inactivity_time(struct adxl345_state *st, u32 val_int)
- {
- st->inact_time_ms = MILLI * val_int;
- return regmap_write(st->regmap, ADXL345_REG_TIME_INACT, val_int);
- }
- static int adxl345_set_freefall_time(struct adxl345_state *st, u32 val_fract)
- {
- /*
- * Datasheet max. value is 255 * 5000 us = 1.275000 seconds.
- *
- * Recommended values between 100ms and 350ms (0x14 to 0x46)
- */
- st->inact_time_ms = DIV_ROUND_UP(val_fract, MILLI);
- return regmap_write(st->regmap, ADXL345_REG_TIME_FF,
- DIV_ROUND_CLOSEST(val_fract, 5));
- }
- /**
- * adxl345_set_inact_time - Configure inactivity time explicitly or by ODR.
- * @st: The sensor state instance.
- * @val_int: The inactivity time, integer part.
- * @val_fract: The inactivity time, fractional part when val_int is 0.
- *
- * Inactivity time can be configured between 1 and 255 seconds. If a user sets
- * val_s to 0, a default inactivity time is calculated automatically (since 0 is
- * also invalid and undefined by the sensor).
- *
- * In such cases, power consumption should be considered: the inactivity period
- * should be shorter at higher sampling frequencies and longer at lower ones.
- * Specifically, for frequencies above 255 Hz, the default is set to 10 seconds;
- * for frequencies below 10 Hz, it defaults to 255 seconds.
- *
- * The calculation method subtracts the integer part of the configured sample
- * frequency from 255 to estimate the inactivity time in seconds. Sub-Hertz
- * values are ignored in this approximation. Since the recommended output data
- * rates (ODRs) for features like activity/inactivity detection, sleep modes,
- * and free fall range between 12.5 Hz and 400 Hz, frequencies outside this
- * range will either use the defined boundary defaults or require explicit
- * configuration via val_s.
- *
- * Return: 0 or error value.
- */
- static int adxl345_set_inact_time(struct adxl345_state *st, u32 val_int,
- u32 val_fract)
- {
- if (val_int > 0) {
- /* Time >= 1s, inactivity */
- return adxl345_set_inactivity_time(st, val_int);
- } else if (val_int == 0) {
- if (val_fract > 0) {
- /* Time < 1s, free-fall */
- return adxl345_set_freefall_time(st, val_fract);
- } else if (val_fract == 0) {
- /* Time == 0.0s */
- return adxl345_set_default_time(st);
- }
- }
- /* Do not support negative or wrong input. */
- return -EINVAL;
- }
- /**
- * adxl345_is_act_inact_ac() - Verify if AC or DC coupling is currently enabled.
- *
- * @st: The device data.
- * @type: The activity or inactivity type.
- *
- * Given a type of activity / inactivity combined with either AC coupling set or
- * default to DC, this function verifies if the combination is currently
- * configured, hence enabled or not.
- *
- * Return: true if configured coupling matches the provided type, else a negative
- * error value.
- */
- static int adxl345_is_act_inact_ac(struct adxl345_state *st,
- enum adxl345_activity_type type)
- {
- unsigned int regval;
- bool coupling;
- int ret;
- if (type == ADXL345_INACTIVITY_FF)
- return true;
- ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val);
- if (ret)
- return ret;
- coupling = adxl345_act_acdc_msk[type] & regval;
- switch (type) {
- case ADXL345_ACTIVITY:
- case ADXL345_INACTIVITY:
- return coupling == ADXL345_COUPLING_DC;
- case ADXL345_ACTIVITY_AC:
- case ADXL345_INACTIVITY_AC:
- return coupling == ADXL345_COUPLING_AC;
- default:
- return -EINVAL;
- }
- }
- /**
- * adxl345_set_act_inact_ac() - Configure AC coupling or DC coupling.
- *
- * @st: The device data.
- * @type: Provide a type of activity or inactivity.
- * @cmd_en: enable or disable AC coupling.
- *
- * Enables AC coupling or DC coupling depending on the provided type argument.
- * Note: Activity and inactivity can be either AC coupled or DC coupled not
- * both at the same time.
- *
- * Return: 0 if successful, else error value.
- */
- static int adxl345_set_act_inact_ac(struct adxl345_state *st,
- enum adxl345_activity_type type,
- bool cmd_en)
- {
- unsigned int act_inact_ac;
- if (type == ADXL345_ACTIVITY_AC || type == ADXL345_INACTIVITY_AC)
- act_inact_ac = ADXL345_COUPLING_AC && cmd_en;
- else
- act_inact_ac = ADXL345_COUPLING_DC && cmd_en;
- /*
- * A setting of false selects dc-coupled operation, and a setting of
- * true enables ac-coupled operation. In dc-coupled operation, the
- * current acceleration magnitude is compared directly with
- * ADXL345_REG_THRESH_ACT and ADXL345_REG_THRESH_INACT to determine
- * whether activity or inactivity is detected.
- *
- * In ac-coupled operation for activity detection, the acceleration
- * value at the start of activity detection is taken as a reference
- * value. New samples of acceleration are then compared to this
- * reference value, and if the magnitude of the difference exceeds the
- * ADXL345_REG_THRESH_ACT value, the device triggers an activity
- * interrupt.
- *
- * Similarly, in ac-coupled operation for inactivity detection, a
- * reference value is used for comparison and is updated whenever the
- * device exceeds the inactivity threshold. After the reference value
- * is selected, the device compares the magnitude of the difference
- * between the reference value and the current acceleration with
- * ADXL345_REG_THRESH_INACT. If the difference is less than the value in
- * ADXL345_REG_THRESH_INACT for the time in ADXL345_REG_TIME_INACT, the
- * device is considered inactive and the inactivity interrupt is
- * triggered. [quoted from p. 24, ADXL345 datasheet Rev. G]
- *
- * In a conclusion, the first acceleration snapshot sample which hit the
- * threshold in a particular direction is always taken as acceleration
- * reference value to that direction. Since for the hardware activity
- * and inactivity depend on the x/y/z axis, so do ac and dc coupling.
- * Note, this sw driver always enables or disables all three x/y/z axis
- * for detection via act_axis_ctrl and inact_axis_ctrl, respectively.
- * Where in dc-coupling samples are compared against the thresholds, in
- * ac-coupling measurement difference to the first acceleration
- * reference value are compared against the threshold. So, ac-coupling
- * allows for a bit more dynamic compensation depending on the initial
- * sample.
- */
- return regmap_assign_bits(st->regmap, ADXL345_REG_ACT_INACT_CTRL,
- adxl345_act_acdc_msk[type], act_inact_ac);
- }
- static int adxl345_is_act_inact_en(struct adxl345_state *st,
- enum adxl345_activity_type type)
- {
- unsigned int axis_ctrl;
- unsigned int regval;
- bool int_en, en;
- int ret;
- ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, &axis_ctrl);
- if (ret)
- return ret;
- /* Check if axis for activity are enabled */
- switch (type) {
- case ADXL345_ACTIVITY:
- case ADXL345_ACTIVITY_AC:
- en = FIELD_GET(ADXL345_ACT_XYZ_EN, axis_ctrl);
- if (!en)
- return false;
- break;
- case ADXL345_INACTIVITY:
- case ADXL345_INACTIVITY_AC:
- en = FIELD_GET(ADXL345_INACT_XYZ_EN, axis_ctrl);
- if (!en)
- return false;
- break;
- case ADXL345_INACTIVITY_FF:
- en = true;
- break;
- default:
- return -EINVAL;
- }
- /* Check if specific interrupt is enabled */
- ret = regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val);
- if (ret)
- return ret;
- int_en = adxl345_act_int_reg[type] & regval;
- if (!int_en)
- return false;
- /* Check if configured coupling matches provided type */
- return adxl345_is_act_inact_ac(st, type);
- }
- static int adxl345_set_act_inact_linkbit(struct adxl345_state *st,
- enum adxl345_activity_type type,
- bool en)
- {
- int act_ac_en, inact_ac_en;
- int act_en, inact_en;
- act_en = adxl345_is_act_inact_en(st, ADXL345_ACTIVITY);
- if (act_en < 0)
- return act_en;
- act_ac_en = adxl345_is_act_inact_en(st, ADXL345_ACTIVITY_AC);
- if (act_ac_en < 0)
- return act_ac_en;
- if (type == ADXL345_INACTIVITY_FF) {
- inact_en = false;
- } else {
- inact_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY);
- if (inact_en < 0)
- return inact_en;
- inact_ac_en = adxl345_is_act_inact_en(st, ADXL345_INACTIVITY_AC);
- if (inact_ac_en < 0)
- return inact_ac_en;
- inact_en = inact_en || inact_ac_en;
- }
- act_en = act_en || act_ac_en;
- return regmap_assign_bits(st->regmap, ADXL345_REG_POWER_CTL,
- ADXL345_POWER_CTL_INACT_MSK,
- en && act_en && inact_en);
- }
- static int adxl345_set_act_inact_en(struct adxl345_state *st,
- enum adxl345_activity_type type,
- bool cmd_en)
- {
- unsigned int axis_ctrl;
- unsigned int threshold;
- unsigned int period;
- int ret;
- if (cmd_en) {
- /* When turning on, check if threshold is valid */
- if (type == ADXL345_ACTIVITY || type == ADXL345_ACTIVITY_AC) {
- ret = regmap_read(st->regmap,
- adxl345_act_thresh_reg[type],
- &threshold);
- if (ret)
- return ret;
- } else {
- threshold = st->inact_threshold;
- }
- if (!threshold) /* Just ignore the command if threshold is 0 */
- return 0;
- /* When turning on inactivity, check if inact time is valid */
- if (type == ADXL345_INACTIVITY || type == ADXL345_INACTIVITY_AC) {
- ret = regmap_read(st->regmap,
- ADXL345_REG_TIME_INACT,
- &period);
- if (ret)
- return ret;
- if (!period)
- return 0;
- }
- } else {
- /*
- * When turning off an activity, ensure that the correct
- * coupling event is specified. This step helps prevent misuse -
- * for example, if an AC-coupled activity is active and the
- * current call attempts to turn off a DC-coupled activity, this
- * inconsistency should be detected here.
- */
- if (adxl345_is_act_inact_ac(st, type) <= 0)
- return 0;
- }
- /* Start modifying configuration registers */
- ret = adxl345_set_measure_en(st, false);
- if (ret)
- return ret;
- /* Enable axis according to the command */
- switch (type) {
- case ADXL345_ACTIVITY:
- case ADXL345_ACTIVITY_AC:
- axis_ctrl = ADXL345_ACT_XYZ_EN;
- break;
- case ADXL345_INACTIVITY:
- case ADXL345_INACTIVITY_AC:
- axis_ctrl = ADXL345_INACT_XYZ_EN;
- break;
- case ADXL345_INACTIVITY_FF:
- axis_ctrl = ADXL345_ACT_INACT_NO_AXIS_EN;
- break;
- default:
- return -EINVAL;
- }
- ret = regmap_assign_bits(st->regmap, ADXL345_REG_ACT_INACT_CTRL,
- axis_ctrl, cmd_en);
- if (ret)
- return ret;
- /* Update AC/DC-coupling according to the command */
- ret = adxl345_set_act_inact_ac(st, type, cmd_en);
- if (ret)
- return ret;
- /* Enable the interrupt line, according to the command */
- ret = regmap_assign_bits(st->regmap, ADXL345_REG_INT_ENABLE,
- adxl345_act_int_reg[type], cmd_en);
- if (ret)
- return ret;
- /* Set link-bit and auto-sleep only when ACT and INACT are enabled */
- ret = adxl345_set_act_inact_linkbit(st, type, cmd_en);
- if (ret)
- return ret;
- return adxl345_set_measure_en(st, true);
- }
- /* tap */
- static int _adxl345_set_tap_int(struct adxl345_state *st,
- enum adxl345_tap_type type, bool state)
- {
- unsigned int int_map = 0x00;
- unsigned int tap_threshold;
- bool axis_valid;
- bool singletap_args_valid = false;
- bool doubletap_args_valid = false;
- bool en = false;
- u32 axis_ctrl;
- int ret;
- ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl);
- if (ret)
- return ret;
- axis_valid = FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl) > 0;
- ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP, &tap_threshold);
- if (ret)
- return ret;
- /*
- * Note: A value of 0 for threshold and/or dur may result in undesirable
- * behavior if single tap/double tap interrupts are enabled.
- */
- singletap_args_valid = tap_threshold > 0 && st->tap_duration_us > 0;
- if (type == ADXL345_SINGLE_TAP) {
- en = axis_valid && singletap_args_valid;
- } else {
- /* doubletap: Window must be equal or greater than latent! */
- doubletap_args_valid = st->tap_latent_us > 0 &&
- st->tap_window_us > 0 &&
- st->tap_window_us >= st->tap_latent_us;
- en = axis_valid && singletap_args_valid && doubletap_args_valid;
- }
- if (state && en)
- int_map |= adxl345_tap_int_reg[type];
- return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE,
- adxl345_tap_int_reg[type], int_map);
- }
- static int adxl345_is_tap_en(struct adxl345_state *st,
- enum iio_modifier axis,
- enum adxl345_tap_type type, bool *en)
- {
- unsigned int regval;
- u32 axis_ctrl;
- int ret;
- ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl);
- if (ret)
- return ret;
- /* Verify if axis is enabled for the tap detection. */
- switch (axis) {
- case IIO_MOD_X:
- *en = FIELD_GET(ADXL345_TAP_X_EN, axis_ctrl);
- break;
- case IIO_MOD_Y:
- *en = FIELD_GET(ADXL345_TAP_Y_EN, axis_ctrl);
- break;
- case IIO_MOD_Z:
- *en = FIELD_GET(ADXL345_TAP_Z_EN, axis_ctrl);
- break;
- default:
- *en = false;
- return -EINVAL;
- }
- if (*en) {
- /*
- * If axis allow for tap detection, verify if the interrupt is
- * enabled for tap detection.
- */
- ret = regmap_read(st->regmap, ADXL345_REG_INT_ENABLE, ®val);
- if (ret)
- return ret;
- *en = adxl345_tap_int_reg[type] & regval;
- }
- return 0;
- }
- static int adxl345_set_singletap_en(struct adxl345_state *st,
- enum iio_modifier axis, bool en)
- {
- int ret;
- u32 axis_ctrl;
- switch (axis) {
- case IIO_MOD_X:
- axis_ctrl = ADXL345_TAP_X_EN;
- break;
- case IIO_MOD_Y:
- axis_ctrl = ADXL345_TAP_Y_EN;
- break;
- case IIO_MOD_Z:
- axis_ctrl = ADXL345_TAP_Z_EN;
- break;
- default:
- return -EINVAL;
- }
- if (en)
- ret = regmap_set_bits(st->regmap, ADXL345_REG_TAP_AXIS,
- axis_ctrl);
- else
- ret = regmap_clear_bits(st->regmap, ADXL345_REG_TAP_AXIS,
- axis_ctrl);
- if (ret)
- return ret;
- return _adxl345_set_tap_int(st, ADXL345_SINGLE_TAP, en);
- }
- static int adxl345_set_doubletap_en(struct adxl345_state *st, bool en)
- {
- int ret;
- /*
- * Generally suppress detection of spikes during the latency period as
- * double taps here, this is fully optional for double tap detection
- */
- ret = regmap_assign_bits(st->regmap, ADXL345_REG_TAP_AXIS,
- ADXL345_REG_TAP_SUPPRESS, en);
- if (ret)
- return ret;
- return _adxl345_set_tap_int(st, ADXL345_DOUBLE_TAP, en);
- }
- static int _adxl345_set_tap_time(struct adxl345_state *st,
- enum adxl345_tap_time_type type, u32 val_us)
- {
- unsigned int regval;
- switch (type) {
- case ADXL345_TAP_TIME_WINDOW:
- st->tap_window_us = val_us;
- break;
- case ADXL345_TAP_TIME_LATENT:
- st->tap_latent_us = val_us;
- break;
- case ADXL345_TAP_TIME_DUR:
- st->tap_duration_us = val_us;
- break;
- }
- /*
- * The scale factor is 1250us / LSB for tap_window_us and tap_latent_us.
- * For tap_duration_us the scale factor is 625us / LSB.
- */
- if (type == ADXL345_TAP_TIME_DUR)
- regval = DIV_ROUND_CLOSEST(val_us, 625);
- else
- regval = DIV_ROUND_CLOSEST(val_us, 1250);
- return regmap_write(st->regmap, adxl345_tap_time_reg[type], regval);
- }
- static int adxl345_set_tap_duration(struct adxl345_state *st, u32 val_int,
- u32 val_fract_us)
- {
- /*
- * Max value is 255 * 625 us = 0.159375 seconds
- *
- * Note: the scaling is similar to the scaling in the ADXL380
- */
- if (val_int || val_fract_us > 159375)
- return -EINVAL;
- return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_DUR, val_fract_us);
- }
- static int adxl345_set_tap_window(struct adxl345_state *st, u32 val_int,
- u32 val_fract_us)
- {
- /*
- * Max value is 255 * 1250 us = 0.318750 seconds
- *
- * Note: the scaling is similar to the scaling in the ADXL380
- */
- if (val_int || val_fract_us > 318750)
- return -EINVAL;
- return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_WINDOW, val_fract_us);
- }
- static int adxl345_set_tap_latent(struct adxl345_state *st, u32 val_int,
- u32 val_fract_us)
- {
- /*
- * Max value is 255 * 1250 us = 0.318750 seconds
- *
- * Note: the scaling is similar to the scaling in the ADXL380
- */
- if (val_int || val_fract_us > 318750)
- return -EINVAL;
- return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us);
- }
- static int adxl345_find_odr(struct adxl345_state *st, int val,
- int val2, enum adxl345_odr *odr)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(adxl345_odr_tbl); i++) {
- if (val == adxl345_odr_tbl[i][0] &&
- val2 == adxl345_odr_tbl[i][1]) {
- *odr = i;
- return 0;
- }
- }
- return -EINVAL;
- }
- static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr)
- {
- int ret;
- ret = regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE,
- ADXL345_BW_RATE_MSK,
- FIELD_PREP(ADXL345_BW_RATE_MSK, odr));
- if (ret)
- return ret;
- /* update inactivity time by ODR */
- return adxl345_set_inact_time(st, 0, 0);
- }
- static int adxl345_find_range(struct adxl345_state *st, int val, int val2,
- enum adxl345_range *range)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(adxl345_fullres_range_tbl); i++) {
- if (val == adxl345_fullres_range_tbl[i][0] &&
- val2 == adxl345_fullres_range_tbl[i][1]) {
- *range = i;
- return 0;
- }
- }
- return -EINVAL;
- }
- static int adxl345_set_range(struct adxl345_state *st, enum adxl345_range range)
- {
- unsigned int act_threshold, inact_threshold;
- unsigned int range_old;
- unsigned int regval;
- int ret;
- ret = regmap_read(st->regmap, ADXL345_REG_DATA_FORMAT, ®val);
- if (ret)
- return ret;
- range_old = FIELD_GET(ADXL345_DATA_FORMAT_RANGE, regval);
- ret = regmap_read(st->regmap,
- adxl345_act_thresh_reg[ADXL345_ACTIVITY],
- &act_threshold);
- if (ret)
- return ret;
- ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT,
- ADXL345_DATA_FORMAT_RANGE,
- FIELD_PREP(ADXL345_DATA_FORMAT_RANGE, range));
- if (ret)
- return ret;
- act_threshold = act_threshold * adxl345_range_factor_tbl[range_old]
- / adxl345_range_factor_tbl[range];
- act_threshold = min(U8_MAX, max(1, act_threshold));
- inact_threshold = st->inact_threshold;
- inact_threshold = inact_threshold * adxl345_range_factor_tbl[range_old]
- / adxl345_range_factor_tbl[range];
- inact_threshold = min(U8_MAX, max(1, inact_threshold));
- ret = regmap_write(st->regmap, adxl345_act_thresh_reg[ADXL345_ACTIVITY],
- act_threshold);
- if (ret)
- return ret;
- return adxl345_set_inact_threshold(st, inact_threshold);
- }
- static int adxl345_read_avail(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- const int **vals, int *type,
- int *length, long mask)
- {
- switch (mask) {
- case IIO_CHAN_INFO_SCALE:
- *vals = (int *)adxl345_fullres_range_tbl;
- *type = IIO_VAL_INT_PLUS_MICRO;
- *length = ARRAY_SIZE(adxl345_fullres_range_tbl) * 2;
- return IIO_AVAIL_LIST;
- case IIO_CHAN_INFO_SAMP_FREQ:
- *vals = (int *)adxl345_odr_tbl;
- *type = IIO_VAL_INT_PLUS_MICRO;
- *length = ARRAY_SIZE(adxl345_odr_tbl) * 2;
- return IIO_AVAIL_LIST;
- }
- return -EINVAL;
- }
- static int adxl345_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- __le16 accel;
- unsigned int regval;
- enum adxl345_odr odr;
- enum adxl345_range range;
- int ret;
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- /*
- * Data is stored in adjacent registers:
- * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte
- * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte
- */
- ret = regmap_bulk_read(st->regmap,
- ADXL345_REG_DATA_AXIS(chan->address),
- &accel, sizeof(accel));
- if (ret)
- return ret;
- *val = sign_extend32(le16_to_cpu(accel), 12);
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_SCALE:
- ret = regmap_read(st->regmap, ADXL345_REG_DATA_FORMAT, ®val);
- if (ret)
- return ret;
- range = FIELD_GET(ADXL345_DATA_FORMAT_RANGE, regval);
- *val = adxl345_fullres_range_tbl[range][0];
- *val2 = adxl345_fullres_range_tbl[range][1];
- return IIO_VAL_INT_PLUS_MICRO;
- case IIO_CHAN_INFO_CALIBBIAS:
- ret = regmap_read(st->regmap,
- ADXL345_REG_OFS_AXIS(chan->address), ®val);
- if (ret)
- return ret;
- /*
- * 8-bit resolution at +/- 2g, that is 4x accel data scale
- * factor
- */
- *val = sign_extend32(regval, 7) * 4;
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_SAMP_FREQ:
- ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, ®val);
- if (ret)
- return ret;
- odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
- *val = adxl345_odr_tbl[odr][0];
- *val2 = adxl345_odr_tbl[odr][1];
- return IIO_VAL_INT_PLUS_MICRO;
- }
- return -EINVAL;
- }
- static int adxl345_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- enum adxl345_range range;
- enum adxl345_odr odr;
- int ret;
- ret = adxl345_set_measure_en(st, false);
- if (ret)
- return ret;
- switch (mask) {
- case IIO_CHAN_INFO_CALIBBIAS:
- /*
- * 8-bit resolution at +/- 2g, that is 4x accel data scale
- * factor
- */
- ret = regmap_write(st->regmap,
- ADXL345_REG_OFS_AXIS(chan->address),
- val / 4);
- if (ret)
- return ret;
- break;
- case IIO_CHAN_INFO_SAMP_FREQ:
- ret = adxl345_find_odr(st, val, val2, &odr);
- if (ret)
- return ret;
- ret = adxl345_set_odr(st, odr);
- if (ret)
- return ret;
- break;
- case IIO_CHAN_INFO_SCALE:
- ret = adxl345_find_range(st, val, val2, &range);
- if (ret)
- return ret;
- ret = adxl345_set_range(st, range);
- if (ret)
- return ret;
- break;
- default:
- return -EINVAL;
- }
- return adxl345_set_measure_en(st, true);
- }
- static int adxl345_read_mag_config(struct adxl345_state *st,
- enum iio_event_direction dir,
- enum adxl345_activity_type type_act,
- enum adxl345_activity_type type_inact)
- {
- switch (dir) {
- case IIO_EV_DIR_RISING:
- return !!adxl345_is_act_inact_en(st, type_act);
- case IIO_EV_DIR_FALLING:
- return !!adxl345_is_act_inact_en(st, type_inact);
- default:
- return -EINVAL;
- }
- }
- static int adxl345_write_mag_config(struct adxl345_state *st,
- enum iio_event_direction dir,
- enum adxl345_activity_type type_act,
- enum adxl345_activity_type type_inact,
- bool state)
- {
- switch (dir) {
- case IIO_EV_DIR_RISING:
- return adxl345_set_act_inact_en(st, type_act, state);
- case IIO_EV_DIR_FALLING:
- return adxl345_set_act_inact_en(st, type_inact, state);
- default:
- return -EINVAL;
- }
- }
- static int adxl345_read_event_config(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
- enum iio_event_type type,
- enum iio_event_direction dir)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- bool int_en;
- int ret;
- switch (type) {
- case IIO_EV_TYPE_MAG:
- return adxl345_read_mag_config(st, dir,
- ADXL345_ACTIVITY,
- ADXL345_INACTIVITY);
- case IIO_EV_TYPE_MAG_ADAPTIVE:
- return adxl345_read_mag_config(st, dir,
- ADXL345_ACTIVITY_AC,
- ADXL345_INACTIVITY_AC);
- case IIO_EV_TYPE_GESTURE:
- switch (dir) {
- case IIO_EV_DIR_SINGLETAP:
- ret = adxl345_is_tap_en(st, chan->channel2,
- ADXL345_SINGLE_TAP, &int_en);
- if (ret)
- return ret;
- return int_en;
- case IIO_EV_DIR_DOUBLETAP:
- ret = adxl345_is_tap_en(st, chan->channel2,
- ADXL345_DOUBLE_TAP, &int_en);
- if (ret)
- return ret;
- return int_en;
- default:
- return -EINVAL;
- }
- default:
- return -EINVAL;
- }
- }
- static int adxl345_write_event_config(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
- enum iio_event_type type,
- enum iio_event_direction dir,
- bool state)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- switch (type) {
- case IIO_EV_TYPE_MAG:
- return adxl345_write_mag_config(st, dir,
- ADXL345_ACTIVITY,
- ADXL345_INACTIVITY,
- state);
- case IIO_EV_TYPE_MAG_ADAPTIVE:
- return adxl345_write_mag_config(st, dir,
- ADXL345_ACTIVITY_AC,
- ADXL345_INACTIVITY_AC,
- state);
- case IIO_EV_TYPE_GESTURE:
- switch (dir) {
- case IIO_EV_DIR_SINGLETAP:
- return adxl345_set_singletap_en(st, chan->channel2, state);
- case IIO_EV_DIR_DOUBLETAP:
- return adxl345_set_doubletap_en(st, state);
- default:
- return -EINVAL;
- }
- default:
- return -EINVAL;
- }
- }
- static int adxl345_read_mag_value(struct adxl345_state *st,
- enum iio_event_direction dir,
- enum iio_event_info info,
- enum adxl345_activity_type type_act,
- enum adxl345_activity_type type_inact,
- int *val, int *val2)
- {
- unsigned int threshold;
- int ret;
- switch (info) {
- case IIO_EV_INFO_VALUE:
- switch (dir) {
- case IIO_EV_DIR_RISING:
- ret = regmap_read(st->regmap,
- adxl345_act_thresh_reg[type_act],
- &threshold);
- if (ret)
- return ret;
- *val = 62500 * threshold;
- *val2 = MICRO;
- return IIO_VAL_FRACTIONAL;
- case IIO_EV_DIR_FALLING:
- *val = 62500 * st->inact_threshold;
- *val2 = MICRO;
- return IIO_VAL_FRACTIONAL;
- default:
- return -EINVAL;
- }
- case IIO_EV_INFO_PERIOD:
- *val = st->inact_time_ms;
- *val2 = MILLI;
- return IIO_VAL_FRACTIONAL;
- default:
- return -EINVAL;
- }
- }
- static int adxl345_write_mag_value(struct adxl345_state *st,
- enum iio_event_direction dir,
- enum iio_event_info info,
- enum adxl345_activity_type type_act,
- enum adxl345_activity_type type_inact,
- int val, int val2)
- {
- switch (info) {
- case IIO_EV_INFO_VALUE:
- /* Scaling factor 62.5mg/LSB, i.e. ~16g corresponds to 0xff */
- val = DIV_ROUND_CLOSEST(val * MICRO + val2, 62500);
- switch (dir) {
- case IIO_EV_DIR_RISING:
- return regmap_write(st->regmap,
- adxl345_act_thresh_reg[type_act],
- val);
- case IIO_EV_DIR_FALLING:
- return adxl345_set_inact_threshold(st, val);
- default:
- return -EINVAL;
- }
- case IIO_EV_INFO_PERIOD:
- return adxl345_set_inact_time(st, val, val2);
- default:
- return -EINVAL;
- }
- }
- static int adxl345_read_event_value(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
- enum iio_event_type type,
- enum iio_event_direction dir,
- enum iio_event_info info,
- int *val, int *val2)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- unsigned int tap_threshold;
- int ret;
- switch (type) {
- case IIO_EV_TYPE_MAG:
- return adxl345_read_mag_value(st, dir, info,
- ADXL345_ACTIVITY,
- ADXL345_INACTIVITY,
- val, val2);
- case IIO_EV_TYPE_MAG_ADAPTIVE:
- return adxl345_read_mag_value(st, dir, info,
- ADXL345_ACTIVITY_AC,
- ADXL345_INACTIVITY_AC,
- val, val2);
- case IIO_EV_TYPE_GESTURE:
- switch (info) {
- case IIO_EV_INFO_VALUE:
- /*
- * The scale factor would be 62.5mg/LSB (i.e. 0xFF = 16g) but
- * not applied here. In context of this general purpose sensor,
- * what imports is rather signal intensity than the absolute
- * measured g value.
- */
- ret = regmap_read(st->regmap, ADXL345_REG_THRESH_TAP,
- &tap_threshold);
- if (ret)
- return ret;
- *val = sign_extend32(tap_threshold, 7);
- return IIO_VAL_INT;
- case IIO_EV_INFO_TIMEOUT:
- *val = st->tap_duration_us;
- *val2 = MICRO;
- return IIO_VAL_FRACTIONAL;
- case IIO_EV_INFO_RESET_TIMEOUT:
- *val = st->tap_window_us;
- *val2 = MICRO;
- return IIO_VAL_FRACTIONAL;
- case IIO_EV_INFO_TAP2_MIN_DELAY:
- *val = st->tap_latent_us;
- *val2 = MICRO;
- return IIO_VAL_FRACTIONAL;
- default:
- return -EINVAL;
- }
- default:
- return -EINVAL;
- }
- }
- static int adxl345_write_event_value(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
- enum iio_event_type type,
- enum iio_event_direction dir,
- enum iio_event_info info,
- int val, int val2)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- int ret;
- ret = adxl345_set_measure_en(st, false);
- if (ret)
- return ret;
- switch (type) {
- case IIO_EV_TYPE_MAG:
- ret = adxl345_write_mag_value(st, dir, info,
- ADXL345_ACTIVITY,
- ADXL345_INACTIVITY,
- val, val2);
- if (ret)
- return ret;
- break;
- case IIO_EV_TYPE_MAG_ADAPTIVE:
- ret = adxl345_write_mag_value(st, dir, info,
- ADXL345_ACTIVITY_AC,
- ADXL345_INACTIVITY_AC,
- val, val2);
- if (ret)
- return ret;
- break;
- case IIO_EV_TYPE_GESTURE:
- switch (info) {
- case IIO_EV_INFO_VALUE:
- ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP,
- min(val, 0xFF));
- if (ret)
- return ret;
- break;
- case IIO_EV_INFO_TIMEOUT:
- ret = adxl345_set_tap_duration(st, val, val2);
- if (ret)
- return ret;
- break;
- case IIO_EV_INFO_RESET_TIMEOUT:
- ret = adxl345_set_tap_window(st, val, val2);
- if (ret)
- return ret;
- break;
- case IIO_EV_INFO_TAP2_MIN_DELAY:
- ret = adxl345_set_tap_latent(st, val, val2);
- if (ret)
- return ret;
- break;
- default:
- return -EINVAL;
- }
- break;
- default:
- return -EINVAL;
- }
- return adxl345_set_measure_en(st, true);
- }
- static int adxl345_reg_access(struct iio_dev *indio_dev, unsigned int reg,
- unsigned int writeval, unsigned int *readval)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- if (readval)
- return regmap_read(st->regmap, reg, readval);
- return regmap_write(st->regmap, reg, writeval);
- }
- static int adxl345_set_watermark(struct iio_dev *indio_dev, unsigned int value)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- const unsigned int fifo_mask = 0x1F, watermark_mask = 0x02;
- int ret;
- value = min(value, ADXL345_FIFO_SIZE - 1);
- ret = regmap_update_bits(st->regmap, ADXL345_REG_FIFO_CTL, fifo_mask, value);
- if (ret)
- return ret;
- st->watermark = value;
- return regmap_update_bits(st->regmap, ADXL345_REG_INT_ENABLE,
- watermark_mask, ADXL345_INT_WATERMARK);
- }
- static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- long mask)
- {
- switch (mask) {
- case IIO_CHAN_INFO_CALIBBIAS:
- return IIO_VAL_INT;
- case IIO_CHAN_INFO_SCALE:
- return IIO_VAL_INT_PLUS_MICRO;
- case IIO_CHAN_INFO_SAMP_FREQ:
- return IIO_VAL_INT_PLUS_MICRO;
- default:
- return -EINVAL;
- }
- }
- static void adxl345_powerdown(void *ptr)
- {
- struct adxl345_state *st = ptr;
- adxl345_set_measure_en(st, false);
- }
- static int adxl345_set_fifo(struct adxl345_state *st)
- {
- unsigned int intio;
- int ret;
- /* FIFO should only be configured while in standby mode */
- ret = adxl345_set_measure_en(st, false);
- if (ret)
- return ret;
- ret = regmap_read(st->regmap, ADXL345_REG_INT_MAP, &intio);
- if (ret)
- return ret;
- ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL,
- FIELD_PREP(ADXL345_FIFO_CTL_SAMPLES_MSK,
- st->watermark) |
- FIELD_PREP(ADXL345_FIFO_CTL_TRIGGER_MSK, intio) |
- FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK,
- st->fifo_mode));
- if (ret)
- return ret;
- return adxl345_set_measure_en(st, true);
- }
- /**
- * adxl345_get_samples() - Read number of FIFO entries.
- * @st: The initialized state instance of this driver.
- *
- * The sensor does not support treating any axis individually, or exclude them
- * from measuring.
- *
- * Return: negative error, or value.
- */
- static int adxl345_get_samples(struct adxl345_state *st)
- {
- unsigned int regval = 0;
- int ret;
- ret = regmap_read(st->regmap, ADXL345_REG_FIFO_STATUS, ®val);
- if (ret)
- return ret;
- return FIELD_GET(ADXL345_REG_FIFO_STATUS_MSK, regval);
- }
- /**
- * adxl345_fifo_transfer() - Read samples number of elements.
- * @st: The instance of the state object of this sensor.
- * @samples: The number of lines in the FIFO referred to as fifo_entry.
- *
- * It is recommended that a multiple-byte read of all registers be performed to
- * prevent a change in data between reads of sequential registers. That is to
- * read out the data registers X0, X1, Y0, Y1, Z0, Z1, i.e. 6 bytes at once.
- *
- * Return: 0 or error value.
- */
- static int adxl345_fifo_transfer(struct adxl345_state *st, int samples)
- {
- int i, ret = 0;
- for (i = 0; i < samples; i++) {
- ret = regmap_bulk_read(st->regmap, ADXL345_REG_XYZ_BASE,
- st->fifo_buf + (i * ADXL345_DIRS),
- sizeof(st->fifo_buf[0]) * ADXL345_DIRS);
- if (ret)
- return ret;
- /*
- * To ensure that the FIFO has completely popped, there must be at least 5
- * us between the end of reading the data registers, signified by the
- * transition to register 0x38 from 0x37 or the CS pin going high, and the
- * start of new reads of the FIFO or reading the FIFO_STATUS register. For
- * SPI operation at 1.5 MHz or lower, the register addressing portion of the
- * transmission is sufficient delay to ensure the FIFO has completely
- * popped. It is necessary for SPI operation greater than 1.5 MHz to
- * de-assert the CS pin to ensure a total of 5 us, which is at most 3.4 us
- * at 5 MHz operation.
- */
- if (st->fifo_delay && samples > 1)
- udelay(3);
- }
- return ret;
- }
- /**
- * adxl345_fifo_reset() - Empty the FIFO in error condition.
- * @st: The instance to the state object of the sensor.
- *
- * Read all elements of the FIFO. Reading the interrupt source register
- * resets the sensor.
- */
- static void adxl345_fifo_reset(struct adxl345_state *st)
- {
- int regval;
- int samples;
- adxl345_set_measure_en(st, false);
- samples = adxl345_get_samples(st);
- if (samples > 0)
- adxl345_fifo_transfer(st, samples);
- regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, ®val);
- adxl345_set_measure_en(st, true);
- }
- static int adxl345_buffer_postenable(struct iio_dev *indio_dev)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- st->fifo_mode = ADXL345_FIFO_STREAM;
- return adxl345_set_fifo(st);
- }
- static int adxl345_buffer_predisable(struct iio_dev *indio_dev)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- int ret;
- st->fifo_mode = ADXL345_FIFO_BYPASS;
- ret = adxl345_set_fifo(st);
- if (ret)
- return ret;
- return regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00);
- }
- static const struct iio_buffer_setup_ops adxl345_buffer_ops = {
- .postenable = adxl345_buffer_postenable,
- .predisable = adxl345_buffer_predisable,
- };
- static int adxl345_fifo_push(struct iio_dev *indio_dev,
- int samples)
- {
- struct adxl345_state *st = iio_priv(indio_dev);
- int i, ret;
- if (samples <= 0)
- return -EINVAL;
- ret = adxl345_fifo_transfer(st, samples);
- if (ret)
- return ret;
- for (i = 0; i < ADXL345_DIRS * samples; i += ADXL345_DIRS)
- iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
- return 0;
- }
- static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat,
- enum iio_modifier act_dir,
- enum iio_modifier tap_dir)
- {
- s64 ts = iio_get_time_ns(indio_dev);
- struct adxl345_state *st = iio_priv(indio_dev);
- unsigned int regval;
- int samples;
- int ret = -ENOENT;
- if (FIELD_GET(ADXL345_INT_SINGLE_TAP, int_stat)) {
- ret = iio_push_event(indio_dev,
- IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir,
- IIO_EV_TYPE_GESTURE,
- IIO_EV_DIR_SINGLETAP),
- ts);
- if (ret)
- return ret;
- }
- if (FIELD_GET(ADXL345_INT_DOUBLE_TAP, int_stat)) {
- ret = iio_push_event(indio_dev,
- IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, tap_dir,
- IIO_EV_TYPE_GESTURE,
- IIO_EV_DIR_DOUBLETAP),
- ts);
- if (ret)
- return ret;
- }
- if (FIELD_GET(ADXL345_INT_ACTIVITY, int_stat)) {
- ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val);
- if (ret)
- return ret;
- if (FIELD_GET(ADXL345_REG_ACT_ACDC, regval)) {
- /* AC coupled */
- ret = iio_push_event(indio_dev,
- IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir,
- IIO_EV_TYPE_MAG_ADAPTIVE,
- IIO_EV_DIR_RISING),
- ts);
- } else {
- /* DC coupled, relying on THRESH */
- ret = iio_push_event(indio_dev,
- IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, act_dir,
- IIO_EV_TYPE_MAG,
- IIO_EV_DIR_RISING),
- ts);
- }
- if (ret)
- return ret;
- }
- if (FIELD_GET(ADXL345_INT_INACTIVITY, int_stat)) {
- ret = regmap_read(st->regmap, ADXL345_REG_ACT_INACT_CTRL, ®val);
- if (ret)
- return ret;
- if (FIELD_GET(ADXL345_REG_INACT_ACDC, regval)) {
- /* AC coupled */
- ret = iio_push_event(indio_dev,
- IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
- IIO_MOD_X_AND_Y_AND_Z,
- IIO_EV_TYPE_MAG_ADAPTIVE,
- IIO_EV_DIR_FALLING),
- ts);
- } else {
- /* DC coupled, relying on THRESH */
- ret = iio_push_event(indio_dev,
- IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
- IIO_MOD_X_AND_Y_AND_Z,
- IIO_EV_TYPE_MAG,
- IIO_EV_DIR_FALLING),
- ts);
- }
- if (ret)
- return ret;
- }
- if (FIELD_GET(ADXL345_INT_FREE_FALL, int_stat)) {
- ret = iio_push_event(indio_dev,
- IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
- IIO_MOD_X_AND_Y_AND_Z,
- IIO_EV_TYPE_MAG,
- IIO_EV_DIR_FALLING),
- ts);
- if (ret)
- return ret;
- }
- if (FIELD_GET(ADXL345_INT_WATERMARK, int_stat)) {
- samples = adxl345_get_samples(st);
- if (samples < 0)
- return -EINVAL;
- if (adxl345_fifo_push(indio_dev, samples) < 0)
- return -EINVAL;
- ret = 0;
- }
- return ret;
- }
- /**
- * adxl345_irq_handler() - Handle irqs of the ADXL345.
- * @irq: The irq being handled.
- * @p: The struct iio_device pointer for the device.
- *
- * Return: The interrupt was handled.
- */
- static irqreturn_t adxl345_irq_handler(int irq, void *p)
- {
- struct iio_dev *indio_dev = p;
- struct adxl345_state *st = iio_priv(indio_dev);
- unsigned int regval;
- enum iio_modifier tap_dir = IIO_NO_MOD;
- enum iio_modifier act_dir = IIO_NO_MOD;
- u32 axis_ctrl;
- int int_stat;
- int ret;
- ret = regmap_read(st->regmap, ADXL345_REG_TAP_AXIS, &axis_ctrl);
- if (ret)
- return IRQ_NONE;
- if (FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, axis_ctrl) ||
- FIELD_GET(ADXL345_ACT_XYZ_EN, axis_ctrl)) {
- ret = regmap_read(st->regmap, ADXL345_REG_ACT_TAP_STATUS, ®val);
- if (ret)
- return IRQ_NONE;
- if (FIELD_GET(ADXL345_TAP_Z_EN, regval))
- tap_dir = IIO_MOD_Z;
- else if (FIELD_GET(ADXL345_TAP_Y_EN, regval))
- tap_dir = IIO_MOD_Y;
- else if (FIELD_GET(ADXL345_TAP_X_EN, regval))
- tap_dir = IIO_MOD_X;
- if (FIELD_GET(ADXL345_ACT_Z_EN, regval))
- act_dir = IIO_MOD_Z;
- else if (FIELD_GET(ADXL345_ACT_Y_EN, regval))
- act_dir = IIO_MOD_Y;
- else if (FIELD_GET(ADXL345_ACT_X_EN, regval))
- act_dir = IIO_MOD_X;
- }
- if (regmap_read(st->regmap, ADXL345_REG_INT_SOURCE, &int_stat))
- return IRQ_NONE;
- if (adxl345_push_event(indio_dev, int_stat, act_dir, tap_dir))
- goto err;
- if (FIELD_GET(ADXL345_INT_OVERRUN, int_stat))
- goto err;
- return IRQ_HANDLED;
- err:
- adxl345_fifo_reset(st);
- return IRQ_HANDLED;
- }
- static const struct iio_info adxl345_info = {
- .read_raw = adxl345_read_raw,
- .write_raw = adxl345_write_raw,
- .read_avail = adxl345_read_avail,
- .write_raw_get_fmt = adxl345_write_raw_get_fmt,
- .read_event_config = adxl345_read_event_config,
- .write_event_config = adxl345_write_event_config,
- .read_event_value = adxl345_read_event_value,
- .write_event_value = adxl345_write_event_value,
- .debugfs_reg_access = &adxl345_reg_access,
- .hwfifo_set_watermark = adxl345_set_watermark,
- };
- static int adxl345_get_int_line(struct device *dev, int *irq)
- {
- *irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1");
- if (*irq > 0)
- return ADXL345_INT1;
- *irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2");
- if (*irq > 0)
- return ADXL345_INT2;
- return ADXL345_INT_NONE;
- }
- /**
- * adxl345_core_probe() - Probe and setup for the accelerometer.
- * @dev: Driver model representation of the device
- * @regmap: Regmap instance for the device
- * @fifo_delay_default: Using FIFO with SPI needs delay
- * @setup: Setup routine to be executed right before the standard device
- * setup
- *
- * For SPI operation greater than 1.6 MHz, it is necessary to deassert the CS
- * pin to ensure a total delay of 5 us; otherwise, the delay is not sufficient.
- * The total delay necessary for 5 MHz operation is at most 3.4 us. This is not
- * a concern when using I2C mode because the communication rate is low enough
- * to ensure a sufficient delay between FIFO reads.
- * Ref: "Retrieving Data from FIFO", p. 21 of 36, Data Sheet ADXL345 Rev. G
- *
- * Return: 0 on success, negative errno on error
- */
- int adxl345_core_probe(struct device *dev, struct regmap *regmap,
- bool fifo_delay_default,
- int (*setup)(struct device*, struct regmap*))
- {
- struct adxl345_state *st;
- struct iio_dev *indio_dev;
- u32 regval;
- u8 intio = ADXL345_INT1;
- unsigned int data_format_mask = (ADXL345_DATA_FORMAT_RANGE |
- ADXL345_DATA_FORMAT_JUSTIFY |
- ADXL345_DATA_FORMAT_FULL_RES |
- ADXL345_DATA_FORMAT_SELF_TEST);
- unsigned int tap_threshold;
- int irq;
- int ret;
- indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
- if (!indio_dev)
- return -ENOMEM;
- st = iio_priv(indio_dev);
- st->regmap = regmap;
- st->info = device_get_match_data(dev);
- if (!st->info)
- return -ENODEV;
- st->fifo_delay = fifo_delay_default;
- /* Init with reasonable values */
- tap_threshold = 48; /* 48 [0x30] -> ~3g */
- st->tap_duration_us = 16; /* 16 [0x10] -> .010 */
- st->tap_window_us = 64; /* 64 [0x40] -> .080 */
- st->tap_latent_us = 16; /* 16 [0x10] -> .020 */
- indio_dev->name = st->info->name;
- indio_dev->info = &adxl345_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = adxl345_channels;
- indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
- indio_dev->available_scan_masks = adxl345_scan_masks;
- /*
- * Using I2C at 100kHz would limit the maximum ODR to 200Hz, operation
- * at an output rate above the recommended maximum may result in
- * undesired behavior.
- */
- ret = adxl345_set_odr(st, ADXL345_ODR_200HZ);
- if (ret)
- return ret;
- ret = adxl345_set_range(st, ADXL345_16G_RANGE);
- if (ret)
- return ret;
- /* Reset interrupts at start up */
- ret = regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00);
- if (ret)
- return ret;
- if (setup) {
- /* Perform optional initial bus specific configuration */
- ret = setup(dev, st->regmap);
- if (ret)
- return ret;
- /* Enable full-resolution mode */
- ret = regmap_update_bits(st->regmap, ADXL345_REG_DATA_FORMAT,
- data_format_mask,
- ADXL345_DATA_FORMAT_FULL_RES);
- if (ret)
- return dev_err_probe(dev, ret,
- "Failed to set data range\n");
- } else {
- /* Enable full-resolution mode (init all data_format bits) */
- ret = regmap_write(st->regmap, ADXL345_REG_DATA_FORMAT,
- ADXL345_DATA_FORMAT_FULL_RES);
- if (ret)
- return dev_err_probe(dev, ret,
- "Failed to set data range\n");
- }
- ret = regmap_read(st->regmap, ADXL345_REG_DEVID, ®val);
- if (ret)
- return dev_err_probe(dev, ret, "Error reading device ID\n");
- if (regval != ADXL345_DEVID)
- return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n",
- regval, ADXL345_DEVID);
- /* Enable measurement mode */
- ret = adxl345_set_measure_en(st, true);
- if (ret)
- return dev_err_probe(dev, ret, "Failed to enable measurement mode\n");
- ret = devm_add_action_or_reset(dev, adxl345_powerdown, st);
- if (ret)
- return ret;
- intio = adxl345_get_int_line(dev, &irq);
- if (intio != ADXL345_INT_NONE) {
- /*
- * In the INT map register, bits set to 0 route their
- * corresponding interrupts to the INT1 pin, while bits set to 1
- * route them to the INT2 pin. The intio should handle this
- * mapping accordingly.
- */
- ret = regmap_assign_bits(st->regmap, ADXL345_REG_INT_MAP,
- U8_MAX, intio);
- if (ret)
- return ret;
- /*
- * Initialized with sensible default values to streamline
- * sensor operation. These defaults are partly derived from
- * the previous input driver for the ADXL345 and partly
- * based on the recommendations provided in the datasheet.
- */
- ret = regmap_write(st->regmap, ADXL345_REG_ACT_INACT_CTRL, 0);
- if (ret)
- return ret;
- ret = regmap_write(st->regmap, ADXL345_REG_THRESH_ACT, 6);
- if (ret)
- return ret;
- ret = adxl345_set_inact_threshold(st, 4);
- if (ret)
- return ret;
- ret = regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, tap_threshold);
- if (ret)
- return ret;
- /* FIFO_STREAM mode is going to be activated later */
- ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, &adxl345_buffer_ops);
- if (ret)
- return ret;
- ret = devm_request_threaded_irq(dev, irq, NULL,
- &adxl345_irq_handler,
- IRQF_SHARED | IRQF_ONESHOT,
- indio_dev->name, indio_dev);
- if (ret)
- return ret;
- } else {
- ret = regmap_write(st->regmap, ADXL345_REG_FIFO_CTL,
- FIELD_PREP(ADXL345_FIFO_CTL_MODE_MSK,
- ADXL345_FIFO_BYPASS));
- if (ret)
- return ret;
- }
- return devm_iio_device_register(dev, indio_dev);
- }
- EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, "IIO_ADXL345");
- MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>");
- MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");
- MODULE_LICENSE("GPL v2");
|