Software APIs
leds.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/lib/boards/teacup_v1_3_0/leds.h"
6 
7 #include "sw/device/lib/base/status.h"
10 #include "sw/device/lib/testing/i2c_testutils.h"
11 
12 static const size_t kDefaultI2cReadTimeoutMicros = 1000;
13 
14 status_t leds_read_ctrl_reg(const dif_i2c_t *i2c, uint8_t reg_addr,
15  uint8_t *data_out) {
16  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr, /*byte_count=*/1, &reg_addr,
17  /*skip_stop=*/false));
18  TRY(i2c_testutils_read(i2c, kLedsDriverI2cAddr, /*byte_count=*/1, data_out,
19  kDefaultI2cReadTimeoutMicros));
20  return OK_STATUS();
21 }
22 
23 status_t leds_set_color(const dif_i2c_t *i2c, teacup_led_t led,
24  led_rgb_color_t color) {
25  // Get register addresses for desired LED.
26  uint8_t b_pwm_low_reg;
27  uint8_t r_pwm_low_reg;
28  uint8_t g_pwm_low_reg;
29  switch (led) {
30  case kTeacupLedDs5:
31  b_pwm_low_reg = kLedBlue0LowRegAddr;
32  r_pwm_low_reg = kLedRed0LowRegAddr;
33  g_pwm_low_reg = kLedGreen0LowRegAddr;
34  break;
35  case kTeacupLedDs9:
36  b_pwm_low_reg = kLedBlue1LowRegAddr;
37  r_pwm_low_reg = kLedRed1LowRegAddr;
38  g_pwm_low_reg = kLedGreen1LowRegAddr;
39  break;
40  case kTeacupLedDs10:
41  b_pwm_low_reg = kLedBlue2LowRegAddr;
42  r_pwm_low_reg = kLedRed2LowRegAddr;
43  g_pwm_low_reg = kLedGreen2LowRegAddr;
44  break;
45  case kTeacupLedDs11:
46  b_pwm_low_reg = kLedBlue3LowRegAddr;
47  r_pwm_low_reg = kLedRed3LowRegAddr;
48  g_pwm_low_reg = kLedGreen3LowRegAddr;
49  break;
50  default:
51  return INTERNAL();
52  }
53 
54  // Set PWM duty cycle for each color channel of the specified LED.
55  // Blue
56  uint8_t blue_data[2] = {b_pwm_low_reg, color.b};
57  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr,
58  /*byte_count=*/sizeof(blue_data), blue_data,
59  /*skip_stop=*/false));
60  // Red
61  uint8_t red_data[2] = {r_pwm_low_reg, color.r};
62  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr,
63  /*byte_count=*/sizeof(red_data), red_data,
64  /*skip_stop=*/false));
65  // Green
66  uint8_t green_data[2] = {g_pwm_low_reg, color.g};
67  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr,
68  /*byte_count=*/sizeof(green_data), green_data,
69  /*skip_stop=*/false));
70 
71  // Activate PWM configurations.
72  uint8_t data[2] = {kLedUpdateRegAddr, 0};
73  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr, /*byte_count=*/sizeof(data),
74  data,
75  /*skip_stop=*/false));
76 
77  return OK_STATUS();
78 }
79 
80 status_t leds_set_all_brightness(const dif_i2c_t *i2c, uint8_t brightness) {
81  uint8_t data[2] = {kLedGlobalCurrentControlRegAddr, brightness};
82  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr, /*byte_count=*/sizeof(data),
83  data,
84  /*skip_stop=*/false));
85  return OK_STATUS();
86 }
87 
88 status_t leds_i2c_controller_configure(const dif_i2c_t *i2c) {
89  // Set control register to 0x0 to enable:
90  // - Software shutdown mode (keep LEDs off until explicitly turned on)
91  // - 8-bit (PWM resolution)
92  // - 16MHz (max oscillator clock frequency)
93  uint8_t data[2] = {kLedsControlRegAddr, 0};
94  uint8_t reg_val = 0;
95  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr, /*byte_count=*/sizeof(data),
96  data,
97  /*skip_stop=*/false));
98  TRY(leds_read_ctrl_reg(i2c, kLedsControlRegAddr, &reg_val));
99  LOG_INFO("Control Reg = 0x%02x", reg_val);
100 
101  // Set global current control to ~30%.
102  data[0] = kLedGlobalCurrentControlRegAddr;
103  data[1] = (uint8_t)((float)0xFF * 30.0 / 100.0);
104  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr, /*byte_count=*/sizeof(data),
105  data,
106  /*skip_stop=*/false));
107  TRY(leds_read_ctrl_reg(i2c, kLedGlobalCurrentControlRegAddr, &reg_val));
108  LOG_INFO("Global Current Control Reg = 0x%02x", reg_val);
109 
110  // Set each PWM channel's current control to 100%.
111  data[0] = kLedChannel0ScalingRegAddr;
112  data[1] = 0xFF;
113  for (size_t i = 0; i < 12; ++i) {
114  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr,
115  /*byte_count=*/sizeof(data), data,
116  /*skip_stop=*/false));
117  TRY(leds_read_ctrl_reg(i2c, data[0], &reg_val));
118  LOG_INFO("LED Channel %d Scaling Reg = 0x%02x", i, reg_val);
119  data[0]++;
120  }
121 
122  return OK_STATUS();
123 }
124 
125 status_t leds_turn_all_off(const dif_i2c_t *i2c) {
126  LOG_INFO("Turning off LEDs via software shutdown bit ...");
127  uint8_t ctrl_reg_val = 0;
128  TRY(leds_read_ctrl_reg(i2c, kLedsControlRegAddr, &ctrl_reg_val));
129  uint8_t data[2] = {kLedsControlRegAddr, ctrl_reg_val & ~0x1};
130  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr, /*byte_count=*/sizeof(data),
131  data,
132  /*skip_stop=*/false));
133  return OK_STATUS();
134 }
135 
136 status_t leds_turn_all_on(const dif_i2c_t *i2c) {
137  LOG_INFO("Turning on LEDs via software shutdown bit ...");
138  uint8_t ctrl_reg_val = 0;
139  TRY(leds_read_ctrl_reg(i2c, kLedsControlRegAddr, &ctrl_reg_val));
140  uint8_t data[2] = {kLedsControlRegAddr, ctrl_reg_val | 0x1};
141  TRY(i2c_testutils_write(i2c, kLedsDriverI2cAddr, /*byte_count=*/sizeof(data),
142  data,
143  /*skip_stop=*/false));
144  return OK_STATUS();
145 }