initial commit, reads dev id

Committer:
phonemacro
Date:
Fri Aug 17 05:35:58 2018 +0000
Revision:
5:1f7b8cb07e26
Updated driver for MAX86140/MAX86141 driver functions

Who changed what in which revision?

UserRevisionLine numberNew contents of line
phonemacro 5:1f7b8cb07e26 1 /*******************************************************************************
phonemacro 5:1f7b8cb07e26 2 * Author: Ismail Kose, Ismail.Kose@maximintegrated.com
phonemacro 5:1f7b8cb07e26 3 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
phonemacro 5:1f7b8cb07e26 4 *
phonemacro 5:1f7b8cb07e26 5 * Permission is hereby granted, free of charge, to any person obtaining a
phonemacro 5:1f7b8cb07e26 6 * copy of this software and associated documentation files (the "Software"),
phonemacro 5:1f7b8cb07e26 7 * to deal in the Software without restriction, including without limitation
phonemacro 5:1f7b8cb07e26 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
phonemacro 5:1f7b8cb07e26 9 * and/or sell copies of the Software, and to permit persons to whom the
phonemacro 5:1f7b8cb07e26 10 * Software is furnished to do so, subject to the following conditions:
phonemacro 5:1f7b8cb07e26 11 *
phonemacro 5:1f7b8cb07e26 12 * The above copyright notice and this permission notice shall be included
phonemacro 5:1f7b8cb07e26 13 * in all copies or substantial portions of the Software.
phonemacro 5:1f7b8cb07e26 14 *
phonemacro 5:1f7b8cb07e26 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
phonemacro 5:1f7b8cb07e26 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
phonemacro 5:1f7b8cb07e26 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
phonemacro 5:1f7b8cb07e26 18 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
phonemacro 5:1f7b8cb07e26 19 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
phonemacro 5:1f7b8cb07e26 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
phonemacro 5:1f7b8cb07e26 21 * OTHER DEALINGS IN THE SOFTWARE.
phonemacro 5:1f7b8cb07e26 22 *
phonemacro 5:1f7b8cb07e26 23 * Except as contained in this notice, the name of Maxim Integrated
phonemacro 5:1f7b8cb07e26 24 * Products, Inc. shall not be used except as stated in the Maxim Integrated
phonemacro 5:1f7b8cb07e26 25 * Products, Inc. Branding Policy.
phonemacro 5:1f7b8cb07e26 26 *
phonemacro 5:1f7b8cb07e26 27 * The mere transfer of this software does not imply any licenses
phonemacro 5:1f7b8cb07e26 28 * of trade secrets, proprietary technology, copyrights, patents,
phonemacro 5:1f7b8cb07e26 29 * trademarks, maskwork rights, or any other form of intellectual
phonemacro 5:1f7b8cb07e26 30 * property whatsoever. Maxim Integrated Products, Inc. retains all
phonemacro 5:1f7b8cb07e26 31 * ownership rights.
phonemacro 5:1f7b8cb07e26 32 *******************************************************************************
phonemacro 5:1f7b8cb07e26 33 */
phonemacro 5:1f7b8cb07e26 34
phonemacro 5:1f7b8cb07e26 35 #include "MAX8614X.h"
phonemacro 5:1f7b8cb07e26 36 #include <errno.h>
phonemacro 5:1f7b8cb07e26 37
phonemacro 5:1f7b8cb07e26 38 #define pr_err(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
phonemacro 5:1f7b8cb07e26 39 #define pr_info(fmt, args...) if(1) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
phonemacro 5:1f7b8cb07e26 40 #define pr_debug(fmt, args...) if(0) printf(fmt " (%s:%d)\n", ##args, __func__, __LINE__)
phonemacro 5:1f7b8cb07e26 41
phonemacro 5:1f7b8cb07e26 42 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
phonemacro 5:1f7b8cb07e26 43
phonemacro 5:1f7b8cb07e26 44 #define ILLEGAL_OUTPUT_POINTER 1
phonemacro 5:1f7b8cb07e26 45 #define ILLEGAL_DIODE_OUTPUT_MIN_MAX_PAIR 2
phonemacro 5:1f7b8cb07e26 46 #define ILLEGAL_LED_SETTING_MIN_MAX_PAIR 3
phonemacro 5:1f7b8cb07e26 47 #define CONSTRAINT_VIOLATION 4
phonemacro 5:1f7b8cb07e26 48
phonemacro 5:1f7b8cb07e26 49 #define MAX8614X_LED_DRIVE_CURRENT_FULL_SCALE \
phonemacro 5:1f7b8cb07e26 50 (MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT)
phonemacro 5:1f7b8cb07e26 51
phonemacro 5:1f7b8cb07e26 52 #define MAX8614X_AGC_DEFAULT_LED_OUT_RANGE 15
phonemacro 5:1f7b8cb07e26 53 #define MAX8614X_AGC_DEFAULT_CORRECTION_COEFF 50
phonemacro 5:1f7b8cb07e26 54 #define MAX8614X_AGC_DEFAULT_SENSITIVITY_PERCENT 10
phonemacro 5:1f7b8cb07e26 55 #define MAX8614X_AGC_DEFAULT_NUM_SAMPLES_TO_AVG 25
phonemacro 5:1f7b8cb07e26 56
phonemacro 5:1f7b8cb07e26 57 #define MAX8614X_PROX_THRESHOLD_1 10000
phonemacro 5:1f7b8cb07e26 58 #define MAX8614X_PROX_THRESHOLD_2 40000
phonemacro 5:1f7b8cb07e26 59 #define MAX8614X_PROX_DEBOUNCE_SPS 2
phonemacro 5:1f7b8cb07e26 60 #define MAX8614X_DAQ_DEBOUNCE_SPS 20
phonemacro 5:1f7b8cb07e26 61
phonemacro 5:1f7b8cb07e26 62 #define MAX8614X_DEFAULT_DAQ_LED_CURRENT_1 40000
phonemacro 5:1f7b8cb07e26 63 #define MAX8614X_DEFAULT_DAQ_LED_CURRENT_2 40000
phonemacro 5:1f7b8cb07e26 64 #define MAX8614X_DEFAULT_DAQ_LED_CURRENT_3 40000
phonemacro 5:1f7b8cb07e26 65 #define MAX8614X_DEFAULT_PROX_LED_CURRENT_1 10000
phonemacro 5:1f7b8cb07e26 66 #define MAX8614X_DEFAULT_PROX_LED_CURRENT_2 0
phonemacro 5:1f7b8cb07e26 67 #define MAX8614X_DEFAULT_PROX_LED_CURRENT_3 0
phonemacro 5:1f7b8cb07e26 68
phonemacro 5:1f7b8cb07e26 69
phonemacro 5:1f7b8cb07e26 70 #define MAX8614X_MIN_LED_DRIVE_CURRENT 0
phonemacro 5:1f7b8cb07e26 71 #define MAX8614X_MAX_LED_DRIVE_CURRENT 60000
phonemacro 5:1f7b8cb07e26 72
phonemacro 5:1f7b8cb07e26 73 #define MAX8614X_MAX_PPG_DIODE_VAL ((1 << 19) - 1)
phonemacro 5:1f7b8cb07e26 74 #define MAX8614X_MIN_PPG_DIODE_VAL 0
phonemacro 5:1f7b8cb07e26 75
phonemacro 5:1f7b8cb07e26 76 #define MAX8614X_DEFAULT_CURRENT1 0x30
phonemacro 5:1f7b8cb07e26 77 #define MAX8614X_DEFAULT_CURRENT2 0
phonemacro 5:1f7b8cb07e26 78 #define MAX8614X_DEFAULT_CURRENT3 0
phonemacro 5:1f7b8cb07e26 79
phonemacro 5:1f7b8cb07e26 80
phonemacro 5:1f7b8cb07e26 81 int MAX8614X::max8614x_update_led_range(
phonemacro 5:1f7b8cb07e26 82 int new_range, uint8_t led_num,
phonemacro 5:1f7b8cb07e26 83 union led_range *led_range_settings)
phonemacro 5:1f7b8cb07e26 84 {
phonemacro 5:1f7b8cb07e26 85 int old_range;
phonemacro 5:1f7b8cb07e26 86 Registers reg_addr;
phonemacro 5:1f7b8cb07e26 87
phonemacro 5:1f7b8cb07e26 88 switch (led_num) {
phonemacro 5:1f7b8cb07e26 89 case LED_1:
phonemacro 5:1f7b8cb07e26 90 old_range = led_range_settings->led1;
phonemacro 5:1f7b8cb07e26 91 led_range_settings->led1 = new_range;
phonemacro 5:1f7b8cb07e26 92 reg_addr = MAX8614X_LED_RANGE1_REG;
phonemacro 5:1f7b8cb07e26 93 break;
phonemacro 5:1f7b8cb07e26 94 case LED_2:
phonemacro 5:1f7b8cb07e26 95 old_range = led_range_settings->led2;
phonemacro 5:1f7b8cb07e26 96 led_range_settings->led2 = new_range;
phonemacro 5:1f7b8cb07e26 97 reg_addr = MAX8614X_LED_RANGE1_REG;
phonemacro 5:1f7b8cb07e26 98 break;
phonemacro 5:1f7b8cb07e26 99 case LED_3:
phonemacro 5:1f7b8cb07e26 100 old_range = led_range_settings->led3;
phonemacro 5:1f7b8cb07e26 101 led_range_settings->led3 = new_range;
phonemacro 5:1f7b8cb07e26 102 reg_addr = MAX8614X_LED_RANGE1_REG;
phonemacro 5:1f7b8cb07e26 103 break;
phonemacro 5:1f7b8cb07e26 104 case LED_4:
phonemacro 5:1f7b8cb07e26 105 old_range = led_range_settings->led4;
phonemacro 5:1f7b8cb07e26 106 led_range_settings->led4 = new_range;
phonemacro 5:1f7b8cb07e26 107 reg_addr = MAX8614X_LED_RANGE2_REG;
phonemacro 5:1f7b8cb07e26 108 break;
phonemacro 5:1f7b8cb07e26 109 case LED_5:
phonemacro 5:1f7b8cb07e26 110 old_range = led_range_settings->led5;
phonemacro 5:1f7b8cb07e26 111 led_range_settings->led5 = new_range;
phonemacro 5:1f7b8cb07e26 112 reg_addr = MAX8614X_LED_RANGE2_REG;
phonemacro 5:1f7b8cb07e26 113 break;
phonemacro 5:1f7b8cb07e26 114 case LED_6:
phonemacro 5:1f7b8cb07e26 115 old_range = led_range_settings->led6;
phonemacro 5:1f7b8cb07e26 116 led_range_settings->led6 = new_range;
phonemacro 5:1f7b8cb07e26 117 reg_addr = MAX8614X_LED_RANGE2_REG;
phonemacro 5:1f7b8cb07e26 118 break;
phonemacro 5:1f7b8cb07e26 119
phonemacro 5:1f7b8cb07e26 120 default:
phonemacro 5:1f7b8cb07e26 121 return -EINVAL;
phonemacro 5:1f7b8cb07e26 122 }
phonemacro 5:1f7b8cb07e26 123
phonemacro 5:1f7b8cb07e26 124 if (old_range == new_range)
phonemacro 5:1f7b8cb07e26 125 return 0;
phonemacro 5:1f7b8cb07e26 126
phonemacro 5:1f7b8cb07e26 127 return writeRegister( reg_addr,
phonemacro 5:1f7b8cb07e26 128 led_range_settings->val[led_num < LED_4 ? 0 : 1]);
phonemacro 5:1f7b8cb07e26 129 }
phonemacro 5:1f7b8cb07e26 130
phonemacro 5:1f7b8cb07e26 131 int MAX8614X::max8614x_update_led_current(
phonemacro 5:1f7b8cb07e26 132 union led_range *led_range_settings,
phonemacro 5:1f7b8cb07e26 133 int led_new_val,
phonemacro 5:1f7b8cb07e26 134 max8614x_led_t led_num)
phonemacro 5:1f7b8cb07e26 135 {
phonemacro 5:1f7b8cb07e26 136 int ret = 0;
phonemacro 5:1f7b8cb07e26 137 Registers led_current_reg_addr;
phonemacro 5:1f7b8cb07e26 138 int led_range;
phonemacro 5:1f7b8cb07e26 139 uint8_t led_current_reg_val;
phonemacro 5:1f7b8cb07e26 140 int led_range_index = led_new_val / 25000;
phonemacro 5:1f7b8cb07e26 141 const int led_range_steps[] = {
phonemacro 5:1f7b8cb07e26 142 LED_RANGE_STEP_25uA,
phonemacro 5:1f7b8cb07e26 143 LED_RANGE_STEP_50uA,
phonemacro 5:1f7b8cb07e26 144 LED_RANGE_STEP_75uA,
phonemacro 5:1f7b8cb07e26 145 LED_RANGE_STEP_100uA,
phonemacro 5:1f7b8cb07e26 146 LED_RANGE_STEP_100uA, /* For led current greater than 100uA */
phonemacro 5:1f7b8cb07e26 147 };
phonemacro 5:1f7b8cb07e26 148
phonemacro 5:1f7b8cb07e26 149 switch(led_num) {
phonemacro 5:1f7b8cb07e26 150 case LED_1:
phonemacro 5:1f7b8cb07e26 151 led_current_reg_addr = MAX8614X_LED1_PA_REG;
phonemacro 5:1f7b8cb07e26 152 break;
phonemacro 5:1f7b8cb07e26 153 case LED_2:
phonemacro 5:1f7b8cb07e26 154 led_current_reg_addr = MAX8614X_LED2_PA_REG;
phonemacro 5:1f7b8cb07e26 155 break;
phonemacro 5:1f7b8cb07e26 156 case LED_3:
phonemacro 5:1f7b8cb07e26 157 led_current_reg_addr = MAX8614X_LED3_PA_REG;
phonemacro 5:1f7b8cb07e26 158 break;
phonemacro 5:1f7b8cb07e26 159 case LED_4:
phonemacro 5:1f7b8cb07e26 160 led_current_reg_addr = MAX8614X_LED4_PA_REG;
phonemacro 5:1f7b8cb07e26 161 break;
phonemacro 5:1f7b8cb07e26 162 case LED_5:
phonemacro 5:1f7b8cb07e26 163 led_current_reg_addr = MAX8614X_LED5_PA_REG;
phonemacro 5:1f7b8cb07e26 164 break;
phonemacro 5:1f7b8cb07e26 165 case LED_6:
phonemacro 5:1f7b8cb07e26 166 led_current_reg_addr = MAX8614X_LED6_PA_REG;
phonemacro 5:1f7b8cb07e26 167 break;
phonemacro 5:1f7b8cb07e26 168 default:
phonemacro 5:1f7b8cb07e26 169 pr_err("Invalid led number: %d\n", led_num);
phonemacro 5:1f7b8cb07e26 170 return -EINVAL;
phonemacro 5:1f7b8cb07e26 171 }
phonemacro 5:1f7b8cb07e26 172
phonemacro 5:1f7b8cb07e26 173 if (led_new_val < MAX8614X_MIN_LED_DRIVE_CURRENT
phonemacro 5:1f7b8cb07e26 174 || led_new_val > MAX8614X_MAX_LED_DRIVE_CURRENT) {
phonemacro 5:1f7b8cb07e26 175 pr_err("Invalid led value: %d\n", led_new_val);
phonemacro 5:1f7b8cb07e26 176 return -EINVAL;
phonemacro 5:1f7b8cb07e26 177 }
phonemacro 5:1f7b8cb07e26 178
phonemacro 5:1f7b8cb07e26 179 led_current_reg_val = led_new_val / led_range_steps[led_range_index];
phonemacro 5:1f7b8cb07e26 180
phonemacro 5:1f7b8cb07e26 181 pr_debug("Updating LED%d current to %d. led_rge_idx: %d, reg_val: %.2X",
phonemacro 5:1f7b8cb07e26 182 led_num, led_new_val, led_range_index, led_current_reg_val);
phonemacro 5:1f7b8cb07e26 183
phonemacro 5:1f7b8cb07e26 184 ret = writeRegister(led_current_reg_addr, led_current_reg_val);
phonemacro 5:1f7b8cb07e26 185 if (ret < 0)
phonemacro 5:1f7b8cb07e26 186 return ret;
phonemacro 5:1f7b8cb07e26 187
phonemacro 5:1f7b8cb07e26 188
phonemacro 5:1f7b8cb07e26 189 led_range = led_range_index;
phonemacro 5:1f7b8cb07e26 190 pr_debug("Updating LED%d range to %d.", led_num, led_range);
phonemacro 5:1f7b8cb07e26 191 if (led_range > 3)
phonemacro 5:1f7b8cb07e26 192 led_range = 3;
phonemacro 5:1f7b8cb07e26 193 ret = max8614x_update_led_range( led_range, led_num, led_range_settings);
phonemacro 5:1f7b8cb07e26 194 if (ret < 0)
phonemacro 5:1f7b8cb07e26 195 return ret;
phonemacro 5:1f7b8cb07e26 196 return ret;
phonemacro 5:1f7b8cb07e26 197 }
phonemacro 5:1f7b8cb07e26 198
phonemacro 5:1f7b8cb07e26 199 int32_t agc_adj_calculator(
phonemacro 5:1f7b8cb07e26 200 int32_t *change_by_percent_of_range,
phonemacro 5:1f7b8cb07e26 201 int32_t *change_by_percent_of_current_setting,
phonemacro 5:1f7b8cb07e26 202 int32_t *change_led_by_absolute_count,
phonemacro 5:1f7b8cb07e26 203 int32_t *set_led_to_absolute_count,
phonemacro 5:1f7b8cb07e26 204 int32_t target_percent_of_range,
phonemacro 5:1f7b8cb07e26 205 int32_t correction_coefficient,
phonemacro 5:1f7b8cb07e26 206 int32_t allowed_error_in_percentage,
phonemacro 5:1f7b8cb07e26 207 int32_t current_average,
phonemacro 5:1f7b8cb07e26 208 int32_t number_of_samples_averaged,
phonemacro 5:1f7b8cb07e26 209 int32_t led_drive_current_value)
phonemacro 5:1f7b8cb07e26 210 {
phonemacro 5:1f7b8cb07e26 211 int32_t current_percent_of_range = 0;
phonemacro 5:1f7b8cb07e26 212 int32_t delta = 0;
phonemacro 5:1f7b8cb07e26 213 int32_t desired_delta = 0;
phonemacro 5:1f7b8cb07e26 214 int32_t current_power_percent = 0;
phonemacro 5:1f7b8cb07e26 215
phonemacro 5:1f7b8cb07e26 216 if (change_by_percent_of_range == 0
phonemacro 5:1f7b8cb07e26 217 || change_by_percent_of_current_setting == 0
phonemacro 5:1f7b8cb07e26 218 || change_led_by_absolute_count == 0
phonemacro 5:1f7b8cb07e26 219 || set_led_to_absolute_count == 0)
phonemacro 5:1f7b8cb07e26 220 return ILLEGAL_OUTPUT_POINTER;
phonemacro 5:1f7b8cb07e26 221
phonemacro 5:1f7b8cb07e26 222 if (target_percent_of_range > 90 || target_percent_of_range < 10)
phonemacro 5:1f7b8cb07e26 223 return CONSTRAINT_VIOLATION;
phonemacro 5:1f7b8cb07e26 224
phonemacro 5:1f7b8cb07e26 225 if (correction_coefficient > 100 || correction_coefficient < 0)
phonemacro 5:1f7b8cb07e26 226 return CONSTRAINT_VIOLATION;
phonemacro 5:1f7b8cb07e26 227
phonemacro 5:1f7b8cb07e26 228 if (allowed_error_in_percentage > 100
phonemacro 5:1f7b8cb07e26 229 || allowed_error_in_percentage < 0)
phonemacro 5:1f7b8cb07e26 230 return CONSTRAINT_VIOLATION;
phonemacro 5:1f7b8cb07e26 231
phonemacro 5:1f7b8cb07e26 232 #if ((MAX8614X_MAX_PPG_DIODE_VAL - MAX8614X_MIN_PPG_DIODE_VAL) <= 0 \
phonemacro 5:1f7b8cb07e26 233 || (MAX8614X_MAX_PPG_DIODE_VAL < 0) || (MAX8614X_MIN_PPG_DIODE_VAL < 0))
phonemacro 5:1f7b8cb07e26 234 #error "Illegal diode Min/Max Pair"
phonemacro 5:1f7b8cb07e26 235 #endif
phonemacro 5:1f7b8cb07e26 236
phonemacro 5:1f7b8cb07e26 237 #if ((MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT) <= 0 \
phonemacro 5:1f7b8cb07e26 238 || (MAX8614X_MAX_LED_DRIVE_CURRENT < 0) || (MAX8614X_MIN_LED_DRIVE_CURRENT < 0))
phonemacro 5:1f7b8cb07e26 239 #error "Illegal LED Min/Max current Pair"
phonemacro 5:1f7b8cb07e26 240 #endif
phonemacro 5:1f7b8cb07e26 241
phonemacro 5:1f7b8cb07e26 242 if (led_drive_current_value > MAX8614X_MAX_LED_DRIVE_CURRENT
phonemacro 5:1f7b8cb07e26 243 || led_drive_current_value < MAX8614X_MIN_LED_DRIVE_CURRENT)
phonemacro 5:1f7b8cb07e26 244 return CONSTRAINT_VIOLATION;
phonemacro 5:1f7b8cb07e26 245
phonemacro 5:1f7b8cb07e26 246 if (current_average < MAX8614X_MIN_PPG_DIODE_VAL
phonemacro 5:1f7b8cb07e26 247 || current_average > MAX8614X_MAX_PPG_DIODE_VAL)
phonemacro 5:1f7b8cb07e26 248 return CONSTRAINT_VIOLATION;
phonemacro 5:1f7b8cb07e26 249
phonemacro 5:1f7b8cb07e26 250 current_percent_of_range = 100 *
phonemacro 5:1f7b8cb07e26 251 (current_average - MAX8614X_MIN_PPG_DIODE_VAL) /
phonemacro 5:1f7b8cb07e26 252 (MAX8614X_MAX_PPG_DIODE_VAL - MAX8614X_MIN_PPG_DIODE_VAL) ;
phonemacro 5:1f7b8cb07e26 253
phonemacro 5:1f7b8cb07e26 254 delta = current_percent_of_range - target_percent_of_range;
phonemacro 5:1f7b8cb07e26 255 delta = delta * correction_coefficient / 100;
phonemacro 5:1f7b8cb07e26 256
phonemacro 5:1f7b8cb07e26 257 if (delta > -allowed_error_in_percentage
phonemacro 5:1f7b8cb07e26 258 && delta < allowed_error_in_percentage) {
phonemacro 5:1f7b8cb07e26 259 *change_by_percent_of_range = 0;
phonemacro 5:1f7b8cb07e26 260 *change_by_percent_of_current_setting = 0;
phonemacro 5:1f7b8cb07e26 261 *change_led_by_absolute_count = 0;
phonemacro 5:1f7b8cb07e26 262 *set_led_to_absolute_count = led_drive_current_value;
phonemacro 5:1f7b8cb07e26 263 return 0;
phonemacro 5:1f7b8cb07e26 264 }
phonemacro 5:1f7b8cb07e26 265
phonemacro 5:1f7b8cb07e26 266 current_power_percent = 100 *
phonemacro 5:1f7b8cb07e26 267 (led_drive_current_value - MAX8614X_MIN_LED_DRIVE_CURRENT) /
phonemacro 5:1f7b8cb07e26 268 (MAX8614X_MAX_LED_DRIVE_CURRENT - MAX8614X_MIN_LED_DRIVE_CURRENT);
phonemacro 5:1f7b8cb07e26 269 if (delta < 0)
phonemacro 5:1f7b8cb07e26 270 desired_delta = -delta * (100 - current_power_percent) /
phonemacro 5:1f7b8cb07e26 271 (100 - current_percent_of_range);
phonemacro 5:1f7b8cb07e26 272
phonemacro 5:1f7b8cb07e26 273 if (delta > 0)
phonemacro 5:1f7b8cb07e26 274 desired_delta = -delta * (current_power_percent)
phonemacro 5:1f7b8cb07e26 275 / (current_percent_of_range);
phonemacro 5:1f7b8cb07e26 276
phonemacro 5:1f7b8cb07e26 277 *change_by_percent_of_range = desired_delta;
phonemacro 5:1f7b8cb07e26 278
phonemacro 5:1f7b8cb07e26 279 *change_led_by_absolute_count = (desired_delta
phonemacro 5:1f7b8cb07e26 280 * MAX8614X_LED_DRIVE_CURRENT_FULL_SCALE / 100);
phonemacro 5:1f7b8cb07e26 281 *change_by_percent_of_current_setting =
phonemacro 5:1f7b8cb07e26 282 (*change_led_by_absolute_count * 100)
phonemacro 5:1f7b8cb07e26 283 / (led_drive_current_value);
phonemacro 5:1f7b8cb07e26 284 *set_led_to_absolute_count = led_drive_current_value
phonemacro 5:1f7b8cb07e26 285 + *change_led_by_absolute_count;
phonemacro 5:1f7b8cb07e26 286
phonemacro 5:1f7b8cb07e26 287 //If we are saturated, cut power in half
phonemacro 5:1f7b8cb07e26 288 if (current_percent_of_range >= 100)
phonemacro 5:1f7b8cb07e26 289 {
phonemacro 5:1f7b8cb07e26 290 *change_by_percent_of_range = -100; //Unknown, set fake value
phonemacro 5:1f7b8cb07e26 291 *change_by_percent_of_current_setting = -50;
phonemacro 5:1f7b8cb07e26 292 *change_led_by_absolute_count = 0 - (led_drive_current_value / 2);
phonemacro 5:1f7b8cb07e26 293 *set_led_to_absolute_count = led_drive_current_value / 2;
phonemacro 5:1f7b8cb07e26 294 }
phonemacro 5:1f7b8cb07e26 295
phonemacro 5:1f7b8cb07e26 296 return 0;
phonemacro 5:1f7b8cb07e26 297 }
phonemacro 5:1f7b8cb07e26 298
phonemacro 5:1f7b8cb07e26 299 void MAX8614X::ppg_auto_gain_ctrl(
phonemacro 5:1f7b8cb07e26 300 struct led_control *led_ctrl,
phonemacro 5:1f7b8cb07e26 301 uint32_t sample_cnt, int diode_data, max8614x_led_t led_num)
phonemacro 5:1f7b8cb07e26 302 {
phonemacro 5:1f7b8cb07e26 303 int ret;
phonemacro 5:1f7b8cb07e26 304 int diode_avg;
phonemacro 5:1f7b8cb07e26 305
phonemacro 5:1f7b8cb07e26 306 if (led_num > LED_3) /* TODO: why3? */
phonemacro 5:1f7b8cb07e26 307 return;
phonemacro 5:1f7b8cb07e26 308
phonemacro 5:1f7b8cb07e26 309 led_ctrl->diode_sum[led_num] += diode_data;
phonemacro 5:1f7b8cb07e26 310 if (sample_cnt % led_ctrl->agc_min_num_samples == 0) {
phonemacro 5:1f7b8cb07e26 311 diode_avg = led_ctrl->diode_sum[led_num]
phonemacro 5:1f7b8cb07e26 312 / led_ctrl->agc_min_num_samples;
phonemacro 5:1f7b8cb07e26 313 led_ctrl->diode_sum[led_num] = 0;
phonemacro 5:1f7b8cb07e26 314 } else
phonemacro 5:1f7b8cb07e26 315 return;
phonemacro 5:1f7b8cb07e26 316
phonemacro 5:1f7b8cb07e26 317 ret = agc_adj_calculator(
phonemacro 5:1f7b8cb07e26 318 &led_ctrl->change_by_percent_of_range[led_num],
phonemacro 5:1f7b8cb07e26 319 &led_ctrl->change_by_percent_of_current_setting[led_num],
phonemacro 5:1f7b8cb07e26 320 &led_ctrl->change_led_by_absolute_count[led_num],
phonemacro 5:1f7b8cb07e26 321 &led_ctrl->led_current[led_num],
phonemacro 5:1f7b8cb07e26 322 led_ctrl->agc_led_out_percent,
phonemacro 5:1f7b8cb07e26 323 led_ctrl->agc_corr_coeff,
phonemacro 5:1f7b8cb07e26 324 led_ctrl->agc_sensitivity_percent,
phonemacro 5:1f7b8cb07e26 325 diode_avg,
phonemacro 5:1f7b8cb07e26 326 led_ctrl->agc_min_num_samples,
phonemacro 5:1f7b8cb07e26 327 led_ctrl->led_current[led_num]);
phonemacro 5:1f7b8cb07e26 328 if (ret)
phonemacro 5:1f7b8cb07e26 329 return;
phonemacro 5:1f7b8cb07e26 330
phonemacro 5:1f7b8cb07e26 331 if (led_ctrl->change_led_by_absolute_count[led_num] == 0)
phonemacro 5:1f7b8cb07e26 332 return;
phonemacro 5:1f7b8cb07e26 333
phonemacro 5:1f7b8cb07e26 334 ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
phonemacro 5:1f7b8cb07e26 335 led_ctrl->led_current[led_num], led_num);
phonemacro 5:1f7b8cb07e26 336 if (ret < 0)
phonemacro 5:1f7b8cb07e26 337 pr_err("%s failed", __func__);
phonemacro 5:1f7b8cb07e26 338 return;
phonemacro 5:1f7b8cb07e26 339 }
phonemacro 5:1f7b8cb07e26 340
phonemacro 5:1f7b8cb07e26 341 void MAX8614X::max8614x_agc_handler(struct led_control *led_ctrl,
phonemacro 5:1f7b8cb07e26 342 int *samples)
phonemacro 5:1f7b8cb07e26 343 {
phonemacro 5:1f7b8cb07e26 344 static int ret = -1;
phonemacro 5:1f7b8cb07e26 345
phonemacro 5:1f7b8cb07e26 346 if (!led_ctrl->agc_is_enabled)
phonemacro 5:1f7b8cb07e26 347 return;
phonemacro 5:1f7b8cb07e26 348
phonemacro 5:1f7b8cb07e26 349 led_ctrl->sample_cnt++;
phonemacro 5:1f7b8cb07e26 350 ret = led_control_sm(led_ctrl,
phonemacro 5:1f7b8cb07e26 351 samples[DATA_TYPE_PPG1_LEDC1],
phonemacro 5:1f7b8cb07e26 352 led_ctrl->lpm_is_enabled);
phonemacro 5:1f7b8cb07e26 353
phonemacro 5:1f7b8cb07e26 354 if (ret == LED_DATA_ACQ) {
phonemacro 5:1f7b8cb07e26 355 ppg_auto_gain_ctrl(led_ctrl,
phonemacro 5:1f7b8cb07e26 356 led_ctrl->sample_cnt,
phonemacro 5:1f7b8cb07e26 357 samples[DATA_TYPE_PPG1_LEDC1],
phonemacro 5:1f7b8cb07e26 358 LED_1);
phonemacro 5:1f7b8cb07e26 359 ppg_auto_gain_ctrl(led_ctrl,
phonemacro 5:1f7b8cb07e26 360 led_ctrl->sample_cnt,
phonemacro 5:1f7b8cb07e26 361 samples[DATA_TYPE_PPG1_LEDC2],
phonemacro 5:1f7b8cb07e26 362 LED_2);
phonemacro 5:1f7b8cb07e26 363 ppg_auto_gain_ctrl(led_ctrl,
phonemacro 5:1f7b8cb07e26 364 led_ctrl->sample_cnt,
phonemacro 5:1f7b8cb07e26 365 samples[DATA_TYPE_PPG1_LEDC3],
phonemacro 5:1f7b8cb07e26 366 LED_3);
phonemacro 5:1f7b8cb07e26 367 }
phonemacro 5:1f7b8cb07e26 368
phonemacro 5:1f7b8cb07e26 369 return;
phonemacro 5:1f7b8cb07e26 370 }
phonemacro 5:1f7b8cb07e26 371
phonemacro 5:1f7b8cb07e26 372 int MAX8614X::led_prox_init(struct led_control *led_ctrl, char lpm)
phonemacro 5:1f7b8cb07e26 373 {
phonemacro 5:1f7b8cb07e26 374 int ret;
phonemacro 5:1f7b8cb07e26 375 const RegisterMap low_pm_settings[] = {
phonemacro 5:1f7b8cb07e26 376 { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
phonemacro 5:1f7b8cb07e26 377 | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
phonemacro 5:1f7b8cb07e26 378 | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
phonemacro 5:1f7b8cb07e26 379 { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_25_SPS},
phonemacro 5:1f7b8cb07e26 380 { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_DATA_RDY_MASK },
phonemacro 5:1f7b8cb07e26 381 };
phonemacro 5:1f7b8cb07e26 382
phonemacro 5:1f7b8cb07e26 383 led_ctrl->led_current[LED_1] = MAX8614X_DEFAULT_PROX_LED_CURRENT_1;
phonemacro 5:1f7b8cb07e26 384 ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
phonemacro 5:1f7b8cb07e26 385 led_ctrl->led_current[LED_1], LED_1);
phonemacro 5:1f7b8cb07e26 386
phonemacro 5:1f7b8cb07e26 387 led_ctrl->led_current[LED_2] = MAX8614X_DEFAULT_PROX_LED_CURRENT_2;
phonemacro 5:1f7b8cb07e26 388 ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
phonemacro 5:1f7b8cb07e26 389 led_ctrl->led_current[LED_2], LED_2);
phonemacro 5:1f7b8cb07e26 390
phonemacro 5:1f7b8cb07e26 391 led_ctrl->led_current[LED_3] = MAX8614X_DEFAULT_PROX_LED_CURRENT_3;
phonemacro 5:1f7b8cb07e26 392 ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
phonemacro 5:1f7b8cb07e26 393 led_ctrl->led_current[LED_3], LED_3);
phonemacro 5:1f7b8cb07e26 394
phonemacro 5:1f7b8cb07e26 395 if (lpm)
phonemacro 5:1f7b8cb07e26 396 ret |= writeBlock(low_pm_settings,
phonemacro 5:1f7b8cb07e26 397 ARRAY_SIZE(low_pm_settings));
phonemacro 5:1f7b8cb07e26 398 return ret;
phonemacro 5:1f7b8cb07e26 399 }
phonemacro 5:1f7b8cb07e26 400
phonemacro 5:1f7b8cb07e26 401 int MAX8614X::led_daq_init(struct led_control *led_ctrl, char lpm)
phonemacro 5:1f7b8cb07e26 402 {
phonemacro 5:1f7b8cb07e26 403 int ret;
phonemacro 5:1f7b8cb07e26 404 const RegisterMap non_lpm_settings[] = {
phonemacro 5:1f7b8cb07e26 405 { MAX8614X_PPG_CFG1_REG, MAX8614X_PPG_LED_PW_115_2_US_MASK // PPG_LED_PW = 3 (115.2us)
phonemacro 5:1f7b8cb07e26 406 | MAX8614X_PPG1_ADC_RGE_32768_MASK // PPG1_ADC_RGE = 3(32768nA)
phonemacro 5:1f7b8cb07e26 407 | MAX8614X_PPG2_ADC_RGE_32768_MASK }, // PPG2_ADC_RGE = 3(32768nA)
phonemacro 5:1f7b8cb07e26 408 { MAX8614X_PPG_CFG2_REG, MAX8614X_PPG_SR_100_SPS},
phonemacro 5:1f7b8cb07e26 409 { MAX8614X_INT_ENABLE1_REG, MAX8614X_INT1_EN_A_FULL_MASK },
phonemacro 5:1f7b8cb07e26 410 };
phonemacro 5:1f7b8cb07e26 411
phonemacro 5:1f7b8cb07e26 412 led_ctrl->led_current[LED_1] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_1;
phonemacro 5:1f7b8cb07e26 413 ret = max8614x_update_led_current(&led_ctrl->led_range_settings,
phonemacro 5:1f7b8cb07e26 414 led_ctrl->led_current[LED_1], LED_1);
phonemacro 5:1f7b8cb07e26 415
phonemacro 5:1f7b8cb07e26 416 led_ctrl->led_current[LED_2] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_2;
phonemacro 5:1f7b8cb07e26 417 ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
phonemacro 5:1f7b8cb07e26 418 led_ctrl->led_current[LED_2], LED_2);
phonemacro 5:1f7b8cb07e26 419
phonemacro 5:1f7b8cb07e26 420 led_ctrl->led_current[LED_3] = MAX8614X_DEFAULT_DAQ_LED_CURRENT_3;
phonemacro 5:1f7b8cb07e26 421 ret |= max8614x_update_led_current(&led_ctrl->led_range_settings,
phonemacro 5:1f7b8cb07e26 422 led_ctrl->led_current[LED_3], LED_3);
phonemacro 5:1f7b8cb07e26 423
phonemacro 5:1f7b8cb07e26 424 if (lpm)
phonemacro 5:1f7b8cb07e26 425 ret |= writeBlock(non_lpm_settings,
phonemacro 5:1f7b8cb07e26 426 ARRAY_SIZE(non_lpm_settings));
phonemacro 5:1f7b8cb07e26 427
phonemacro 5:1f7b8cb07e26 428 return ret;
phonemacro 5:1f7b8cb07e26 429 }
phonemacro 5:1f7b8cb07e26 430
phonemacro 5:1f7b8cb07e26 431 int MAX8614X::led_control_sm(struct led_control *led_ctrl, int diode_data, char lpm)
phonemacro 5:1f7b8cb07e26 432 {
phonemacro 5:1f7b8cb07e26 433 int ret = led_ctrl->state;
phonemacro 5:1f7b8cb07e26 434 int avg = 0;
phonemacro 5:1f7b8cb07e26 435
phonemacro 5:1f7b8cb07e26 436 led_ctrl->prox_sample_cnt++;
phonemacro 5:1f7b8cb07e26 437 led_ctrl->prox_sum += diode_data;
phonemacro 5:1f7b8cb07e26 438
phonemacro 5:1f7b8cb07e26 439 switch (led_ctrl->state) {
phonemacro 5:1f7b8cb07e26 440 case LED_PROX:
phonemacro 5:1f7b8cb07e26 441 if (led_ctrl->prox_sample_cnt % MAX8614X_PROX_DEBOUNCE_SPS != 0)
phonemacro 5:1f7b8cb07e26 442 break;
phonemacro 5:1f7b8cb07e26 443
phonemacro 5:1f7b8cb07e26 444 avg = led_ctrl->prox_sum / MAX8614X_PROX_DEBOUNCE_SPS;
phonemacro 5:1f7b8cb07e26 445 if (avg >= MAX8614X_PROX_THRESHOLD_1) {
phonemacro 5:1f7b8cb07e26 446 led_ctrl->state = LED_DATA_ACQ;
phonemacro 5:1f7b8cb07e26 447 ret = led_daq_init(led_ctrl, lpm);
phonemacro 5:1f7b8cb07e26 448 led_ctrl->prox_sample_cnt = 0;
phonemacro 5:1f7b8cb07e26 449 }
phonemacro 5:1f7b8cb07e26 450 led_ctrl->prox_sum = 0;
phonemacro 5:1f7b8cb07e26 451 break;
phonemacro 5:1f7b8cb07e26 452
phonemacro 5:1f7b8cb07e26 453 case LED_DATA_ACQ:
phonemacro 5:1f7b8cb07e26 454 if (led_ctrl->prox_sample_cnt % MAX8614X_DAQ_DEBOUNCE_SPS != 0)
phonemacro 5:1f7b8cb07e26 455 break;
phonemacro 5:1f7b8cb07e26 456
phonemacro 5:1f7b8cb07e26 457 avg = led_ctrl->prox_sum / MAX8614X_DAQ_DEBOUNCE_SPS;
phonemacro 5:1f7b8cb07e26 458 if (avg <= MAX8614X_PROX_THRESHOLD_2) {
phonemacro 5:1f7b8cb07e26 459 led_ctrl->state = LED_PROX;
phonemacro 5:1f7b8cb07e26 460 ret = led_prox_init(led_ctrl, lpm);
phonemacro 5:1f7b8cb07e26 461 led_ctrl->prox_sample_cnt = 0;
phonemacro 5:1f7b8cb07e26 462 }
phonemacro 5:1f7b8cb07e26 463 led_ctrl->prox_sum = 0;
phonemacro 5:1f7b8cb07e26 464 break;
phonemacro 5:1f7b8cb07e26 465
phonemacro 5:1f7b8cb07e26 466 default:
phonemacro 5:1f7b8cb07e26 467 led_ctrl->state = LED_PROX;
phonemacro 5:1f7b8cb07e26 468 led_ctrl->prox_sum = 0;
phonemacro 5:1f7b8cb07e26 469 led_ctrl->prox_sample_cnt = 0;
phonemacro 5:1f7b8cb07e26 470 return -EINVAL;
phonemacro 5:1f7b8cb07e26 471 }
phonemacro 5:1f7b8cb07e26 472
phonemacro 5:1f7b8cb07e26 473 return ret;
phonemacro 5:1f7b8cb07e26 474 }
phonemacro 5:1f7b8cb07e26 475
phonemacro 5:1f7b8cb07e26 476 void MAX8614X::led_control_reset(struct led_control *led_ctrl)
phonemacro 5:1f7b8cb07e26 477 {
phonemacro 5:1f7b8cb07e26 478 led_ctrl->led_current[LED_1] = led_ctrl->default_current[LED_1];
phonemacro 5:1f7b8cb07e26 479 led_ctrl->led_current[LED_2] = led_ctrl->default_current[LED_2];
phonemacro 5:1f7b8cb07e26 480 led_ctrl->led_current[LED_3] = led_ctrl->default_current[LED_3];
phonemacro 5:1f7b8cb07e26 481
phonemacro 5:1f7b8cb07e26 482 memset(led_ctrl->change_by_percent_of_range, 0,
phonemacro 5:1f7b8cb07e26 483 sizeof(led_ctrl->change_by_percent_of_range));
phonemacro 5:1f7b8cb07e26 484 memset(led_ctrl->change_by_percent_of_current_setting, 0,
phonemacro 5:1f7b8cb07e26 485 sizeof(led_ctrl->change_by_percent_of_range));
phonemacro 5:1f7b8cb07e26 486 memset(led_ctrl->change_led_by_absolute_count, 0,
phonemacro 5:1f7b8cb07e26 487 sizeof(led_ctrl->change_by_percent_of_range));
phonemacro 5:1f7b8cb07e26 488 memset(led_ctrl->diode_sum, 0, sizeof(led_ctrl->diode_sum));
phonemacro 5:1f7b8cb07e26 489
phonemacro 5:1f7b8cb07e26 490 led_ctrl->agc_is_enabled = 1;
phonemacro 5:1f7b8cb07e26 491 led_ctrl->prox_sum = 0;
phonemacro 5:1f7b8cb07e26 492 led_ctrl->prox_sample_cnt = 0;
phonemacro 5:1f7b8cb07e26 493 led_ctrl->sample_cnt = -1;
phonemacro 5:1f7b8cb07e26 494 led_ctrl->state = LED_PROX;
phonemacro 5:1f7b8cb07e26 495 }
phonemacro 5:1f7b8cb07e26 496
phonemacro 5:1f7b8cb07e26 497 void MAX8614X::led_control_init(struct led_control *led_ctrl)
phonemacro 5:1f7b8cb07e26 498 {
phonemacro 5:1f7b8cb07e26 499 memset(led_ctrl, 0, sizeof(struct led_control));
phonemacro 5:1f7b8cb07e26 500
phonemacro 5:1f7b8cb07e26 501 led_ctrl->default_current[LED_1] = MAX8614X_DEFAULT_CURRENT1;
phonemacro 5:1f7b8cb07e26 502 led_ctrl->default_current[LED_2] = MAX8614X_DEFAULT_CURRENT2;
phonemacro 5:1f7b8cb07e26 503 led_ctrl->default_current[LED_3] = MAX8614X_DEFAULT_CURRENT3;
phonemacro 5:1f7b8cb07e26 504 led_ctrl->agc_led_out_percent = MAX8614X_AGC_DEFAULT_LED_OUT_RANGE;
phonemacro 5:1f7b8cb07e26 505 led_ctrl->agc_corr_coeff = MAX8614X_AGC_DEFAULT_CORRECTION_COEFF;
phonemacro 5:1f7b8cb07e26 506 led_ctrl->agc_min_num_samples = MAX8614X_AGC_DEFAULT_NUM_SAMPLES_TO_AVG;
phonemacro 5:1f7b8cb07e26 507 led_ctrl->agc_sensitivity_percent = MAX8614X_AGC_DEFAULT_SENSITIVITY_PERCENT;
phonemacro 5:1f7b8cb07e26 508 }
phonemacro 5:1f7b8cb07e26 509