#include #include #include "io_expander.h" static struct ioexp_obj_s *ioexp_head_p = NULL; static struct ioexp_obj_s *ioexp_tail_p = NULL; struct ioexp_map_s ioexp_map_cypress_nabc = { .chip_amount = 3, .data_width = 2, .map_present = { {0, 0, 4}, /* map_present[0] = MOD_ABS_PORT(X) */ {0, 0, 5}, /* map_present[1] = MOD_ABS_PORT(X+1) */ {0, 0, 6}, /* map_present[2] = MOD_ABS_PORT(X+2) */ {0, 0, 7}, /* map_present[3] = MOD_ABS_PORT(X+3) */ {1, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ {1, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ {1, 0, 6}, /* map_present[6] = MOD_ABS_PORT(X+6) */ {1, 0, 7}, /* map_present[7] = MOD_ABS_PORT(X+7) */ }, .map_tx_disable = { {0, 1, 0}, /* map_tx_disable[0] = TXDISABLE_SFP+_P(X) */ {0, 1, 1}, /* map_tx_disable[1] = TXDISABLE_SFP+_P(X+1) */ {0, 1, 2}, /* map_tx_disable[2] = TXDISABLE_SFP+_P(X+2) */ {0, 1, 3}, /* map_tx_disable[3] = TXDISABLE_SFP+_P(X+3) */ {1, 1, 0}, /* map_tx_disable[4] = TXDISABLE_SFP+_P(X+4) */ {1, 1, 1}, /* map_tx_disable[5] = TXDISABLE_SFP+_P(X+5) */ {1, 1, 2}, /* map_tx_disable[6] = TXDISABLE_SFP+_P(X+6) */ {1, 1, 3}, /* map_tx_disable[7] = TXDISABLE_SFP+_P(X+7) */ }, .map_tx_fault = { {0, 0, 0}, /* map_tx_fault[0] = TXFAULT_SFP+_P(X) */ {0, 0, 1}, /* map_tx_fault[1] = TXFAULT_SFP+_P(X+1) */ {0, 0, 2}, /* map_tx_fault[2] = TXFAULT_SFP+_P(X+2) */ {0, 0, 3}, /* map_tx_fault[3] = TXFAULT_SFP+_P(X+3) */ {1, 0, 0}, /* map_tx_fault[4] = TXFAULT_SFP+_P(X+4) */ {1, 0, 1}, /* map_tx_fault[5] = TXFAULT_SFP+_P(X+5) */ {1, 0, 2}, /* map_tx_fault[6] = TXFAULT_SFP+_P(X+6) */ {1, 0, 3}, /* map_tx_fault[7] = TXFAULT_SFP+_P(X+7) */ }, .map_rxlos = { {0, 1, 4}, /* map_rxlos[0] = OPRXLOS_PORT(X) */ {0, 1, 5}, /* map_rxlos[1] = OPRXLOS_PORT(X+1) */ {0, 1, 6}, /* map_rxlos[2] = OPRXLOS_PORT(X+2) */ {0, 1, 7}, /* map_rxlos[3] = OPRXLOS_PORT(X+3) */ {1, 1, 4}, /* map_rxlos[4] = OPRXLOS_PORT(X+4) */ {1, 1, 5}, /* map_rxlos[5] = OPRXLOS_PORT(X+5) */ {1, 1, 6}, /* map_rxlos[6] = OPRXLOS_PORT(X+6) */ {1, 1, 7}, /* map_rxlos[7] = OPRXLOS_PORT(X+7) */ }, }; struct ioexp_map_s ioexp_map_cypress_7abc = { .chip_amount = 3, .data_width = 2, .map_present = { {2, 0, 0}, /* map_present[0] = MOD_ABS_PORT(X) */ {2, 0, 1}, /* map_present[1] = MOD_ABS_PORT(X+1) */ {2, 0, 2}, /* map_present[2] = MOD_ABS_PORT(X+2) */ {2, 0, 3}, /* map_present[3] = MOD_ABS_PORT(X+3) */ {2, 0, 4}, /* map_present[4] = MOD_ABS_PORT(X+4) */ {2, 0, 5}, /* map_present[5] = MOD_ABS_PORT(X+5) */ }, .map_reset = { {0, 0, 0}, /* map_reset[0] = QRESET_QSFP_N_P(X) */ {0, 0, 1}, /* map_reset[1] = QRESET_QSFP_N_P(X+1) */ {0, 0, 2}, /* map_reset[2] = QRESET_QSFP_N_P(X+2) */ {0, 0, 3}, /* map_reset[3] = QRESET_QSFP_N_P(X+3) */ {0, 0, 4}, /* map_reset[4] = QRESET_QSFP_N_P(X+4) */ {0, 0, 5}, /* map_reset[5] = QRESET_QSFP_N_P(X+5) */ }, .map_lpmod = { {0, 1, 0}, /* map_lpmod[0] = LPMODE_QSFP_P(X) */ {0, 1, 1}, /* map_lpmod[1] = LPMODE_QSFP_P(X+1) */ {0, 1, 2}, /* map_lpmod[2] = LPMODE_QSFP_P(X+2) */ {0, 1, 3}, /* map_lpmod[3] = LPMODE_QSFP_P(X+3) */ {0, 1, 4}, /* map_lpmod[4] = LPMODE_QSFP_P(X+4) */ {0, 1, 5}, /* map_lpmod[5] = LPMODE_QSFP_P(X+5) */ }, .map_modsel = { {1, 1, 0}, /* map_modsel[0] = MODSEL_QSFP_N_P(X) */ {1, 1, 1}, /* map_modsel[1] = MODSEL_QSFP_N_P(X+1) */ {1, 1, 2}, /* map_modsel[2] = MODSEL_QSFP_N_P(X+2) */ {1, 1, 3}, /* map_modsel[3] = MODSEL_QSFP_N_P(X+3) */ {1, 1, 4}, /* map_modsel[4] = MODSEL_QSFP_N_P(X+4) */ {1, 1, 5}, /* map_modsel[5] = MODSEL_QSFP_N_P(X+5) */ }, }; /* ========== Private functions ========== */ int check_channel_tier_1(void); struct i2c_client * _get_i2c_client(struct ioexp_obj_s *self, int chip_id){ struct ioexp_i2c_s *i2c_curr_p = self->i2c_head_p; if (!(i2c_curr_p)){ SWPS_ERR("%s: i2c_curr_p is NULL\n", __func__); return NULL; } while (i2c_curr_p){ if ((i2c_curr_p->chip_id) == chip_id){ return i2c_curr_p->i2c_client_p; } i2c_curr_p = i2c_curr_p->next; } SWPS_ERR("%s: not exist! :%d\n", __func__, chip_id); return NULL; } static int _common_ioexp_update_one(struct ioexp_obj_s *self, struct ioexp_addr_s *ioexp_addr, int chip_id, int data_width, int show_err, char *caller_name) { int buf = 0; int err = 0; int data_id = 0; int r_offset = 0; for(data_id=0; data_idread_offset[data_id]; buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), r_offset); /* Check error */ if (buf < 0) { err = 1; if (show_err) { SWPS_INFO("IOEXP-%d read fail! :%d \n", self->ioexp_id, buf); SWPS_INFO("Dump: :%d :0x%02x :%d, :%s\n", ioexp_addr->chan_id, ioexp_addr->chip_addr, ioexp_addr->read_offset[data_id], caller_name); } continue; } /* Update IOEXP object */ self->chip_data[chip_id].data[data_id] = (uint8_t)buf; } if (err) { return ERR_IOEXP_UNEXCPT; } return 0; } static int common_ioexp_update_all(struct ioexp_obj_s *self, int show_err, char *caller_name){ int err = 0; int chip_id = 0; int chip_amount = self->ioexp_map_p->chip_amount; for (chip_id=0; chip_idioexp_map_p->map_addr[chip_id]), chip_id, self->ioexp_map_p->data_width, show_err, caller_name) < 0) { err = 1; } } if (err) { return ERR_IOEXP_UNEXCPT; } return 0; } static int _common_get_bit(struct ioexp_obj_s *self, struct ioexp_bitmap_s *bitmap_obj_p, char *func_mane){ uint8_t buf; int err_code; /* Get address */ err_code = self->fsm_4_direct(self); if (err_code < 0){ return err_code; } if (!bitmap_obj_p){ SWPS_ERR("Layout config incorrect! :%d :%s\n", self->ioexp_id, func_mane); return ERR_IOEXP_BADCONF; } /* Get data form cache */ buf = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset]; return (int)(buf >> bitmap_obj_p->bit_shift & 0x01); } static int _common_set_bit(struct ioexp_obj_s *self, struct ioexp_bitmap_s *bitmap_obj_p, int input_val, char *func_mane){ int err_code, target_offset; uint8_t origin_byte; uint8_t modify_byte; /* Get address */ err_code = self->fsm_4_direct(self); if (err_code < 0){ return err_code; } if (!bitmap_obj_p){ SWPS_ERR("Layout config incorrect! :%d :%s\n", self->ioexp_id, func_mane); return ERR_IOEXP_BADCONF; } /* Prepare write date */ origin_byte = self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset]; switch (input_val) { case 0: modify_byte = origin_byte; SWP_BIT_CLEAR(modify_byte, bitmap_obj_p->bit_shift); break; case 1: modify_byte = origin_byte; SWP_BIT_SET(modify_byte, bitmap_obj_p->bit_shift); break; default: SWPS_ERR("Input value incorrect! :%d :%d :%s\n", input_val, self->ioexp_id, func_mane); return ERR_IOEXP_BADINPUT; } /* Setup i2c client */ target_offset = self->ioexp_map_p->map_addr[bitmap_obj_p->chip_id].write_offset[bitmap_obj_p->ioexp_voffset]; /* Write byte to chip via I2C */ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, bitmap_obj_p->chip_id), target_offset, modify_byte); /* Update or bollback object */ if (err_code < 0){ self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = origin_byte; SWPS_ERR("I2C write fail! :%d :%d :%s :%d\n", input_val, self->ioexp_id, func_mane, err_code); return err_code; } self->chip_data[bitmap_obj_p->chip_id].data[bitmap_obj_p->ioexp_voffset] = modify_byte; return 0; } /* ========== Object public functions ========== */ int common_get_present(struct ioexp_obj_s *self, int virt_offset){ int UNPLUG = 1; int retval = ERR_IOEXP_UNEXCPT; retval = _common_get_bit(self, &(self->ioexp_map_p->map_present[virt_offset]), "common_get_present"); if (retval < 0) { /* [Note] * => Transceiver object does not need to handle IOEXP layer issues. */ return UNPLUG; } return retval; } int common_get_tx_fault(struct ioexp_obj_s *self, int virt_offset){ return _common_get_bit(self, &(self->ioexp_map_p->map_tx_fault[virt_offset]), "common_get_tx_fault"); } int common_get_rxlos(struct ioexp_obj_s *self, int virt_offset){ /* [Receiver Loss of Signal (Rx_LOS)] * The post-amplification IC also includes transition detection circuitry * which monitors the ac level of incoming optical signals and provides a * TTL/CMOS compatible status signal to the host (pin 8). An adequate optical * input results in a low Rx_LOS output while a high Rx_LOS output indicates * an unusable optical input. The Rx_LOS thresholds are factory set so that * a high output indicates a definite optical fault has occurred. Rx_LOS can * also be monitored via the two-wire serial interface * (address A2h, byte 110, bit 1). * * 0: Normal * 1: Abnormal */ return _common_get_bit(self, &(self->ioexp_map_p->map_rxlos[virt_offset]), "common_get_rxlos"); } int common_get_tx_disable(struct ioexp_obj_s *self, int virt_offset){ return _common_get_bit(self, &(self->ioexp_map_p->map_tx_disable[virt_offset]), "common_get_tx_disable"); } int common_get_reset(struct ioexp_obj_s *self, int virt_offset){ return _common_get_bit(self, &(self->ioexp_map_p->map_reset[virt_offset]), "common_get_reset"); } int common_get_lpmod(struct ioexp_obj_s *self, int virt_offset){ return _common_get_bit(self, &(self->ioexp_map_p->map_lpmod[virt_offset]), "common_get_lpmod"); } int common_get_modsel(struct ioexp_obj_s *self, int virt_offset){ return _common_get_bit(self, &(self->ioexp_map_p->map_modsel[virt_offset]), "common_get_modsel"); } int common_set_tx_disable(struct ioexp_obj_s *self, int virt_offset, int input_val){ return _common_set_bit(self, &(self->ioexp_map_p->map_tx_disable[virt_offset]), input_val, "common_set_tx_disable"); } int common_set_reset(struct ioexp_obj_s *self, int virt_offset, int input_val){ return _common_set_bit(self, &(self->ioexp_map_p->map_reset[virt_offset]), input_val, "common_set_reset"); } int common_set_lpmod(struct ioexp_obj_s *self, int virt_offset, int input_val){ return _common_set_bit(self, &(self->ioexp_map_p->map_lpmod[virt_offset]), input_val, "common_set_lpmod"); } int common_set_modsel(struct ioexp_obj_s *self, int virt_offset, int input_val){ return _common_set_bit(self, &(self->ioexp_map_p->map_modsel[virt_offset]), input_val, "common_set_modsel"); } int ioexp_get_not_support(struct ioexp_obj_s *self, int virt_offset){ return ERR_IOEXP_NOTSUPPORT; } int ioexp_set_not_support(struct ioexp_obj_s *self, int virt_offset, int input_val){ return ERR_IOEXP_NOTSUPPORT; } /* ========== Initial functions for IO Expander ========== */ int common_ioexp_init(struct ioexp_obj_s *self) { int chip_id, offset, err_code; struct ioexp_addr_s *addr_p; if (self->mode == IOEXP_MODE_DIRECT) { ///important goto update_common_ioexp_init; } /* Setup default value to each physical IO Expander */ for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ /* Get address mapping */ addr_p = &(self->ioexp_map_p->map_addr[chip_id]); if (!addr_p){ SWPS_ERR("%s: IOEXP config incorrect! :%d \n", __func__, chip_id); return -1; } /* Setup default value */ for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id), addr_p->write_offset[offset], addr_p->data_default[offset]); if (err_code < 0){ SWPS_ERR("%s: set default fail! :%d \n", __func__, err_code); return ERR_IOEXP_UNEXCPT; } } } update_common_ioexp_init: /* Check and update info to object */ err_code = self->update_all(self, 1, "common_ioexp_init"); if (err_code < 0) { SWPS_ERR("%s: update_all() fail! :%d \n", __func__, err_code); return ERR_IOEXP_UNEXCPT; } return 0; } /* ========== Object functions for Final State Machine ========== */ int _is_channel_ready(struct ioexp_obj_s *self){ int buf = 0; int chip_id = 0; /* Use first chip which be registered */ int data_id = 0; /* Use first byte which be registered */ struct ioexp_addr_s *ioexp_addr = NULL; ioexp_addr = &(self->ioexp_map_p->map_addr[chip_id]); if (!ioexp_addr){ SWPS_ERR("%s: config incorrect!\n", __func__); return ERR_IOEXP_UNEXCPT; } buf = i2c_smbus_read_byte_data(_get_i2c_client(self, chip_id), ioexp_addr->read_offset[data_id]); if (buf >= 0){ return 1; } return 0; } int _ioexp_init_handler(struct ioexp_obj_s *self){ int return_val; switch (self->mode) { case IOEXP_MODE_DIRECT: return_val = self->init(self); if (return_val < 0){ self->state = STATE_IOEXP_ABNORMAL; } else { self->state = STATE_IOEXP_NORMAL; } return return_val; default: break; } SWPS_ERR("%s: exception occur :%d\n", __func__, self->mode); return ERR_IOEXP_UNEXCPT; } int common_ioexp_fsm_4_direct(struct ioexp_obj_s *self){ int result_val; int show_err = 1; char *func_mane = "common_ioexp_fsm_4_direct"; switch (self->state){ case STATE_IOEXP_INIT: result_val = _ioexp_init_handler(self); /* Exception case: terminate initial procedure */ if(result_val < 0){ /* Initial fail */ return result_val; } if(self->state == STATE_IOEXP_INIT){ /* Keep in INIT state, and return error */ return ERR_IOEXP_UNINIT; } /* Case: Initial done */ return 0; case STATE_IOEXP_NORMAL: result_val = self->update_all(self, show_err, func_mane); if (result_val < 0){ SWPS_INFO("%s: NORMAL -> ABNORMAL :%d\n", __func__, result_val); self->state = STATE_IOEXP_ABNORMAL; return result_val; } self->state = STATE_IOEXP_NORMAL; return 0; case STATE_IOEXP_ABNORMAL: result_val = self->update_all(self, show_err, func_mane); if (result_val < 0){ self->state = STATE_IOEXP_ABNORMAL; return result_val; } SWPS_DEBUG("%s: ABNORMAL -> NORMAL :%d\n", __func__, result_val); self->state = STATE_IOEXP_NORMAL; return 0; default: break; } SWPS_ERR("%s: Exception occurs :%d\n", __func__, self->state); return ERR_IOEXP_UNEXCPT; } /* ========== Functions for Factory pattern ========== */ static struct ioexp_map_s * get_ioexp_map(int ioexp_type){ switch (ioexp_type){ case IOEXP_TYPE_CYPRESS_NABC: return &ioexp_map_cypress_nabc; case IOEXP_TYPE_CYPRESS_7ABC: return &ioexp_map_cypress_7abc; default: return NULL; } } int setup_ioexp_ssize_attr(struct ioexp_obj_s *self, struct ioexp_map_s *ioexp_map_p, int ioexp_id, int ioexp_type, int run_mode){ switch (run_mode){ case IOEXP_MODE_DIRECT: /* Direct access device mode */ self->mode = run_mode; break; default: SWPS_ERR("%s: non-defined run_mode:%d\n", __func__, run_mode); self->mode = ERR_IOEXP_UNEXCPT; return ERR_IOEXP_UNEXCPT; } self->ioexp_id = ioexp_id; self->ioexp_type = ioexp_type; self->ioexp_map_p = ioexp_map_p; self->state = STATE_IOEXP_INIT; mutex_init(&self->lock); return 0; } static int setup_addr_mapping(struct ioexp_obj_s *self, struct ioexp_addr_s *addr_map_p){ if (!addr_map_p){ SWPS_ERR("%s: map is null\n", __func__); return -1; } self->ioexp_map_p->map_addr = addr_map_p; return 0; } static int setup_ioexp_public_cb(struct ioexp_obj_s *self, int ioexp_type){ switch (ioexp_type){ case IOEXP_TYPE_CYPRESS_NABC: self->get_present = common_get_present; self->get_tx_fault = common_get_tx_fault; self->get_rxlos = common_get_rxlos; self->get_tx_disable = common_get_tx_disable; self->get_reset = ioexp_get_not_support; self->get_lpmod = ioexp_get_not_support; self->get_modsel = ioexp_get_not_support; self->set_tx_disable = common_set_tx_disable; self->set_reset = ioexp_set_not_support; self->set_lpmod = ioexp_set_not_support; self->set_modsel = ioexp_set_not_support; return 0; case IOEXP_TYPE_CYPRESS_7ABC: self->get_present = common_get_present; self->get_tx_fault = ioexp_get_not_support; self->get_rxlos = ioexp_get_not_support; self->get_tx_disable = ioexp_get_not_support; self->get_reset = common_get_reset; self->get_lpmod = common_get_lpmod; self->get_modsel = common_get_modsel; self->set_tx_disable = ioexp_set_not_support; self->set_reset = common_set_reset; self->set_lpmod = common_set_lpmod; self->set_modsel = common_set_modsel; return 0; default: SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type); break; } return ERR_IOEXP_UNEXCPT; } static int setup_ioexp_private_cb(struct ioexp_obj_s *self, int ioexp_type){ switch (ioexp_type){ case IOEXP_TYPE_CYPRESS_NABC: case IOEXP_TYPE_CYPRESS_7ABC: self->init = common_ioexp_init; self->update_all = common_ioexp_update_all; self->fsm_4_direct = common_ioexp_fsm_4_direct; return 0; default: SWPS_ERR("%s: type:%d incorrect!\n", __func__, ioexp_type); break; } return ERR_IOEXP_UNEXCPT; } static int setup_i2c_client_one(struct ioexp_obj_s *self, int chip_id){ char *err_msg = "ERROR"; struct i2c_adapter *adap = NULL; struct i2c_client *client = NULL; struct ioexp_i2c_s *i2c_obj_p = NULL; struct ioexp_i2c_s *i2c_curr_p = NULL; int chan_id = self->ioexp_map_p->map_addr[chip_id].chan_id; adap = i2c_get_adapter(chan_id); if(!adap){ err_msg = "Can not get adap!"; goto err_ioexp_setup_i2c_1; } client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client){ err_msg = "Can not kzalloc client!"; goto err_ioexp_setup_i2c_1; } i2c_obj_p = kzalloc(sizeof(*i2c_obj_p), GFP_KERNEL); if (!i2c_obj_p){ err_msg = "Can not kzalloc i2c_obj_p!"; goto err_ioexp_setup_i2c_2; } client->adapter = adap; client->addr = self->ioexp_map_p->map_addr[chip_id].chip_addr; i2c_obj_p->i2c_client_p = client; i2c_obj_p->chip_id = chip_id; i2c_obj_p->next = NULL; if (!self->i2c_head_p){ self->i2c_head_p = i2c_obj_p; } else { i2c_curr_p = self->i2c_head_p; while (i2c_curr_p->next){ i2c_curr_p = i2c_curr_p->next; } i2c_curr_p->next = i2c_obj_p; } return 0; err_ioexp_setup_i2c_2: kfree(client); err_ioexp_setup_i2c_1: SWPS_ERR("%s: %s :%d\n", __func__, err_msg, chan_id); return -1; } static int setup_i2c_client(struct ioexp_obj_s* self){ int result; int chip_id = 0; for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ result = setup_i2c_client_one(self, chip_id); if (result < 0){ SWPS_ERR("%s fail! :%d\n", __func__, chip_id); return -1; } } return 0; } static int setup_ioexp_config(struct ioexp_obj_s *self) { int chip_id, offset, err_code; struct ioexp_addr_s *addr_p; for (chip_id=0; chip_id<(self->ioexp_map_p->chip_amount); chip_id++){ addr_p = &(self->ioexp_map_p->map_addr[chip_id]); if (!addr_p){ SWPS_ERR("IOEXP config incorrect! :%d \n",chip_id); return -1; } for (offset=0; offset<(self->ioexp_map_p->data_width); offset++){ err_code = i2c_smbus_write_byte_data(_get_i2c_client(self, chip_id), addr_p->conf_offset[offset], addr_p->conf_default[offset]); if (err_code < 0){ SWPS_INFO("%s: set conf fail! :%d \n", __func__, err_code); return -2; } } } return 0; } struct ioexp_obj_s * _create_ioexp_obj(int ioexp_id, int ioexp_type, struct ioexp_addr_s *addr_map_p, int run_mode){ struct ioexp_map_s* ioexp_map_p; struct ioexp_obj_s* result_p; struct ioexp_i2c_s *i2c_curr_p; struct ioexp_i2c_s *i2c_next_p; /* Get layout */ ioexp_map_p = get_ioexp_map(ioexp_type); if (!ioexp_map_p){ SWPS_ERR("%s: Invalid ioexp_type\n", __func__); goto err_create_ioexp_fail; } /* Prepare IOEXP object */ result_p = kzalloc(sizeof(*result_p), GFP_KERNEL); if (!result_p){ SWPS_ERR("%s: kzalloc failure!\n", __func__); goto err_create_ioexp_fail; } /* Prepare static size attributes */ if (setup_ioexp_ssize_attr(result_p, ioexp_map_p, ioexp_id, ioexp_type, run_mode) < 0){ goto err_create_ioexp_setup_attr_fail; } /* Prepare address mapping */ if (setup_addr_mapping(result_p, addr_map_p) < 0){ goto err_create_ioexp_setup_attr_fail; } if (setup_i2c_client(result_p) < 0){ goto err_create_ioexp_setup_i2c_fail; } /* Prepare call back functions of object */ if (setup_ioexp_public_cb(result_p, ioexp_type) < 0){ goto err_create_ioexp_setup_i2c_fail; } if (setup_ioexp_private_cb(result_p, ioexp_type) < 0){ goto err_create_ioexp_setup_i2c_fail; } return result_p; err_create_ioexp_setup_i2c_fail: i2c_curr_p = result_p->i2c_head_p; i2c_next_p = result_p->i2c_head_p; while (i2c_curr_p){ i2c_next_p = i2c_curr_p->next; kfree(i2c_curr_p->i2c_client_p); kfree(i2c_curr_p); i2c_curr_p = i2c_next_p; } err_create_ioexp_setup_attr_fail: kfree(result_p); err_create_ioexp_fail: SWPS_ERR("%s: fail! :%d :%d \n", __func__, ioexp_id, ioexp_type); return NULL; } int create_ioexp_obj(int ioexp_id, int ioexp_type, struct ioexp_addr_s *addr_map_p, int run_mode){ struct ioexp_obj_s *ioexp_p = NULL; ioexp_p = _create_ioexp_obj(ioexp_id, ioexp_type, addr_map_p, run_mode); if (!ioexp_p){ return -1; } if (ioexp_head_p == NULL){ ioexp_head_p = ioexp_p; ioexp_tail_p = ioexp_p; return 0; } ioexp_tail_p->next = ioexp_p; ioexp_tail_p = ioexp_p; return 0; } static int _init_ioexp_obj(struct ioexp_obj_s* self) { char *err_msg = "ERR"; char *func_name = "_init_ioexp_obj"; /* Setup IOEXP configure byte */ if (setup_ioexp_config(self) < 0){ err_msg = "setup_ioexp_config fail"; goto err_init_ioexp_obj; } /* Setup default data */ if (_ioexp_init_handler(self) < 0){ err_msg = "_ioexp_init_handler fail"; goto err_init_ioexp_obj; } /* Update all */ if (self->state == STATE_IOEXP_NORMAL){ if (self->update_all(self, 1, func_name) < 0){ err_msg = "update_all() fail"; goto err_init_ioexp_obj; } } return 0; err_init_ioexp_obj: SWPS_DEBUG("%s: %s\n", __func__, err_msg); return -1; } int init_ioexp_objs(void){ /* Return value: * 0: Success * -1: Detect topology error * -2: SWPS internal error */ struct ioexp_obj_s *curr_p = ioexp_head_p; if (!curr_p) { SWPS_ERR("%s: ioexp_head_p is NULL\n", __func__); return -2; } while (curr_p) { if (_init_ioexp_obj(curr_p) < 0) { SWPS_DEBUG("%s: _init_ioexp_obj() fail\n", __func__); return -1; } curr_p = curr_p->next; } SWPS_DEBUG("%s: done.\n", __func__); return 0; } void clean_ioexp_objs(void){ struct ioexp_i2c_s *i2c_curr_p = NULL; struct ioexp_i2c_s *i2c_next_p = NULL; struct ioexp_obj_s *ioexp_next_p = NULL; struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p; if (ioexp_head_p == NULL){ ioexp_tail_p = NULL; return; } while(ioexp_curr_p){ ioexp_next_p = ioexp_curr_p->next; i2c_curr_p = ioexp_curr_p->i2c_head_p; while (i2c_curr_p) { i2c_next_p = i2c_curr_p->next; kfree(i2c_curr_p->i2c_client_p); kfree(i2c_curr_p); i2c_curr_p = i2c_next_p; } kfree(ioexp_curr_p); ioexp_curr_p = ioexp_next_p; } ioexp_tail_p = NULL; SWPS_DEBUG("%s: done.\n", __func__); } struct ioexp_obj_s * get_ioexp_obj(int ioexp_id){ struct ioexp_obj_s *result_p = NULL; struct ioexp_obj_s *ioexp_curr_p = ioexp_head_p; while(ioexp_curr_p){ if (ioexp_curr_p->ioexp_id == ioexp_id){ result_p = ioexp_curr_p; break; } ioexp_curr_p = ioexp_curr_p->next; } return result_p; } int check_channel_tier_1(void) { if ( (!_is_channel_ready(ioexp_head_p)) && (!_is_channel_ready(ioexp_tail_p)) ){ return -1; } return 0; }