static int faxgen_generate(struct cw_channel *chan, void *data, int samples) { int len; fax_state_t *fax; struct cw_frame outf; uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*CW_FRIENDLY_OFFSET]; uint8_t *buf = __buf + CW_FRIENDLY_OFFSET; fax = (fax_state_t*) data; samples = (samples <= MAX_BLOCK_SIZE) ? samples : MAX_BLOCK_SIZE; if ((len = fax_tx(fax, (int16_t *) &buf[CW_FRIENDLY_OFFSET], samples)) > 0) { cw_fr_init_ex(&outf, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "FAX"); outf.datalen = len*sizeof(int16_t); outf.samples = len; outf.data = &buf[CW_FRIENDLY_OFFSET]; outf.offset = CW_FRIENDLY_OFFSET; if (cw_write(chan, &outf) < 0) cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); } return 0; }
static int linear_generator(struct cw_channel *chan, void *data, int samples) { struct cw_frame f; short buf[2048 + CW_FRIENDLY_OFFSET / 2]; struct linear_state *ls = data; int res, len; len = samples*sizeof(int16_t); if (len > sizeof(buf) - CW_FRIENDLY_OFFSET) { cw_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len); len = sizeof(buf) - CW_FRIENDLY_OFFSET; } memset(&f, 0, sizeof(f)); res = read(ls->fd, buf + CW_FRIENDLY_OFFSET/2, len); if (res > 0) { cw_fr_init_ex(&f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, NULL); f.data = buf + CW_FRIENDLY_OFFSET/sizeof(int16_t); f.datalen = res; f.samples = res/sizeof(int16_t); f.offset = CW_FRIENDLY_OFFSET; cw_write(chan, &f); if (res == len) return 0; } return -1; }
static int cw_quickstart(struct cw_battery *cw_bat) { int ret = 0; u8 reg_val = MODE_QUICK_START; ret = cw_write(cw_bat->client, REG_MODE, ®_val); //(MODE_QUICK_START | MODE_NORMAL)); // 0x30 if(ret < 0) { dev_err(&cw_bat->client->dev, "Error quick start1\n"); return ret; } reg_val = MODE_NORMAL; ret = cw_write(cw_bat->client, REG_MODE, ®_val); if(ret < 0) { dev_err(&cw_bat->client->dev, "Error quick start2\n"); return ret; } return 1; }
static int playtones_generator(struct cw_channel *chan, void *data, int samples) { struct playtones_state *ps = data; struct playtones_item *pi; int len; int x; /* * We need to prepare a frame with 16 * timelen samples as we're * generating SLIN audio */ len = samples + samples; if (len > sizeof(ps->data)/sizeof(int16_t) - 1) { cw_log(LOG_WARNING, "Can't generate that much data!\n"); return -1; } x = tone_gen(&ps->tone_state, ps->data, samples); pi = &ps->items[ps->npos]; /* Assemble frame */ cw_fr_init_ex(&ps->f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, NULL); ps->f.datalen = len; ps->f.samples = samples; ps->f.offset = CW_FRIENDLY_OFFSET; ps->f.data = ps->data; cw_write(chan, &ps->f); ps->pos += x; if (pi->duration && ps->pos >= pi->duration*8) { /* item finished? */ ps->pos = 0; /* start new item */ ps->npos++; if (ps->npos >= ps->nitems) { /* last item */ if (ps->reppos == -1) /* repeat set? */ return -1; ps->npos = ps->reppos; /* redo from top */ } /* Prepare the tone generator for more */ pi = &ps->items[ps->npos]; tone_setup(ps, pi); } return 0; }
static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count) { struct cw_frame outf; struct cw_channel *chan; chan = (struct cw_channel *) user_data; cw_fr_init_ex(&outf, CW_FRAME_MODEM, CW_MODEM_T38, "FAX"); outf.datalen = len; outf.data = (char *) buf; outf.tx_copies = count; if (cw_write(chan, &outf) < 0) cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); return 0; }
int cw_dtmf_stream(struct cw_channel *chan,struct cw_channel *peer,char *digits,int between) { char *ptr; int res = 0; struct cw_frame f; if (!between) between = 100; if (peer) res = cw_autoservice_start(peer); if (!res) { res = cw_waitfor(chan,100); if (res > -1) { for (ptr=digits; *ptr; ptr++) { if (*ptr == 'w') { res = cw_safe_sleep(chan, 500); if (res) break; continue; } cw_fr_init_ex(&f, CW_FRAME_DTMF, *ptr, NULL); f.src = "cw_dtmf_stream"; if (strchr("0123456789*#abcdABCD",*ptr) == NULL) { cw_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr); } else { res = cw_write(chan, &f); if (res) break; /* pause between digits */ res = cw_safe_sleep(chan,between); if (res) break; } } } if (peer) res = cw_autoservice_stop(peer); } return res; }
// process outgoing frames for the channel, playing either normal conference audio, // or requested sounds static int process_outgoing( struct cw_conf_member *member, int samples ) { int res; struct cw_frame *cf = NULL; cw_mutex_lock(&member->lock); cf=get_outgoing_frame( member->conf, member, samples ) ; cw_mutex_unlock(&member->lock); /* cw_log(LOG_WARNING, "OURGen: samples %d - conf %s - speak: %d - format: %d\n", samples, member->chan->name, member->is_speaking , cf->frametype ); */ // if there's no frames exit the loop. if( cf == NULL ) { cw_log( LOG_ERROR, "Nothing to write to the conference, channel => %s\n", member->channel_name ) ; return 0; } // send the voice frame res = cw_write( member->chan, cf ); if ( ( res != 0) ) { // log 'dropped' outgoing frame cw_log( LOG_ERROR, "unable to write voice frame to channel, channel => %s, samples %d \n", member->channel_name, samples ) ; } // clean up frame cw_fr_free(cf); return 0; }
static int cw_get_alt(struct cw_battery *cw_bat) { int ret = 0; u8 reg_val; u8 value8 = 0; int alrt; ret = cw_read(cw_bat->client, REG_RRT_ALERT, ®_val); if (ret < 0) return ret; value8 = reg_val; alrt = value8 >>7; //dev_info(&cw_bat->client->dev, "read RRT %d%%. value16 0x%x\n", alrt, value16); value8 = value8&0x7f; reg_val = value8; ret = cw_write(cw_bat->client, REG_RRT_ALERT, ®_val); if(ret < 0) { dev_err(&cw_bat->client->dev, "Error clear ALRT\n"); return ret; } return alrt; }
static int pipe_exec(struct cw_channel *chan, int argc, char **argv) { int res=0; struct localuser *u; int fds[2]; int ms = -1; int pid = -1; int owriteformat; int oreadformat; int timeout = 2000; struct timeval last; struct cw_frame *f; struct myframe { struct cw_frame f; char offset[CW_FRIENDLY_OFFSET]; short frdata[160]; } myf; last.tv_usec = 0; last.tv_sec = 0; if (argc < 2 || argc > 3) { cw_log(LOG_ERROR, "Syntax: %s\n", pipe_syntax); return -1; } LOCAL_USER_ADD(u); if (pipe(fds)) { cw_log(LOG_WARNING, "Unable to create pipe\n"); LOCAL_USER_REMOVE(u); return -1; } // MOC: Setting non blocking doesn't seem to change anything // flags = fcntl(fds[1], F_GETFL); // fcntl(fds[1], F_SETFL, flags | O_NONBLOCK); // flags = fcntl(fds[0], F_GETFL); // fcntl(fds[0], F_SETFL, flags | O_NONBLOCK); cw_stopstream(chan); if (chan->_state != CW_STATE_UP) res = cw_answer(chan); if (res) { close(fds[0]); close(fds[1]); cw_log(LOG_WARNING, "Answer failed!\n"); LOCAL_USER_REMOVE(u); return -1; } oreadformat = chan->readformat; res = cw_set_read_format(chan, CW_FORMAT_SLINEAR); owriteformat = chan->writeformat; res += cw_set_write_format(chan, CW_FORMAT_SLINEAR); if (res < 0) { close(fds[0]); close(fds[1]); cw_log(LOG_WARNING, "Unable to set write format to signed linear\n"); LOCAL_USER_REMOVE(u); return -1; } res = pipeencode(argv[1], argv[2], fds[0], fds[1]); if (res >= 0) { last = cw_tvnow(); last.tv_sec += 1; pid = res; for (;;) { /* Wait for audio, and stream */ if (argv[0][0] == '0') { /* START WRITE TO FD */ ms = cw_waitfor(chan, 10); if (ms < 0) { cw_log(LOG_DEBUG, "Hangup detected\n"); res = -1; break; } else if (ms > 0) { f = cw_read(chan); if (!f) { cw_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == CW_FRAME_DTMF) { cw_log(LOG_DEBUG, "User pressed a key\n"); cw_fr_free(f); res = 0; break; } if (f->frametype == CW_FRAME_VOICE) { res = write(fds[1], f->data, f->datalen); if (res < 0) { if (errno != EAGAIN) { cw_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno)); cw_fr_free(f); res = -1; break; } } } cw_fr_free(f); } /* END WRITE TO FD */ } else { /* START WRITE CHANNEL */ ms = cw_tvdiff_ms(last, cw_tvnow()); if (ms <= 0) { res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout); if (res > 0) { cw_fr_init_ex(&myf.f, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, __PRETTY_FUNCTION__); myf.f.datalen = res; myf.f.samples = res/sizeof(int16_t); myf.f.offset = CW_FRIENDLY_OFFSET; myf.f.data = myf.frdata; if (cw_write(chan, &myf.f) < 0) { res = -1; break; } } else { cw_log(LOG_DEBUG, "No more stream\n"); res = 0; break; } last = cw_tvadd(last, cw_samp2tv(myf.f.samples, 8000)); } else { ms = cw_waitfor(chan, ms); if (ms < 0) { cw_log(LOG_DEBUG, "Hangup detected\n"); res = -1; break; } if (ms) { f = cw_read(chan); if (!f) { cw_log(LOG_DEBUG, "Null frame == hangup() detected\n"); res = -1; break; } if (f->frametype == CW_FRAME_DTMF) { cw_log(LOG_DEBUG, "User pressed a key\n"); cw_fr_free(f); res = 0; break; } cw_fr_free(f); } } /* END WRITE CHANNEL */ } } } close(fds[0]); close(fds[1]); LOCAL_USER_REMOVE(u); if (pid > -1) kill(pid, SIGKILL); if (!res && oreadformat) cw_set_read_format(chan, oreadformat); if (!res && owriteformat) cw_set_write_format(chan, owriteformat); return res; }
static int fax_audio(struct cw_channel *chan, fax_state_t *fax, const char *file, int calling_party, int verbose) { char *x; struct cw_frame *inf = NULL; struct cw_frame outf; int ready = 1; int samples = 0; int res = 0; int len = 0; int generator_mode = 0; uint64_t begin = 0; uint64_t received_frames = 0; uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*CW_FRIENDLY_OFFSET]; uint8_t *buf = __buf + CW_FRIENDLY_OFFSET; #if 0 struct cw_frame *dspf = NULL; struct cw_dsp *dsp = NULL; #endif uint64_t voice_frames; t30_state_t *t30; memset(fax, 0, sizeof(*fax)); if (fax_init(fax, calling_party) == NULL) { cw_log(LOG_WARNING, "Unable to start FAX\n"); return -1; } t30 = fax_get_t30_state(fax); fax_set_transmit_on_idle(fax, TRUE); span_log_set_message_handler(&fax->logging, span_message); span_log_set_message_handler(&t30->logging, span_message); if (verbose) { span_log_set_level(&fax->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); } fax_set_common(chan, t30, file, calling_party, verbose); fax_set_transmit_on_idle(fax, TRUE); if (calling_party) { voice_frames = 0; } else { #if 0 /* Initializing the DSP */ if ((dsp = cw_dsp_new()) == NULL) { cw_log(LOG_WARNING, "Unable to allocate DSP!\n"); } else { cw_dsp_set_threshold(dsp, 256); cw_dsp_set_features(dsp, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_CNG_DETECT); cw_dsp_digitmode(dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); } #endif voice_frames = 1; } /* This is the main loop */ begin = nowis(); while (ready && ready_to_talk(chan)) { if (chan->t38_status == T38_NEGOTIATED) break; if ((res = cw_waitfor(chan, 20)) < 0) { ready = 0; break; } if (!t30_call_active(t30)) break; if ((inf = cw_read(chan)) == NULL) { ready = 0; break; } /* We got a frame */ if (inf->frametype == CW_FRAME_VOICE) { #if 0 if (dsp) { if ((dspf = cw_frdup(inf))) dspf = cw_dsp_process(chan, dsp, dspf); if (dspf) { if (dspf->frametype == CW_FRAME_DTMF) { if (dspf->subclass == 'f') { cw_log(LOG_DEBUG, "Fax detected in RxFax !!!\n"); cw_app_request_t38(chan); /* Prevent any further attempts to negotiate T.38 */ cw_dsp_free(dsp); dsp = NULL; } } cw_fr_free(dspf); dspf = NULL; } } #else if (voice_frames) { /* Wait a little before trying to switch to T.38, as some things don't seem to like entirely missing the audio. */ if (++voice_frames == 100) { cw_log(LOG_DEBUG, "Requesting T.38 negotation in RxFax !!!\n"); cw_app_request_t38(chan); voice_frames = 0; } } #endif received_frames++; if (fax_rx(fax, inf->data, inf->samples)) break; samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE; if ((len = fax_tx(fax, (int16_t *) &buf[CW_FRIENDLY_OFFSET], samples)) > 0) { cw_fr_init_ex(&outf, CW_FRAME_VOICE, CW_FORMAT_SLINEAR, "FAX"); outf.datalen = len*sizeof(int16_t); outf.samples = len; outf.data = &buf[CW_FRIENDLY_OFFSET]; outf.offset = CW_FRIENDLY_OFFSET; if (cw_write(chan, &outf) < 0) { cw_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); break; } } } else { if ((nowis() - begin) > 1000000) { if (received_frames < 20) { /* Just to be sure we have had no frames ... */ cw_log(LOG_NOTICE, "Switching to generator mode\n"); generator_mode = 1; break; } } } cw_fr_free(inf); inf = NULL; } if (inf) { cw_fr_free(inf); inf = NULL; } if (generator_mode) { /* This is activated when we don't receive any frame for X seconds (see above)... */ cw_log(LOG_NOTICE, "Starting generator\n"); #if 0 if (dsp) cw_dsp_reset(dsp); #endif cw_generator_activate(chan, &faxgen, fax); while (ready && ready_to_talk(chan)) { if (chan->t38_status == T38_NEGOTIATED) break; if ((res = cw_waitfor(chan, 20)) < 0) { ready = 0; break; } if (!t30_call_active(t30)) break; if ((inf = cw_read(chan)) == NULL) { ready = 0; break; } /* We got a frame */ if (inf->frametype == CW_FRAME_VOICE) { #if 0 if (dsp) { if ((dspf = cw_frdup(inf))) dspf = cw_dsp_process(chan, dsp, dspf); if (dspf) { if (dspf->frametype == CW_FRAME_DTMF) { if (dspf->subclass == 'f') { cw_log(LOG_DEBUG, "Fax detected in RxFax !!!\n"); cw_app_request_t38(chan); /* Prevent any further attempts to negotiate T.38 */ cw_dsp_free(dsp); dsp = NULL; } } cw_fr_free(dspf); dspf = NULL; } } #else if (voice_frames) { if (++voice_frames == 100) { cw_log(LOG_DEBUG, "Requesting T.38 negotation in RxFax !!!\n"); cw_app_request_t38(chan); voice_frames = 0; } } #endif if (fax_rx(fax, inf->data, inf->samples)) { ready = 0; break; } } cw_fr_free(inf); inf = NULL; } if (inf) { cw_fr_free(inf); inf = NULL; } cw_log(LOG_NOTICE, "Stopping generator\n"); cw_generator_deactivate(chan); } #if 0 if (dsp) cw_dsp_free(dsp); #endif return ready; }
static int cw_get_capacity(struct cw_battery *cw_bat) { int cw_capacity; int ret; u8 reg_val[2]; struct timespec ts; long new_run_time; long new_sleep_time; long capacity_or_aconline_time; int allow_change; int allow_capacity; static int if_quickstart = 0; static int jump_flag =0; int charge_time; // ret = cw_read(cw_bat->client, REG_SOC, ®_val); ret = cw_read_word(cw_bat->client, REG_SOC, reg_val); if (ret < 0) return ret; cw_capacity = reg_val[0]; if ((cw_capacity < 0) || (cw_capacity > 100)) { dev_err(&cw_bat->client->dev, "get cw_capacity error; cw_capacity = %d\n", cw_capacity); return cw_capacity; } if (cw_capacity == 0) dev_dbg(&cw_bat->client->dev, "the cw201x capacity is 0 !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__); else dev_dbg(&cw_bat->client->dev, "the cw201x capacity is %d, funciton: %s\n", cw_capacity, __func__); // ret = cw_read(cw_bat->client, REG_SOC + 1, ®_val); ktime_get_ts(&ts); new_run_time = ts.tv_sec; get_monotonic_boottime(&ts); new_sleep_time = ts.tv_sec - new_run_time; if ((cw_bat->charger_mode > 0) && (cw_capacity >= 95) && (cw_capacity <= cw_bat->capacity)) { // avoid no charge full capacity_or_aconline_time = (cw_bat->sleep_time_capacity_change > cw_bat->sleep_time_charge_start) ? cw_bat->sleep_time_capacity_change : cw_bat->sleep_time_charge_start; capacity_or_aconline_time += (cw_bat->run_time_capacity_change > cw_bat->run_time_charge_start) ? cw_bat->run_time_capacity_change : cw_bat->run_time_charge_start; allow_change = (new_sleep_time + new_run_time - capacity_or_aconline_time) / BATTERY_UP_MAX_CHANGE; if (allow_change > 0) { allow_capacity = cw_bat->capacity + allow_change; cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100; jump_flag =1; } else if (cw_capacity <= cw_bat->capacity) { cw_capacity = cw_bat->capacity; } } else if (((cw_bat->charger_mode > 0) && (cw_capacity == (cw_bat->capacity - 1))) || ((cw_bat->charger_mode == 0) && (cw_capacity == (cw_bat->capacity + 1)))) { // modify battery level swing if (!(cw_capacity == 0 && cw_bat->capacity == 1)) { cw_capacity = cw_bat->capacity; } } else if ((cw_capacity == 0) && (cw_bat->capacity > 1)) { // avoid battery level jump to 0% at a moment from more than 2% allow_change = ((new_run_time - cw_bat->run_time_capacity_change) / BATTERY_DOWN_MIN_CHANGE_RUN); allow_change += ((new_sleep_time - cw_bat->sleep_time_capacity_change) / BATTERY_DOWN_MIN_CHANGE_SLEEP); allow_capacity = cw_bat->capacity - allow_change; cw_capacity = (allow_capacity >= cw_capacity) ? allow_capacity: cw_capacity; reg_val[0] = MODE_NORMAL; ret = cw_write(cw_bat->client, REG_MODE, reg_val); if (ret < 0) return ret; } else if ((cw_bat->charger_mode == 0) && (cw_capacity <= cw_bat->capacity ) && (cw_capacity >= 90) && (jump_flag == 1)) { // avoid battery level jump to CW_BAT capacity_or_aconline_time = (cw_bat->sleep_time_capacity_change > cw_bat->sleep_time_charge_start) ? cw_bat->sleep_time_capacity_change : cw_bat->sleep_time_charge_start; capacity_or_aconline_time += (cw_bat->run_time_capacity_change > cw_bat->run_time_charge_start) ? cw_bat->run_time_capacity_change : cw_bat->run_time_charge_start; allow_change = (new_sleep_time + new_run_time - capacity_or_aconline_time) / BATTERY_DOWN_CHANGE; if (allow_change > 0) { allow_capacity = cw_bat->capacity - allow_change; if (cw_capacity >= allow_capacity){ jump_flag =0; } else{ cw_capacity = (allow_capacity <= 100) ? allow_capacity : 100; } } else if (cw_capacity <= cw_bat->capacity) { cw_capacity = cw_bat->capacity; } } #if 1 if((cw_bat->charger_mode > 0) &&(cw_capacity == 0)) { charge_time = new_sleep_time + new_run_time - cw_bat->sleep_time_charge_start - cw_bat->run_time_charge_start; if ((charge_time > BATTERY_DOWN_MAX_CHANGE_RUN_AC_ONLINE) && (if_quickstart == 0)) { cw_quickstart(cw_bat); // if the cw_capacity = 0 the cw2015 will qstrt if_quickstart = 1; } } else if ((if_quickstart == 1)&&(cw_bat->charger_mode == 0)) { if_quickstart = 0; } #endif #if 0 if (cw_bat->plat_data->chg_ok_pin != INVALID_GPIO) { if(gpio_get_value(cw_bat->plat_data->chg_ok_pin) != cw_bat->plat_data->chg_ok_level) { if (cw_capacity == 100) { cw_capacity = 99; } } else { if (cw_bat->charger_mode > 0) { cw_capacity = 100; } } } #endif #ifdef SYSTEM_SHUTDOWN_VOLTAGE if ((cw_bat->charger_mode == 0) && (cw_capacity <= 10) && (cw_bat->voltage <= SYSTEM_SHUTDOWN_VOLTAGE)){ if (if_quickstart == 10){ cw_quickstart(cw_bat); if_quickstart = 12; cw_capacity = 0; } else if (if_quickstart <= 10) if_quickstart =if_quickstart+2; dev_info(&cw_bat->client->dev, "the cw201x voltage is less than SYSTEM_SHUTDOWN_VOLTAGE !!!!!!!, funciton: %s, line: %d\n", __func__, __LINE__); } else if ((cw_bat->charger_mode > 0)&& (if_quickstart <= 12)) { if_quickstart = 0; } #endif return cw_capacity; }
static int cw_init(struct cw_battery *cw_bat) { int ret; int i; u8 reg_val = MODE_SLEEP; #if 0 ret = cw_read(cw_bat->client, REG_MODE, ®_val); if (ret < 0) return ret; #endif if ((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) { reg_val = MODE_NORMAL; ret = cw_write(cw_bat->client, REG_MODE, ®_val); if (ret < 0) return ret; } ret = cw_read(cw_bat->client, REG_CONFIG, ®_val); if (ret < 0) return ret; if ((reg_val & 0xf8) != ATHD) { dev_info(&cw_bat->client->dev, "the new ATHD have not set\n"); reg_val &= 0x07; /* clear ATHD */ reg_val |= ATHD; /* set ATHD */ ret = cw_write(cw_bat->client, REG_CONFIG, ®_val); if (ret < 0) return ret; } ret = cw_read(cw_bat->client, REG_CONFIG, ®_val); if (ret < 0) return ret; if (!(reg_val & CONFIG_UPDATE_FLG)) { dev_info(&cw_bat->client->dev, "update flag for new battery info have not set\n"); ret = cw_update_config_info(cw_bat); if (ret < 0) return ret; } else { for(i = 0; i < SIZE_BATINFO; i++) { ret = cw_read(cw_bat->client, (REG_BATINFO + i), ®_val); if (ret < 0) return ret; if (cw_bat->plat_data->cw_bat_config_info[i] != reg_val) break; } if (i != SIZE_BATINFO) { dev_info(&cw_bat->client->dev, "update flag for new battery info have not set\n"); ret = cw_update_config_info(cw_bat); if (ret < 0) return ret; } } for (i = 0; i < 30; i++) { ret = cw_read(cw_bat->client, REG_SOC, ®_val); if (ret < 0) return ret; else if (ret != 0xff) break; msleep(100); if (i > 25) dev_err(&cw_bat->client->dev, "cw2015/cw2013 input unvalid power error\n"); } return 0; }
static int cw_update_config_info(struct cw_battery *cw_bat) { int ret; u8 reg_val; int i; u8 reset_val; dev_info(&cw_bat->client->dev, "func: %s-------\n", __func__); /* make sure no in sleep mode */ ret = cw_read(cw_bat->client, REG_MODE, ®_val); if (ret < 0) return ret; reset_val = reg_val; if((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) { dev_err(&cw_bat->client->dev, "Error, device in sleep mode, cannot update battery info\n"); return -1; } /* update new battery info */ for (i = 0; i < SIZE_BATINFO; i++) { dev_info(&cw_bat->client->dev, "cw_bat->plat_data->cw_bat_config_info[%d] = 0x%x\n", i, \ cw_bat->plat_data->cw_bat_config_info[i]); ret = cw_write(cw_bat->client, REG_BATINFO + i, &cw_bat->plat_data->cw_bat_config_info[i]); if (ret < 0) return ret; } /* readback & check */ for (i = 0; i < SIZE_BATINFO; i++) { ret = cw_read(cw_bat->client, REG_BATINFO + i, ®_val); if (reg_val != cw_bat->plat_data->cw_bat_config_info[i]) return -1; } /* set cw2015/cw2013 to use new battery info */ ret = cw_read(cw_bat->client, REG_CONFIG, ®_val); if (ret < 0) return ret; reg_val |= CONFIG_UPDATE_FLG; /* set UPDATE_FLAG */ reg_val &= 0x07; /* clear ATHD */ reg_val |= ATHD; /* set ATHD */ ret = cw_write(cw_bat->client, REG_CONFIG, ®_val); if (ret < 0) return ret; /* check 2015/cw2013 for ATHD & update_flag */ ret = cw_read(cw_bat->client, REG_CONFIG, ®_val); if (ret < 0) return ret; if (!(reg_val & CONFIG_UPDATE_FLG)) { dev_info(&cw_bat->client->dev, "update flag for new battery info have not set..\n"); } if ((reg_val & 0xf8) != ATHD) { dev_info(&cw_bat->client->dev, "the new ATHD have not set..\n"); } /* reset */ reset_val &= ~(MODE_RESTART); reg_val = reset_val | MODE_RESTART; ret = cw_write(cw_bat->client, REG_MODE, ®_val); if (ret < 0) return ret; msleep(10); ret = cw_write(cw_bat->client, REG_MODE, &reset_val); if (ret < 0) return ret; return 0; }