1*1cdd9412SStefan Roese /* 2*1cdd9412SStefan Roese * Copyright (C) 2015 Stefan Roese <sr@denx.de> 3*1cdd9412SStefan Roese * 4*1cdd9412SStefan Roese * SPDX-License-Identifier: GPL-2.0+ 5*1cdd9412SStefan Roese */ 6*1cdd9412SStefan Roese 7*1cdd9412SStefan Roese #include <common.h> 8*1cdd9412SStefan Roese #include <errno.h> 9*1cdd9412SStefan Roese #include <i2c.h> 10*1cdd9412SStefan Roese 11*1cdd9412SStefan Roese #ifndef CONFIG_PCA9551_I2C_ADDR 12*1cdd9412SStefan Roese #error "CONFIG_PCA9551_I2C_ADDR not defined!" 13*1cdd9412SStefan Roese #endif 14*1cdd9412SStefan Roese 15*1cdd9412SStefan Roese #define PCA9551_REG_INPUT 0x00 /* Input register (read only) */ 16*1cdd9412SStefan Roese #define PCA9551_REG_PSC0 0x01 /* Frequency prescaler 0 */ 17*1cdd9412SStefan Roese #define PCA9551_REG_PWM0 0x02 /* PWM0 */ 18*1cdd9412SStefan Roese #define PCA9551_REG_PSC1 0x03 /* Frequency prescaler 1 */ 19*1cdd9412SStefan Roese #define PCA9551_REG_PWM1 0x04 /* PWM1 */ 20*1cdd9412SStefan Roese #define PCA9551_REG_LS0 0x05 /* LED0 to LED3 selector */ 21*1cdd9412SStefan Roese #define PCA9551_REG_LS1 0x06 /* LED4 to LED7 selector */ 22*1cdd9412SStefan Roese 23*1cdd9412SStefan Roese #define PCA9551_CTRL_AI (1 << 4) /* Auto-increment flag */ 24*1cdd9412SStefan Roese 25*1cdd9412SStefan Roese #define PCA9551_LED_STATE_ON 0x00 26*1cdd9412SStefan Roese #define PCA9551_LED_STATE_OFF 0x01 27*1cdd9412SStefan Roese #define PCA9551_LED_STATE_BLINK0 0x02 28*1cdd9412SStefan Roese #define PCA9551_LED_STATE_BLINK1 0x03 29*1cdd9412SStefan Roese 30*1cdd9412SStefan Roese struct pca9551_blink_rate { 31*1cdd9412SStefan Roese u8 psc; /* Frequency preescaler, see PCA9551_7.pdf p. 6 */ 32*1cdd9412SStefan Roese u8 pwm; /* Pulse width modulation, see PCA9551_7.pdf p. 6 */ 33*1cdd9412SStefan Roese }; 34*1cdd9412SStefan Roese 35*1cdd9412SStefan Roese static int freq0, freq1; 36*1cdd9412SStefan Roese 37*1cdd9412SStefan Roese static int pca9551_led_get_state(int led, int *state) 38*1cdd9412SStefan Roese { 39*1cdd9412SStefan Roese unsigned int reg; 40*1cdd9412SStefan Roese u8 shift, buf; 41*1cdd9412SStefan Roese int ret; 42*1cdd9412SStefan Roese 43*1cdd9412SStefan Roese if (led < 0 || led > 7) { 44*1cdd9412SStefan Roese return -EINVAL; 45*1cdd9412SStefan Roese } else if (led < 4) { 46*1cdd9412SStefan Roese reg = PCA9551_REG_LS0; 47*1cdd9412SStefan Roese shift = led << 1; 48*1cdd9412SStefan Roese } else { 49*1cdd9412SStefan Roese reg = PCA9551_REG_LS1; 50*1cdd9412SStefan Roese shift = (led - 4) << 1; 51*1cdd9412SStefan Roese } 52*1cdd9412SStefan Roese 53*1cdd9412SStefan Roese ret = i2c_read(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); 54*1cdd9412SStefan Roese if (ret) 55*1cdd9412SStefan Roese return ret; 56*1cdd9412SStefan Roese 57*1cdd9412SStefan Roese *state = (buf >> shift) & 0x03; 58*1cdd9412SStefan Roese return 0; 59*1cdd9412SStefan Roese } 60*1cdd9412SStefan Roese 61*1cdd9412SStefan Roese static int pca9551_led_set_state(int led, int state) 62*1cdd9412SStefan Roese { 63*1cdd9412SStefan Roese unsigned int reg; 64*1cdd9412SStefan Roese u8 shift, buf, mask; 65*1cdd9412SStefan Roese int ret; 66*1cdd9412SStefan Roese 67*1cdd9412SStefan Roese if (led < 0 || led > 7) { 68*1cdd9412SStefan Roese return -EINVAL; 69*1cdd9412SStefan Roese } else if (led < 4) { 70*1cdd9412SStefan Roese reg = PCA9551_REG_LS0; 71*1cdd9412SStefan Roese shift = led << 1; 72*1cdd9412SStefan Roese } else { 73*1cdd9412SStefan Roese reg = PCA9551_REG_LS1; 74*1cdd9412SStefan Roese shift = (led - 4) << 1; 75*1cdd9412SStefan Roese } 76*1cdd9412SStefan Roese mask = 0x03 << shift; 77*1cdd9412SStefan Roese 78*1cdd9412SStefan Roese ret = i2c_read(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); 79*1cdd9412SStefan Roese if (ret) 80*1cdd9412SStefan Roese return ret; 81*1cdd9412SStefan Roese 82*1cdd9412SStefan Roese buf = (buf & ~mask) | ((state & 0x03) << shift); 83*1cdd9412SStefan Roese 84*1cdd9412SStefan Roese ret = i2c_write(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); 85*1cdd9412SStefan Roese if (ret) 86*1cdd9412SStefan Roese return ret; 87*1cdd9412SStefan Roese 88*1cdd9412SStefan Roese return 0; 89*1cdd9412SStefan Roese } 90*1cdd9412SStefan Roese 91*1cdd9412SStefan Roese static int pca9551_led_set_blink_rate(int idx, struct pca9551_blink_rate rate) 92*1cdd9412SStefan Roese { 93*1cdd9412SStefan Roese unsigned int reg; 94*1cdd9412SStefan Roese int ret; 95*1cdd9412SStefan Roese 96*1cdd9412SStefan Roese switch (idx) { 97*1cdd9412SStefan Roese case 0: 98*1cdd9412SStefan Roese reg = PCA9551_REG_PSC0; 99*1cdd9412SStefan Roese break; 100*1cdd9412SStefan Roese case 1: 101*1cdd9412SStefan Roese reg = PCA9551_REG_PSC1; 102*1cdd9412SStefan Roese break; 103*1cdd9412SStefan Roese default: 104*1cdd9412SStefan Roese return -EINVAL; 105*1cdd9412SStefan Roese } 106*1cdd9412SStefan Roese reg |= PCA9551_CTRL_AI; 107*1cdd9412SStefan Roese 108*1cdd9412SStefan Roese ret = i2c_write(CONFIG_PCA9551_I2C_ADDR, reg, 1, (u8 *)&rate, 2); 109*1cdd9412SStefan Roese if (ret) 110*1cdd9412SStefan Roese return ret; 111*1cdd9412SStefan Roese 112*1cdd9412SStefan Roese return 0; 113*1cdd9412SStefan Roese } 114*1cdd9412SStefan Roese 115*1cdd9412SStefan Roese /* 116*1cdd9412SStefan Roese * Functions referenced by cmd_led.c 117*1cdd9412SStefan Roese */ 118*1cdd9412SStefan Roese void __led_set(led_id_t mask, int state) 119*1cdd9412SStefan Roese { 120*1cdd9412SStefan Roese if (state == STATUS_LED_OFF) 121*1cdd9412SStefan Roese pca9551_led_set_state(mask, PCA9551_LED_STATE_OFF); 122*1cdd9412SStefan Roese else 123*1cdd9412SStefan Roese pca9551_led_set_state(mask, PCA9551_LED_STATE_ON); 124*1cdd9412SStefan Roese } 125*1cdd9412SStefan Roese 126*1cdd9412SStefan Roese void __led_toggle(led_id_t mask) 127*1cdd9412SStefan Roese { 128*1cdd9412SStefan Roese int state = 0; 129*1cdd9412SStefan Roese 130*1cdd9412SStefan Roese pca9551_led_get_state(mask, &state); 131*1cdd9412SStefan Roese pca9551_led_set_state(mask, !state); 132*1cdd9412SStefan Roese } 133*1cdd9412SStefan Roese 134*1cdd9412SStefan Roese void __led_blink(led_id_t mask, int freq) 135*1cdd9412SStefan Roese { 136*1cdd9412SStefan Roese struct pca9551_blink_rate rate; 137*1cdd9412SStefan Roese int mode; 138*1cdd9412SStefan Roese int blink; 139*1cdd9412SStefan Roese 140*1cdd9412SStefan Roese if ((freq0 == 0) || (freq == freq0)) { 141*1cdd9412SStefan Roese blink = 0; 142*1cdd9412SStefan Roese mode = PCA9551_LED_STATE_BLINK0; 143*1cdd9412SStefan Roese freq0 = freq; 144*1cdd9412SStefan Roese } else { 145*1cdd9412SStefan Roese blink = 1; 146*1cdd9412SStefan Roese mode = PCA9551_LED_STATE_BLINK1; 147*1cdd9412SStefan Roese freq1 = freq; 148*1cdd9412SStefan Roese } 149*1cdd9412SStefan Roese 150*1cdd9412SStefan Roese rate.psc = ((freq * 38) / 1000) - 1; 151*1cdd9412SStefan Roese rate.pwm = 128; /* 50% duty cycle */ 152*1cdd9412SStefan Roese 153*1cdd9412SStefan Roese pca9551_led_set_blink_rate(blink, rate); 154*1cdd9412SStefan Roese pca9551_led_set_state(mask, mode); 155*1cdd9412SStefan Roese } 156