// // Copyright (C) 2010 Andy Pugh // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // #include "rtapi_math.h" #include <linux/slab.h> #include "hal/drivers/mesa-hostmot2/hostmot2.h" /****************/ int hm2_8i20_create(hostmot2_t *hm2, hm2_module_descriptor_t *md) { int i,c,r; int n; for (i = 0 ; i < hm2->sserial.num_instances ; i++) { hm2_sserial_instance_t *inst = &hm2->sserial.instance[i]; if (inst->num_8i20 == 0) continue; inst->hal_8i20 = (hal_8i20_t *)hal_malloc(inst->num_8i20 * sizeof(hal_8i20_t)); if (inst->hal_8i20 == NULL) { HM2_ERR("out of memory!\n"); r = -ENOMEM; return r; } inst->tram_8i20 = (hm2_sserial_tram_t *)kmalloc(inst->num_8i20 * sizeof(hm2_sserial_tram_t), GFP_KERNEL); if (inst->tram_8i20 == NULL) { HM2_ERR("out of memory!\n"); r = -ENOMEM; return r; } n = -1; for (c = 0 ; c < inst->num_channels ; c++ ) { hal_8i20_t *hal; hm2_sserial_tram_t *tram; if (inst->tag_8i20 & (1 << c)) { n++; hal = &hm2->sserial.instance[i].hal_8i20[n]; tram = &hm2->sserial.instance[i].tram_8i20[n]; tram->index = c; tram->reg_command_addr = inst->command_reg_addr; tram->reg_data_addr= inst->data_reg_addr; r = hal_pin_float_newf(HAL_IN, &(hal->pin.hm2_phase_angle), hm2->llio->comp_id,"%s.8i20.%1d.%1d.angle", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding pin %s.8i20.%1d.%1d.angle. aborting\n", hm2->llio->name, inst->module_index, c); return r; } r = hal_pin_float_newf(HAL_IN, &(hal->pin.hm2_current), hm2->llio->comp_id, "%s.8i20.%1d.%1d.current", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding pin %s.8i20.%1d.%1d.current. aborting\n", hm2->llio->name, inst->module_index, c); return r; } r = hal_pin_float_newf(HAL_OUT, &(hal->pin.hm2_bus_voltage), hm2->llio->comp_id, "%s.8i20.%1d.%1d.voltage", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding pin %s.8i20.%1d.%1d.voltage. aborting\n", hm2->llio->name, inst->module_index, c); return r; } r = hal_pin_float_newf(HAL_OUT, &(hal->pin.hm2_card_temp), hm2->llio->comp_id, "%s.8i20.%1d.%1d.temp", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding pin %s.8i20.%1d.%1d.temp. aborting\n", hm2->llio->name, inst->module_index, c); return r; } r = hal_pin_u32_newf(HAL_OUT, &(hal->pin.hm2_fault), hm2->llio->comp_id, "%s.8i20.%1d.%1d.fault", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding pin %s.8i20.%1d.%1d.fault. aborting\n", hm2->llio->name, inst->module_index, c); return r; } r = hal_pin_u32_newf(HAL_OUT, &(hal->pin.hm2_status), hm2->llio->comp_id, "%s.8i20.%1d.%1d.status", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding pin %s.8i20.%1d.%1d.status. aborting\n", hm2->llio->name, inst->module_index, c); return r; } r = hal_pin_u32_newf(HAL_OUT, &(hal->pin.hm2_comms), hm2->llio->comp_id, "%s.8i20.%1d.%1d.comms", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding pin %s.8i20.%1d.%1d.comms. aborting\n", hm2->llio->name, inst->module_index, c); return r; } r = hal_pin_bit_newf(HAL_IN, &(hal->pin.enable), hm2->llio->comp_id, "%s.8i20.%1d.%1d.amp_enable", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding pin %s.8i20.%1d.%1d.amp_enable. aborting\n", hm2->llio->name, inst->module_index, c); return r; } // Create Parameters (normal mode) r = hal_param_float_newf(HAL_RW, &(hal->param.hm2_max_current), hm2->llio->comp_id, "%s.8i20.%1d.%1d.max_current", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding parameter %s.8i20.%1d.%1d.max_current." "aborting\n", hm2->llio->name, inst->module_index, c); return r; } r = hal_param_u32_newf(HAL_RW, &(hal->param.hm2_serialnumber), hm2->llio->comp_id, "%s.8i20.%1d.%1d.serial_number", hm2->llio->name, inst->module_index, c); if (r < 0) { HM2_ERR("error adding parameter %s.8i20.%1d.%1d.serial_" "number. aborting\n",hm2->llio->name, inst->module_index, c); return r; } // Register the TRAM values and store the register addresses for // other functions to use // Use tram_read in all modes, but only tram_write in normal mode. tram->reg_cs_addr = md->base_address + 2 * md->register_stride + inst->module_index * md->instance_stride + c * sizeof(u32); r = hm2_register_tram_read_region(hm2, tram->reg_cs_addr, sizeof(u32), &tram->reg_cs_read); if (r < 0) { HM2_ERR("error registering tram read region for sserial CS" "register (%d)\n", r); return r; } tram->reg_0_addr = md->base_address + 3 * md->register_stride + inst->module_index * md->instance_stride + c * sizeof(u32); r = hm2_register_tram_read_region(hm2, tram->reg_0_addr, sizeof(u32), &tram->reg_0_read); if (r < 0) { HM2_ERR("error registering tram read region for sserial " "interface 0 register (%d)\n", r); return r; } tram->reg_1_addr = md->base_address + 4 * md->register_stride + inst->module_index * md->instance_stride + c * sizeof(u32); r = hm2_register_tram_read_region(hm2, tram->reg_1_addr, sizeof(u32), &tram->reg_1_read); if (r < 0) { HM2_ERR("error registering tram read region for sserial " "interface 1 register (%d)\n", r); return r; } r = hm2_register_tram_write_region(hm2, tram->reg_0_addr, sizeof(u32), &(tram->reg_0_write)); if (r < 0) { HM2_ERR("error registering tram write region for sserial" "interface 0 register (%d)\n", r); return r; } } } } return 0; } void hm2_8i20_prepare_tram_write(hostmot2_t *hm2){ int i; int c; u32 angle_lim; double norm_current; const float i_const = 32767; const float a_const = 65535; for (i = 0 ; i < hm2->sserial.num_instances ; i++){ hm2_sserial_instance_t *inst = &hm2->sserial.instance[i]; if (*inst->state != 0x01) continue ; // Only work on running instances for (c = 0 ; c < hm2->sserial.instance[i].num_8i20 ; c++){ hal_8i20_t *hal = &inst->hal_8i20[c]; hm2_sserial_tram_t *tram = &inst->tram_8i20[c]; if (hal->param.hm2_max_current > hal->param.hm2_nv_max_current) { HM2_ERR("8i20 %X EEPROM Max Curent is %f.\n You asked for %f." "Resetting to EEPROM max.\n", hal->param.hm2_serialnumber, hal->param.hm2_nv_max_current, hal->param.hm2_max_current); hal->param.hm2_max_current = hal->param.hm2_nv_max_current; } if (hal->param.hm2_max_current < 0){ HM2_ERR("8i20 minimum setting for max_current parameter is zero." "Resetting to zero\n"); hal->param.hm2_max_current = 0; } angle_lim = ((u32)(*hal->pin.hm2_phase_angle * a_const)) & 0x0000FFFF; if (*hal->pin.hm2_current > 1.0) {*hal->pin.hm2_current = 1.0;} else if (*hal->pin.hm2_current < -1.0){*hal->pin.hm2_current = -1;} norm_current = *hal->pin.hm2_current * hal->param.hm2_max_current / hal->param.hm2_nv_max_current * i_const; if (*hal->pin.enable) { *tram->reg_0_write = ((int)(norm_current) << 16) | angle_lim; } else { *tram->reg_0_write = 0x00000000; } } } } void hm2_8i20_process_tram_read(hostmot2_t *hm2){ int i; int c; for (i = 0 ; i < hm2->sserial.num_instances ; i++){ hm2_sserial_instance_t *inst = &hm2->sserial.instance[i]; if (*inst->state != 0x01) continue ; // Only work on running instances for (c = 0 ; c < hm2->sserial.instance[i].num_8i20 ; c++){ hal_8i20_t *hal = &inst->hal_8i20[c]; hm2_sserial_tram_t *tram = &inst->tram_8i20[c]; *hal->pin.hm2_comms = *tram->reg_cs_read; *hal->pin.hm2_card_temp=(hal_float_t)(*tram->reg_0_read & 0xFFFF); *hal->pin.hm2_bus_voltage= (hal_float_t)((*tram->reg_0_read & 0xFFFF0000) >> 16) * 0.01; *hal->pin.hm2_fault = (*tram->reg_1_read & 0xFFFF0000) >> 16; *hal->pin.hm2_status= *tram->reg_1_read & 0x0000FFFF; } } } int hm2_8i20_params(hostmot2_t *hm2){ int i, c, buff; for (i = 0 ; i < hm2->sserial.num_instances ; i++) { hm2_sserial_instance_t *inst = &hm2->sserial.instance[i]; if (hm2->sserial.instance[i].num_8i20 > 0) { for (c = 0 ; c < hm2->sserial.instance[i].num_8i20 ; c++) { hal_8i20_t *hal = &inst->hal_8i20[c]; hm2_sserial_tram_t *tram = &inst->tram_8i20[c]; hm2->llio->read(hm2->llio, tram->reg_0_addr, &buff, sizeof(u32)); hal->param.hm2_serialnumber = buff; buff = hm2_sserial_get_param(hm2, tram, 0x8E8); hal->param.hm2_nv_max_current = buff * 0.01; hal->param.hm2_max_current = buff * 0.01; } } } return 0; } void hm2_8i20_setmode(hostmot2_t *hm2, hm2_sserial_instance_t *inst){ u32 buff=0x00; u32 addr; int c; int n = 0; int i = inst->module_index; for (c = 0 ; c < inst->num_8i20 ; c++){ n = inst->tram_8i20[c].index; if (hm2->config.sserial_modes[i][n] != 'x') { // CS addr - write card mode addr = inst->tram_8i20[c].reg_cs_addr; buff = (hm2->config.sserial_modes[i][n] - '0') << 24; hm2->llio->write(hm2->llio, addr, &buff, sizeof(u32)); } } } int hm2_sserial_8i20_check(hostmot2_t *hm2, hm2_sserial_instance_t *inst){ int c; int err_flag = 0; for (c = 0 ; c < inst->num_8i20 ; c++){ hm2_sserial_tram_t *tram=&inst->tram_8i20[c]; if ( hm2_sserial_check_errors(hm2, tram)) {err_flag = -EINVAL;} } return err_flag; } void hm2_sserial_8i20_cleanup(hostmot2_t *hm2){ int i; for (i = 1 ; i < hm2->sserial.num_instances; i++){ if (hm2->sserial.instance[i].tram_8i20 != NULL){ kfree(hm2->sserial.instance[i].tram_8i20); } } }