/** * find_free_channel - finds an empty channel for conversion * * If the ADC is not enabled then start using 0th channel * itself. Otherwise find an empty channel by looking for a * channel in which the stopbit is set to 1. returns the index * of the first free channel if succeeds or an error code. * * Context: can sleep * * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc * code. */ static int find_free_channel(void) { int ret; int i; uint8_t data; /* check whether ADC is enabled */ ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); if (ret) return ret; if ((data & MSIC_ADC_ENBL) == 0) return 0; /* ADC is already enabled; Looking for an empty channel */ for (i = 0; i < ADC_CHANLS_MAX; i++) { ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data); if (ret) return ret; if (data & MSIC_STOPBIT_MASK) { ret = i; break; } } return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret; }
static void led_enable_set(u16 reg, int value) { int ret; uint8_t ctrldata; LED_INFO("%s, reg=0x%X, value=%d\n", __func__, reg, value); /* set bit ALTFUNCEN = 0 */ ret = intel_scu_ipc_ioread8(CHGDETGPO_REG, &ctrldata); if (ret) { LED_ERR(" IPC Failed to read %d\n", ret); } ctrldata &= ~(BIT(6)); ret = intel_scu_ipc_iowrite8(CHGDETGPO_REG, ctrldata); if (ret) { LED_ERR(" IPC Failed to write %d\n", ret); } ret = intel_scu_ipc_ioread8(reg, &ctrldata); if (ret) { LED_ERR(" IPC Failed to read %d\n", ret); } if (value) ctrldata |= (BIT(5)|BIT(4)|BIT(0)); else ctrldata &= ~(BIT(5)|BIT(4)|BIT(0)); ret = intel_scu_ipc_iowrite8(reg, ctrldata); if (ret) { LED_ERR(" IPC Failed to write %d\n", ret); } power_on_flag = value; }
static void __vpro2_power_ctrl(bool on) { u8 value, addr = MSIC_VPROG2_MRFLD_CTRL; int ret = 0xFF; uint8_t pmic_id = 0; ret = intel_scu_ipc_ioread8(PMIC_ID_ADDR, &pmic_id); if (!ret) { if (PMIC_CHIP_ID_B0_VAL == pmic_id) addr = MSIC_B0_VPROG2_MRFLD_CTRL; if (intel_scu_ipc_ioread8(addr, &value)) DRM_ERROR("%s: %d: failed to read vPro2\n", __func__, __LINE__); /* Control vPROG2 power rail with 2.85v. */ if (on) value |= 0x1; else value &= ~0x1; if (intel_scu_ipc_iowrite8(addr, value)) DRM_ERROR("%s: %d: failed to write vPro2\n",__func__, __LINE__); } else { DRM_ERROR("%s: %d: failed to read pmic id \n",__func__, __LINE__); } }
static int msic_gpio_get(struct gpio_chip *chip, unsigned offset) { struct msic_gpio *mg = &msic_gpio; u8 value; int ret; u16 ctlo, ctli, reg; ctlo = offset < mg->ngpio_lv ? mg->gpio0_lv_ctlo + offset : mg->gpio0_hv_ctlo + (offset - mg->ngpio_lv); ctli = offset < mg->ngpio_lv ? mg->gpio0_lv_ctli + offset : mg->gpio0_hv_ctli + (offset - mg->ngpio_lv); /* First get pin direction */ ret = intel_scu_ipc_ioread8(ctlo, &value); if (ret) return -EIO; /* The pin values for output and input direction * are stored in different registers. */ reg = (value & CTLO_DIR_O) ? ctlo : ctli; ret = intel_scu_ipc_ioread8(reg, &value); if (ret) return -EIO; return value & CTL_VALUE_MASK; }
/** * msic_probe */ static int __devinit msic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct drm_device *dev = hdmi_priv ? hdmi_priv->dev : NULL; int ret = 0; if (dev) PSB_DEBUG_ENTRY("\n"); /* enable msic hdmi device */ ret = pci_enable_device(pdev); if (!ret) { if (pdev->device == MSIC_PCI_DEVICE_ID) { sram_vreg_addr = ioremap_nocache(SRAM_MSIC_VRINT_ADDR, 0x2); ret = request_irq(pdev->irq, msic_vreg_handler, IRQF_SHARED, "msic_hdmi_driver",(void *)&hdmi_priv); } else DRM_ERROR("%s: pciid = 0x%x is not msic_hdmi pciid. \n", __FUNCTION__, pdev->device); if (!ret) { #if 0 /* #ifdef CONFIG_X86_MRST may still be necessary*/ u8 data = 0; /* clear HDMI HPD */ intel_scu_ipc_ioread8(MSIC_VRINT_STATUS, &data); intel_scu_ipc_iowrite8(MSIC_VRINT_STATUS, data); /* clear MSIC first level VREG interrupt. */ intel_scu_ipc_ioread8(MSIC_IRQLVL1_STATUS, &data); data &= VREG_STATUS; intel_scu_ipc_iowrite8(MSIC_IRQLVL1_STATUS, data); /* enable HDMI HPD */ intel_scu_ipc_ioread8(MSIC_VRINT_MASK, &data); data &= ~HDMI_HPD_MASK; intel_scu_ipc_iowrite8(MSIC_VRINT_MASK, data); /* enable MSIC first level VREG interrupt. */ intel_scu_ipc_ioread8(MSIC_IRQLVL1_MASK, &data); data &= ~VREG_MASK; intel_scu_ipc_iowrite8(MSIC_IRQLVL1_MASK, data); /* Enable and handle other msic vreq interrupts when necessary. */ #endif } else { pci_dev_put(pdev); DRM_ERROR("%s: request_irq failed. ret = 0x%x. \n", __FUNCTION__, ret); } } return ret; }
int basin_cove_get_id(struct dwc_otg2 *otg) { int ret, id = RID_UNKNOWN; u8 idsts, pmic_id; ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL, USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0, USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0); if (ret) otg_err(otg, "Fail to enable ACA&ID detection logic\n"); ret = intel_scu_ipc_ioread8(PMIC_USBIDSTS, &idsts); if (ret) { otg_err(otg, "Fail to read id\n"); return id; } if (idsts & USBIDSTS_ID_FLOAT_STS) id = RID_FLOAT; else if (idsts & USBIDSTS_ID_RARBRC_STS(1)) id = RID_A; else if (idsts & USBIDSTS_ID_RARBRC_STS(2)) id = RID_B; else if (idsts & USBIDSTS_ID_RARBRC_STS(3)) id = RID_C; else { /* PMIC A0 reports ID_GND = 0 for RID_GND but PMIC B0 reports * ID_GND = 1 for RID_GND */ ret = intel_scu_ipc_ioread8(0x00, &pmic_id); if (ret) { otg_err(otg, "Fail to read PMIC ID register\n"); } else if (((pmic_id & VENDOR_ID_MASK) == BASIN_COVE_PMIC_ID) && ((pmic_id & PMIC_MAJOR_REV) == PMIC_A0_MAJOR_REV)) { if (idsts & USBIDSTS_ID_GND) id = RID_GND; } else { if (!(idsts & USBIDSTS_ID_GND)) id = RID_GND; } } ret = intel_scu_ipc_update_register(PMIC_USBIDCTRL, USBIDCTRL_ACA_DETEN_D1 | PMIC_USBPHYCTRL_D0, 0); if (ret) otg_err(otg, "Fail to enable ACA&ID detection logic\n"); return id; }
/* Board specific setup related to SD goes here */ static int mrfl_sd_setup(struct sdhci_pci_data *data) { u8 vldocnt = 0; int err; /* * Change necessary GPIO pin mode for SD card working. * This is something should be done in IA firmware. * But, anyway, just do it here in case IA firmware * forget to do so. */ lnw_gpio_set_alt(MRFLD_GPIO_SDIO_0_CD, 0); err = intel_scu_ipc_ioread8(MRFLD_PMIC_VLDOCNT, &vldocnt); if (err) { pr_err("PMIC vldocnt IPC read error: %d\n", err); return err; } vldocnt |= MRFLD_PMIC_VLDOCNT_VSWITCH_BIT; err = intel_scu_ipc_iowrite8(MRFLD_PMIC_VLDOCNT, vldocnt); if (err) { pr_err("PMIC vldocnt IPC write error: %d\n", err); return err; } msleep(20); return 0; }
/** * sst_sc_reg_access - IPC read/write wrapper * * @sc_access: array of data, addresses and mask * @type: operation type * @num_val: number of reg to opertae on * * Reads/writes/read-modify operations on registers accessed through SCU (sound * card and few SST DSP regsisters that are not accissible to IA) */ int sst_sc_reg_access(struct sc_reg_access *sc_access, int type, int num_val) { int i, retval = 0; if (type == PMIC_WRITE) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr, sc_access[i].value); if (retval) goto err; } } else if (type == PMIC_READ) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr, &(sc_access[i].value)); if (retval) goto err; } } else { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_update_register( sc_access[i].reg_addr, sc_access[i].value, sc_access[i].mask); if (retval) goto err; } } return 0; err: pr_err("IPC failed for cmd %d, %d\n", retval, type); pr_err("reg:0x%2x addr:0x%2x\n", sc_access[i].reg_addr, sc_access[i].value); return retval; }
/** * sst_sc_reg_access - IPC read/write wrapper * * @sc_access: array of data, addresses and mask * @type: operation type * @num_val: number of reg to opertae on * * Reads/writes/read-modify operations on registers accessed through SCU (sound * card and few SST DSP regsisters that are not accissible to IA) */ int sst_sc_reg_access(struct sc_reg_access *sc_access, int type, int num_val) { int i, retval = 0; if (type == PMIC_WRITE) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr, sc_access[i].value); if (retval) { pr_err("sst: IPC write failed!!! %d\n", retval); return retval; } } } else if (type == PMIC_READ) { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr, &(sc_access[i].value)); if (retval) { pr_err("sst: IPC read failed!!!!!%d\n", retval); return retval; } } } else { for (i = 0; i < num_val; i++) { retval = intel_scu_ipc_update_register( sc_access[i].reg_addr, sc_access[i].value, sc_access[i].mask); if (retval) { pr_err("sst: IPC Modify failed!!!%d\n", retval); return retval; } } } return retval; }
static ssize_t store_crit_shutdown(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; uint8_t data; unsigned long flag; if (kstrtoul(buf, 10, &flag) || (flag != 0 && flag != 1)) return -EINVAL; mutex_lock(&ocd_update_lock); ret = intel_scu_ipc_ioread8(VCRIT_CFG, &data); if (ret) goto ipc_fail; /* * flag:1 enables shutdown due to burst current * flag:0 disables shutdown due to burst current */ if (flag) data |= VCRIT_SHUTDOWN; else data &= ~VCRIT_SHUTDOWN; ret = intel_scu_ipc_iowrite8(VCRIT_CFG, data); if (!ret) ret = count; ipc_fail: mutex_unlock(&ocd_update_lock); return ret; }
static void msic_chrg_led_set(struct led_classdev *led_cdev, enum led_brightness value) { int ret; uint8_t val; mutex_lock(&lock); pr_debug("%s: %d\n", __func__, value); /* Unlock Charge parameter registers before reading */ ret = intel_scu_ipc_iowrite8(MSIC_BATT_CHR_WDTWRITE_ADDR, WDTWRITE_UNLOCK_VALUE); if (ret) { pr_err("%s: intel_scu_ipc_iowrite8 error WDTWRITE: %d\n", __func__, ret); mutex_unlock(&lock); return; } /* Read control register and set enable bit */ ret = intel_scu_ipc_ioread8(MSIC_CHRG_LED_CNTL_REG, &val); if (ret) { pr_err("%s: intel_scu_ipc_ioread8 error %d\n", __func__, ret); mutex_unlock(&lock); return; } if (value) val |= MSIC_CHRG_LED_ENBL; else val &= (~MSIC_CHRG_LED_ENBL); ret = intel_scu_ipc_iowrite8(MSIC_CHRG_LED_CNTL_REG, val); if (ret) pr_err("%s: intel_scu_ipc_iowrite8 error %d\n", __func__, ret); mutex_unlock(&lock); }
static void handle_VW2_event(int event, void *dev_data) { uint8_t irq_status, beh_data; struct ocd_info *cinfo = (struct ocd_info *)dev_data; int ret; dev_info(cinfo->dev, "EM:BCU: BCU Event %d has occured\n", event); /* Notify using UEvent */ kobject_uevent(&cinfo->dev->kobj, KOBJ_CHANGE); ret = intel_scu_ipc_ioread8(S_BCUINT, &irq_status); if (ret) goto ipc_fail; dev_dbg(cinfo->dev, "EM:BCU: S_BCUINT: %x\n", irq_status); /* If Vsys is below WARN2 level-No action required from driver */ if (!(irq_status & SVWARN2)) { /* Vsys is above WARN2 level */ ret = intel_scu_ipc_ioread8(CAMFLDIS_BEH, &beh_data); if (ret) goto ipc_fail; if (IS_ASSRT_ON_VW2(beh_data) && IS_STICKY(beh_data)) { ret = intel_scu_ipc_update_register(S_BCUCTRL, 0xFF, SBCUCTRL_CAMFLDIS); if (ret) goto ipc_fail; } ret = intel_scu_ipc_ioread8(BCUDISW2_BEH, &beh_data); if (ret) goto ipc_fail; if (IS_ASSRT_ON_VW2(beh_data) && IS_STICKY(beh_data)) { ret = intel_scu_ipc_update_register(S_BCUCTRL, 0xFF, SBCUCTRL_BCUDISW2); if (ret) goto ipc_fail; } } return; ipc_fail: dev_err(cinfo->dev, "EM:BCU: ipc read/write failed:func:%s()\n", __func__); return; }
static int pmic_gpio_chip_present(void) { int ret; u8 r; ret = intel_scu_ipc_ioread8(0x00, &r); if (ret < 0) return 0; return r == 0x3a ? 1 : 0; }
/** * mid_read_temp - read sensors for temperature * @temp: holds the current temperature for the sensor after reading * * reads the adc_code from the channel and converts it to real * temperature. The converted value is stored in temp. * * Can sleep */ static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) { struct thermal_device_info *td_info = tzd->devdata; uint16_t adc_val, addr; uint8_t data = 0; int ret; unsigned long curr_temp; addr = td_info->chnl_addr; /* Enable the msic for conversion before reading */ ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); if (ret) return ret; /* Re-toggle the RRDATARD bit (temporary workaround) */ ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL); if (ret) return ret; /* Read the higher bits of data */ ret = intel_scu_ipc_ioread8(addr, &data); if (ret) return ret; /* Shift bits to accommodate the lower two data bits */ adc_val = (data << 2); addr++; ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */ if (ret) return ret; /* Adding lower two bits to the higher bits */ data &= 03; adc_val += data; /* Convert ADC value to temperature */ ret = adc_to_temp(td_info->direct, adc_val, &curr_temp); if (ret == 0) *temp = td_info->curr_temp = curr_temp; return ret; }
/** * reset_stopbit - sets the stop bit to 0 on the given channel * @addr: address of the channel * * Can sleep */ static int reset_stopbit(uint16_t addr) { int ret; uint8_t data; ret = intel_scu_ipc_ioread8(addr, &data); if (ret) return ret; /* Set the stop bit to zero */ return intel_scu_ipc_iowrite8(addr, (data & 0xEF)); }
static int sn95031_read(void *ctx, unsigned int reg, unsigned int *val) { u8 value = 0; int ret; ret = intel_scu_ipc_ioread8(reg, &value); if (ret == 0) *val = value; return ret; }
static int check_vbus_status(struct dwc_otg2 *otg) { int ret; u8 schgrirq1; ret = intel_scu_ipc_ioread8(PMIC_SCHGRIRQ1, &schgrirq1); if (ret) return -EINVAL; return schgrirq1 & PMIC_SCHGRIRQ1_SVBUSDET; }
static inline unsigned int sn95031_read(struct snd_soc_codec *codec, unsigned int reg) { u8 value = 0; int ret; ret = intel_scu_ipc_ioread8(reg, &value); if (ret) pr_err("read of %x failed, err %d\n", reg, ret); return value; }
/* * sd_cv_get_adc_value - gets the ADC code from the register * @alert_reg_h: The 'high' register address * */ static int sd_cv_get_adc_value(uint16_t alert_reg_h, int *auto_cur_sel) { int ret; uint16_t adc_val; uint8_t l, h; int battid_cursrc; /* multiple 1000 first (here's no floating point calculation in kernel) */ int auto_cur_sel_uA[] = { 0, 1125, 2250, 4500, 9000, 18000, 36000, 72000, 144000 }; /* Reading high register address */ ret = intel_scu_ipc_ioread8(alert_reg_h, &h); if (ret) goto exit; /* Get the address of alert_reg_l */ ++alert_reg_h; /* Reading low register address */ ret = intel_scu_ipc_ioread8(alert_reg_h, &l); if (ret) goto exit; /* Concatenate 'h' and 'l' to get 12-bit ADC code */ adc_val = ((h & 0x0F) << 8) | l; if (auto_cur_sel) { /* Get the battery id current source to decide auto current selection */ battid_cursrc = (h & 0xF0) >> 4; *auto_cur_sel = auto_cur_sel_uA[battid_cursrc]; } return adc_val; exit: return ret; }
static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset) { u8 r; int ret; /* we only have 8 GPIO pins we can use as input */ if (offset >= 8) return -EOPNOTSUPP; ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r); if (ret < 0) return ret; return r & GPIO_DIN; }
/* * ps_hdmi_get_cable_status - Get HDMI cable connection status * @context: hdmi device context * * Returns - boolean state. * true - HDMI cable connected * false - HDMI cable disconnected */ bool ps_hdmi_get_cable_status(void *context) { hdmi_context_t *ctx = (hdmi_context_t *)context; u8 data = 0; if (ctx == NULL) return false; /* Read HDMI cable status from MSIC chip */ intel_scu_ipc_ioread8(PS_MSIC_HDMI_STATUS_CMD, &data); if (data & PS_MSIC_HDMI_STATUS) return true; else return false; }
static void enable_volt_trip_points(void) { int i, ret; uint8_t data; /* * Enable the Voltage comparator logic, so that the output * signals are asserted when a voltage drop occurs. */ for (i = 0; i < NUM_VOLT_LEVELS; i++) { ret = intel_scu_ipc_ioread8(VWARN1_CFG + i, &data); if (!ret) intel_scu_ipc_iowrite8(VWARN1_CFG + i, (data | VWARN_EN)); } }
static void enable_current_trip_points(void) { int i, ret; uint8_t data; /* * Enable the Current comparator logic, so that the output * signals are asserted when the platform current surges. */ for (i = 0; i < NUM_CURR_LEVELS; i++) { ret = intel_scu_ipc_ioread8(MAXVCC_CFG + i, &data); if (!ret) intel_scu_ipc_iowrite8(MAXVCC_CFG + i, (data | ICCMAX_EN)); } }
int _get_board_id(void) { u8 i = 0; u8 data = -1; int value = 0; for (i = 0x79; i <= 0x7c; i++) { intel_scu_ipc_ioread8(i, &data); value |= (data & 0x1) << (0x7c - i); data = -1; } printf("[SCU_IPC_DEBUG] board ID: %x\n", value); return value; }
static void __vpro2_power_ctrl(bool on) { u8 addr, value; addr = 0xad; if (intel_scu_ipc_ioread8(addr, &value)) DRM_ERROR("%s: %d: failed to read vPro2\n", __func__, __LINE__); /* Control vPROG2 power rail with 2.85v. */ if (on) value |= 0x1; else value &= ~0x1; if (intel_scu_ipc_iowrite8(addr, value)) DRM_ERROR("%s: %d: failed to write vPro2\n", __func__, __LINE__); }
/** * mid_initialize_adc - initializing the ADC * @dev: our device structure * * Initialize the ADC for reading thermistor values. Can sleep. */ static int mid_initialize_adc(struct device *dev) { u8 data; u16 base_addr; int ret; /* * Ensure that adctherm is disabled before we * initialize the ADC */ ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data); if (ret) return ret; if (data & MSIC_ADCTHERM_MASK) dev_warn(dev, "ADCTHERM already set"); /* Index of the first channel in which the stop bit is set */ channel_index = find_free_channel(); if (channel_index < 0) { dev_err(dev, "No free ADC channels"); return channel_index; } base_addr = ADC_CHNL_START_ADDR + channel_index; if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) { /* Reset stop bit for channels other than 0 and 12 */ ret = reset_stopbit(base_addr); if (ret) return ret; /* Index of the first free channel */ base_addr++; channel_index++; } ret = set_up_therm_channel(base_addr); if (ret) { dev_err(dev, "unable to enable ADC"); return ret; } dev_dbg(dev, "ADC initialization successful"); return ret; }
/** * configure_adc - enables/disables the ADC for conversion * @val: zero: disables the ADC non-zero:enables the ADC * * Enable/Disable the ADC depending on the argument * * Can sleep */ static int configure_adc(int val) { int ret; uint8_t data; ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); if (ret) return ret; if (val) { /* Enable and start the ADC */ data |= (MSIC_ADC_ENBL | MSIC_ADC_START); } else { /* Just stop the ADC */ data &= (~MSIC_ADC_START); } return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data); }
/* Board specific cleanup related to SD goes here */ static void mrfl_sd_cleanup(struct sdhci_pci_data *data) { u8 vldocnt = 0; int err; err = intel_scu_ipc_ioread8(MRFLD_PMIC_VLDOCNT, &vldocnt); if (err) { pr_err("PMIC vldocnt IPC read error: %d\n", err); return; } vldocnt &= MRFLD_PMIC_VLDOCNT_PW_OFF; err = intel_scu_ipc_iowrite8(MRFLD_PMIC_VLDOCNT, vldocnt); if (err) pr_err("PMIC vldocnt IPC write error: %d\n", err); return; }
static ssize_t show_crit_shutdown(struct device *dev, struct device_attribute *attr, char *buf) { int flag, ret; uint8_t data; mutex_lock(&ocd_update_lock); ret = intel_scu_ipc_ioread8(VCRIT_CFG, &data); if (!ret) { /* 'flag' is 1 if CRIT_SHUTDOWN is enabled, 0 otherwise */ flag = !!(data & VCRIT_SHUTDOWN); } mutex_unlock(&ocd_update_lock); return ret ? ret : sprintf(buf, "%d\n", flag); }
static void pmic_gpio_dump(void *buf) { struct reg_info *reg; int i; u8 val; int ret; reg = (struct reg_info *)buf; for (i = 0; i < (sizeof(reg_offsets) / sizeof(int)); i++, reg++) { reg->valid = 1; ret = intel_scu_ipc_ioread8(reg_offsets[i], &val); if (ret < 0) reg->valid = 0; reg->version = INFO_VER; reg->chip_id = PMIC_GPIO; reg->register_id = reg_offsets[i]; reg->register_value = val; } }