1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Azoteq IQS624/625 Angular Position Sensors 4 * 5 * Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com> 6 */ 7 8 #include <linux/device.h> 9 #include <linux/iio/events.h> 10 #include <linux/iio/iio.h> 11 #include <linux/kernel.h> 12 #include <linux/mfd/iqs62x.h> 13 #include <linux/module.h> 14 #include <linux/mutex.h> 15 #include <linux/notifier.h> 16 #include <linux/platform_device.h> 17 #include <linux/regmap.h> 18 19 #define IQS624_POS_DEG_OUT 0x16 20 21 #define IQS624_POS_SCALE1 (314159 / 180) 22 #define IQS624_POS_SCALE2 100000 23 24 struct iqs624_pos_private { 25 struct iqs62x_core *iqs62x; 26 struct notifier_block notifier; 27 struct mutex lock; 28 bool angle_en; 29 u16 angle; 30 }; 31 32 static int iqs624_pos_angle_en(struct iqs62x_core *iqs62x, bool angle_en) 33 { 34 unsigned int event_mask = IQS624_HALL_UI_WHL_EVENT; 35 36 /* 37 * The IQS625 reports angular position in the form of coarse intervals, 38 * so only interval change events are unmasked. Conversely, the IQS624 39 * reports angular position down to one degree of resolution, so wheel 40 * movement events are unmasked instead. 41 */ 42 if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM) 43 event_mask = IQS624_HALL_UI_INT_EVENT; 44 45 return regmap_update_bits(iqs62x->regmap, IQS624_HALL_UI, event_mask, 46 angle_en ? 0 : 0xFF); 47 } 48 49 static int iqs624_pos_notifier(struct notifier_block *notifier, 50 unsigned long event_flags, void *context) 51 { 52 struct iqs62x_event_data *event_data = context; 53 struct iqs624_pos_private *iqs624_pos; 54 struct iqs62x_core *iqs62x; 55 struct iio_dev *indio_dev; 56 u16 angle = event_data->ui_data; 57 s64 timestamp; 58 int ret; 59 60 iqs624_pos = container_of(notifier, struct iqs624_pos_private, 61 notifier); 62 indio_dev = iio_priv_to_dev(iqs624_pos); 63 timestamp = iio_get_time_ns(indio_dev); 64 65 iqs62x = iqs624_pos->iqs62x; 66 if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM) 67 angle = event_data->interval; 68 69 mutex_lock(&iqs624_pos->lock); 70 71 if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) { 72 ret = iqs624_pos_angle_en(iqs62x, iqs624_pos->angle_en); 73 if (ret) { 74 dev_err(indio_dev->dev.parent, 75 "Failed to re-initialize device: %d\n", ret); 76 ret = NOTIFY_BAD; 77 } else { 78 ret = NOTIFY_OK; 79 } 80 } else if (iqs624_pos->angle_en && (angle != iqs624_pos->angle)) { 81 iio_push_event(indio_dev, 82 IIO_UNMOD_EVENT_CODE(IIO_ANGL, 0, 83 IIO_EV_TYPE_CHANGE, 84 IIO_EV_DIR_NONE), 85 timestamp); 86 87 iqs624_pos->angle = angle; 88 ret = NOTIFY_OK; 89 } else { 90 ret = NOTIFY_DONE; 91 } 92 93 mutex_unlock(&iqs624_pos->lock); 94 95 return ret; 96 } 97 98 static void iqs624_pos_notifier_unregister(void *context) 99 { 100 struct iqs624_pos_private *iqs624_pos = context; 101 struct iio_dev *indio_dev = iio_priv_to_dev(iqs624_pos); 102 int ret; 103 104 ret = blocking_notifier_chain_unregister(&iqs624_pos->iqs62x->nh, 105 &iqs624_pos->notifier); 106 if (ret) 107 dev_err(indio_dev->dev.parent, 108 "Failed to unregister notifier: %d\n", ret); 109 } 110 111 static int iqs624_pos_angle_get(struct iqs62x_core *iqs62x, unsigned int *val) 112 { 113 int ret; 114 __le16 val_buf; 115 116 if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM) 117 return regmap_read(iqs62x->regmap, iqs62x->dev_desc->interval, 118 val); 119 120 ret = regmap_raw_read(iqs62x->regmap, IQS624_POS_DEG_OUT, &val_buf, 121 sizeof(val_buf)); 122 if (ret) 123 return ret; 124 125 *val = le16_to_cpu(val_buf); 126 127 return 0; 128 } 129 130 static int iqs624_pos_read_raw(struct iio_dev *indio_dev, 131 struct iio_chan_spec const *chan, 132 int *val, int *val2, long mask) 133 { 134 struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev); 135 struct iqs62x_core *iqs62x = iqs624_pos->iqs62x; 136 unsigned int scale = 1; 137 int ret; 138 139 switch (mask) { 140 case IIO_CHAN_INFO_RAW: 141 ret = iqs624_pos_angle_get(iqs62x, val); 142 if (ret) 143 return ret; 144 145 return IIO_VAL_INT; 146 147 case IIO_CHAN_INFO_SCALE: 148 if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM) { 149 ret = regmap_read(iqs62x->regmap, IQS624_INTERVAL_DIV, 150 &scale); 151 if (ret) 152 return ret; 153 } 154 155 *val = scale * IQS624_POS_SCALE1; 156 *val2 = IQS624_POS_SCALE2; 157 return IIO_VAL_FRACTIONAL; 158 159 default: 160 return -EINVAL; 161 } 162 } 163 164 static int iqs624_pos_read_event_config(struct iio_dev *indio_dev, 165 const struct iio_chan_spec *chan, 166 enum iio_event_type type, 167 enum iio_event_direction dir) 168 { 169 struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev); 170 int ret; 171 172 mutex_lock(&iqs624_pos->lock); 173 ret = iqs624_pos->angle_en; 174 mutex_unlock(&iqs624_pos->lock); 175 176 return ret; 177 } 178 179 static int iqs624_pos_write_event_config(struct iio_dev *indio_dev, 180 const struct iio_chan_spec *chan, 181 enum iio_event_type type, 182 enum iio_event_direction dir, 183 int state) 184 { 185 struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev); 186 struct iqs62x_core *iqs62x = iqs624_pos->iqs62x; 187 unsigned int val; 188 int ret; 189 190 mutex_lock(&iqs624_pos->lock); 191 192 ret = iqs624_pos_angle_get(iqs62x, &val); 193 if (ret) 194 goto err_mutex; 195 196 ret = iqs624_pos_angle_en(iqs62x, state); 197 if (ret) 198 goto err_mutex; 199 200 iqs624_pos->angle = val; 201 iqs624_pos->angle_en = state; 202 203 err_mutex: 204 mutex_unlock(&iqs624_pos->lock); 205 206 return ret; 207 } 208 209 static const struct iio_info iqs624_pos_info = { 210 .read_raw = &iqs624_pos_read_raw, 211 .read_event_config = iqs624_pos_read_event_config, 212 .write_event_config = iqs624_pos_write_event_config, 213 }; 214 215 static const struct iio_event_spec iqs624_pos_events[] = { 216 { 217 .type = IIO_EV_TYPE_CHANGE, 218 .dir = IIO_EV_DIR_NONE, 219 .mask_separate = BIT(IIO_EV_INFO_ENABLE), 220 }, 221 }; 222 223 static const struct iio_chan_spec iqs624_pos_channels[] = { 224 { 225 .type = IIO_ANGL, 226 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 227 BIT(IIO_CHAN_INFO_SCALE), 228 .event_spec = iqs624_pos_events, 229 .num_event_specs = ARRAY_SIZE(iqs624_pos_events), 230 }, 231 }; 232 233 static int iqs624_pos_probe(struct platform_device *pdev) 234 { 235 struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent); 236 struct iqs624_pos_private *iqs624_pos; 237 struct iio_dev *indio_dev; 238 int ret; 239 240 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs624_pos)); 241 if (!indio_dev) 242 return -ENOMEM; 243 244 iqs624_pos = iio_priv(indio_dev); 245 iqs624_pos->iqs62x = iqs62x; 246 247 indio_dev->modes = INDIO_DIRECT_MODE; 248 indio_dev->dev.parent = &pdev->dev; 249 indio_dev->channels = iqs624_pos_channels; 250 indio_dev->num_channels = ARRAY_SIZE(iqs624_pos_channels); 251 indio_dev->name = iqs62x->dev_desc->dev_name; 252 indio_dev->info = &iqs624_pos_info; 253 254 mutex_init(&iqs624_pos->lock); 255 256 iqs624_pos->notifier.notifier_call = iqs624_pos_notifier; 257 ret = blocking_notifier_chain_register(&iqs624_pos->iqs62x->nh, 258 &iqs624_pos->notifier); 259 if (ret) { 260 dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret); 261 return ret; 262 } 263 264 ret = devm_add_action_or_reset(&pdev->dev, 265 iqs624_pos_notifier_unregister, 266 iqs624_pos); 267 if (ret) 268 return ret; 269 270 return devm_iio_device_register(&pdev->dev, indio_dev); 271 } 272 273 static struct platform_driver iqs624_pos_platform_driver = { 274 .driver = { 275 .name = "iqs624-pos", 276 }, 277 .probe = iqs624_pos_probe, 278 }; 279 module_platform_driver(iqs624_pos_platform_driver); 280 281 MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); 282 MODULE_DESCRIPTION("Azoteq IQS624/625 Angular Position Sensors"); 283 MODULE_LICENSE("GPL"); 284 MODULE_ALIAS("platform:iqs624-pos"); 285