Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/input/als.c
1476 views
1
/*
2
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
3
*
4
* Copyright (c) 2018 CTCaer
5
*
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms and conditions of the GNU General Public License,
8
* version 2, as published by the Free Software Foundation.
9
*
10
* This program is distributed in the hope it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
* more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include "als.h"
20
#include <power/max7762x.h>
21
#include <soc/clock.h>
22
#include <soc/i2c.h>
23
#include <soc/pinmux.h>
24
#include <utils/util.h>
25
26
#define BH1730_DEFAULT_GAIN BH1730_GAIN_64X
27
#define BH1730_DEFAULT_ICYCLE 38
28
29
#define BH1730_INTERNAL_CLOCK_NS 2800
30
#define BH1730_ADC_CALC_DELAY_US 2000 /* BH1730_INTERNAL_CLOCK_MS * 714 */
31
#define BH1730_ITIME_CYCLE_TO_US 2700 /* BH1730_INTERNAL_CLOCK_MS * 964 */
32
33
#define BH1730_DEFAULT_ITIME_MS 100
34
35
#define BH1730_LUX_MULTIPLIER 3600
36
#define BH1730_LUX_MULTIPLIER_AULA 1410
37
38
#define BH1730_LUX_MAX 100000
39
40
typedef struct _opt_win_cal_t
41
{
42
u32 rc;
43
u32 cv;
44
u32 ci;
45
} opt_win_cal_t;
46
47
// Nintendo Switch Icosa/Iowa Optical Window calibration.
48
static const opt_win_cal_t opt_win_cal_default[] = {
49
{ 500, 5002, 7502 },
50
{ 754, 2250, 2000 },
51
{ 1029, 1999, 1667 },
52
{ 1373, 884, 583 },
53
{ 1879, 309, 165 }
54
};
55
56
// Nintendo Switch Aula Optical Window calibration.
57
static const opt_win_cal_t opt_win_cal_aula[] = {
58
{ 231, 9697, 30300 },
59
{ 993, 3333, 2778 },
60
{ 1478, 1621, 1053 },
61
{ 7500, 81, 10 }
62
};
63
64
static const u32 als_gain_idx_tbl[4] = { 1, 2, 64, 128 };
65
66
void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle)
67
{
68
if (gain > BH1730_GAIN_128X)
69
gain = BH1730_GAIN_128X;
70
71
if (!cycle)
72
cycle = 1;
73
74
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain);
75
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle));
76
77
als_ctxt->gain = gain;
78
als_ctxt->cycle = cycle;
79
}
80
81
void get_als_lux(als_ctxt_t *als_ctxt)
82
{
83
u32 data[2];
84
u32 vi_light;
85
u32 ir_light;
86
u64 lux = 0;
87
u32 itime_us = BH1730_ITIME_CYCLE_TO_US * als_ctxt->cycle;
88
89
// Get visible and ir light raw data. Mode is continuous so waiting for new values doesn't matter.
90
data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) +
91
(i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8);
92
data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) +
93
(i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8);
94
95
vi_light = data[0];
96
ir_light = data[1];
97
98
als_ctxt->vi_light = vi_light;
99
als_ctxt->ir_light = ir_light;
100
als_ctxt->over_limit = vi_light > 65534 || ir_light > 65534;
101
102
if (!vi_light)
103
{
104
als_ctxt->lux = 0;
105
106
return;
107
}
108
109
// Set calibration parameters.
110
u32 lux_multiplier = BH1730_LUX_MULTIPLIER;
111
u32 opt_win_cal_count = ARRAY_SIZE(opt_win_cal_default);
112
const opt_win_cal_t *opt_win_cal = opt_win_cal_default;
113
114
// Apply optical window calibration coefficients.
115
for (u32 i = 0; i < opt_win_cal_count; i++)
116
{
117
if (1000 * ir_light / vi_light < opt_win_cal[i].rc)
118
{
119
lux = ((u64)opt_win_cal[i].cv * data[0]) - (opt_win_cal[i].ci * data[1]);
120
break;
121
}
122
}
123
124
lux *= BH1730_DEFAULT_ITIME_MS * lux_multiplier;
125
lux /= als_gain_idx_tbl[als_ctxt->gain] * itime_us;
126
lux /= 1000;
127
128
if (lux > BH1730_LUX_MAX)
129
lux = BH1730_LUX_MAX;
130
131
als_ctxt->lux = lux;
132
}
133
134
u8 als_power_on(als_ctxt_t *als_ctxt)
135
{
136
// Enable power to ALS IC.
137
max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000);
138
max7762x_regulator_enable(REGULATOR_LDO6, true);
139
140
// Init I2C2.
141
pinmux_config_i2c(I2C_2);
142
clock_enable_i2c(I2C_2);
143
i2c_init(I2C_2);
144
145
// Initialize ALS.
146
u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12));
147
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0);
148
149
set_als_cfg(als_ctxt, BH1730_DEFAULT_GAIN, BH1730_DEFAULT_ICYCLE);
150
151
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN);
152
153
return id;
154
}
155
156