| /* |
| * Dollar Cove -- Device access for Intel PMIC for CR |
| * |
| * Copyright (c) 2014, Intel Corporation. |
| * |
| * Author: Yang Bin <bin.yang@intel.com> |
| * |
| * 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; version 2 |
| * of the License. |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/delay.h> |
| #include <linux/mfd/core.h> |
| #include <linux/err.h> |
| #include <linux/i2c.h> |
| #include <linux/irq.h> |
| #include <linux/interrupt.h> |
| #include <linux/gpio.h> |
| #include <linux/mfd/intel_soc_pmic.h> |
| #include <linux/acpi.h> |
| #include <linux/version.h> |
| #include <linux/power/dc_xpwr_battery.h> |
| #include <linux/power/dc_xpwr_charger.h> |
| #include <linux/regulator/intel_dollar_cove_pmic.h> |
| |
| #include <asm/intel_em_config.h> |
| #include <linux/extcon/extcon-dc-pwrsrc.h> |
| #include <linux/power/battery_id.h> |
| |
| #include "intel_soc_pmic_core.h" |
| |
| #define XPOWER_DEFAULT_TEMP_MAX 45 |
| |
| #define GPIO_USB_MUX_INDEX 1 |
| #define GPIO_OTG_VBUS_INDEX 2 |
| |
| enum { |
| VBUS_FALLING_IRQ = 2, |
| VBUS_RISING_IRQ, |
| VBUS_OV_IRQ, |
| VBUS_FALLING_ALT_IRQ, |
| VBUS_RISING_ALT_IRQ, |
| VBUS_OV_ALT_IRQ, |
| |
| CHARGE_DONE_IRQ = 10, |
| CHARGE_CHARGING_IRQ, |
| BAT_SAFE_QUIT_IRQ, |
| BAT_SAFE_ENTER_IRQ, |
| BAT_ABSENT_IRQ, |
| BAT_APPEND_IRQ, |
| |
| QWBTU_IRQ = 16, |
| WBTU_IRQ, |
| QWBTO_IRQ, |
| WBTO_IRQ, |
| QCBTU_IRQ, |
| CBTU_IRQ, |
| QCBTO_IRQ, |
| CBTO_IRQ, |
| |
| WL2_IRQ = 24, |
| WL1_IRQ, |
| GPADC_IRQ, |
| OT_IRQ = 31, |
| |
| GPIO0_IRQ = 32, |
| GPIO1_IRQ, |
| POKO_IRQ, |
| POKL_IRQ, |
| POKS_IRQ, |
| POKN_IRQ, |
| POKP_IRQ, |
| EVENT_IRQ, |
| |
| MV_CHNG_IRQ = 40, |
| BC_USB_CHNG_IRQ, |
| }; |
| |
| static struct resource power_button_resources[] = { |
| { |
| .start = POKN_IRQ, |
| .end = POKN_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = POKP_IRQ, |
| .end = POKP_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| |
| static struct resource gpio_resources[] = { |
| { |
| .start = GPIO0_IRQ, |
| .end = GPIO1_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct resource adc_resources[] = { |
| { |
| .start = GPADC_IRQ, |
| .end = GPADC_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct resource pwrsrc_resources[] = { |
| { |
| .start = VBUS_FALLING_IRQ, |
| .end = VBUS_FALLING_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = VBUS_RISING_IRQ, |
| .end = VBUS_RISING_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = MV_CHNG_IRQ, |
| .end = MV_CHNG_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = BC_USB_CHNG_IRQ, |
| .end = BC_USB_CHNG_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct resource charger_resources[] = { |
| { |
| .start = VBUS_OV_IRQ, |
| .end = VBUS_OV_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = CHARGE_DONE_IRQ, |
| .end = CHARGE_DONE_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = CHARGE_CHARGING_IRQ, |
| .end = CHARGE_CHARGING_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = BAT_SAFE_QUIT_IRQ, |
| .end = BAT_SAFE_QUIT_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = BAT_SAFE_ENTER_IRQ, |
| .end = BAT_SAFE_ENTER_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = QCBTU_IRQ, |
| .end = QCBTU_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = CBTU_IRQ, |
| .end = CBTU_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = QCBTO_IRQ, |
| .end = QCBTO_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = CBTO_IRQ, |
| .end = CBTO_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct resource battery_resources[] = { |
| { |
| .start = QWBTU_IRQ, |
| .end = QWBTU_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = WBTU_IRQ, |
| .end = WBTU_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = QWBTO_IRQ, |
| .end = QWBTO_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = WBTO_IRQ, |
| .end = WBTO_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = WL2_IRQ, |
| .end = WL2_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| { |
| .start = WL1_IRQ, |
| .end = WL1_IRQ, |
| .flags = IORESOURCE_IRQ, |
| }, |
| }; |
| |
| static struct mfd_cell dollar_cove_dev[] = { |
| { |
| .name = "dollar_cove_adc", |
| .id = 0, |
| .num_resources = ARRAY_SIZE(adc_resources), |
| .resources = adc_resources, |
| }, |
| { |
| .name = "dollar_cove_gpio", |
| .id = 0, |
| .num_resources = ARRAY_SIZE(gpio_resources), |
| .resources = gpio_resources, |
| }, |
| { |
| .name = "dollar_cove_power_button", |
| .id = 0, |
| .num_resources = ARRAY_SIZE(power_button_resources), |
| .resources = power_button_resources, |
| }, |
| { |
| .name = "dollar_cove_pwrsrc", |
| .id = 0, |
| .num_resources = ARRAY_SIZE(pwrsrc_resources), |
| .resources = pwrsrc_resources, |
| }, |
| { |
| .name = "dollar_cove_charger", |
| .id = 0, |
| .num_resources = ARRAY_SIZE(charger_resources), |
| .resources = charger_resources, |
| }, |
| { |
| .name = "dollar_cove_battery", |
| .id = 0, |
| .num_resources = ARRAY_SIZE(battery_resources), |
| .resources = battery_resources, |
| }, |
| { |
| .name = "dollar_cove_region", |
| }, |
| { |
| .name = "dcovex_regulator", |
| .id = DCOVEX_ID_LDO2 + 1, |
| .num_resources = 0, |
| .resources = NULL, |
| }, |
| { |
| .name = "dcovex_regulator", |
| .id = DCOVEX_ID_LDO3 + 1, |
| .num_resources = 0, |
| .resources = NULL, |
| }, |
| {NULL, }, |
| }; |
| |
| #define DOLLAR_COVE_IRQREGMAP(irq) \ |
| [irq] = { \ |
| {(0x40 + (irq / 8)), (irq % 8), 1, INTEL_PMIC_REG_INV},\ |
| {(0x48 + (irq / 8)), (irq % 8), 1, INTEL_PMIC_REG_W1C},\ |
| {(0x48 + (irq / 8)), (irq % 8), 1, INTEL_PMIC_REG_W1C},\ |
| } |
| |
| struct intel_pmic_irqregmap dollar_cove_irqregmap[] = { |
| DOLLAR_COVE_IRQREGMAP(VBUS_FALLING_IRQ), |
| DOLLAR_COVE_IRQREGMAP(VBUS_RISING_IRQ), |
| DOLLAR_COVE_IRQREGMAP(VBUS_OV_IRQ), |
| DOLLAR_COVE_IRQREGMAP(VBUS_FALLING_ALT_IRQ), |
| DOLLAR_COVE_IRQREGMAP(VBUS_RISING_ALT_IRQ), |
| DOLLAR_COVE_IRQREGMAP(VBUS_OV_ALT_IRQ), |
| DOLLAR_COVE_IRQREGMAP(CHARGE_DONE_IRQ), |
| DOLLAR_COVE_IRQREGMAP(CHARGE_CHARGING_IRQ), |
| DOLLAR_COVE_IRQREGMAP(BAT_SAFE_QUIT_IRQ), |
| DOLLAR_COVE_IRQREGMAP(BAT_SAFE_ENTER_IRQ), |
| DOLLAR_COVE_IRQREGMAP(BAT_ABSENT_IRQ), |
| DOLLAR_COVE_IRQREGMAP(BAT_APPEND_IRQ), |
| DOLLAR_COVE_IRQREGMAP(QWBTU_IRQ), |
| DOLLAR_COVE_IRQREGMAP(WBTU_IRQ), |
| DOLLAR_COVE_IRQREGMAP(QWBTO_IRQ), |
| DOLLAR_COVE_IRQREGMAP(WBTO_IRQ), |
| DOLLAR_COVE_IRQREGMAP(QCBTU_IRQ), |
| DOLLAR_COVE_IRQREGMAP(CBTU_IRQ), |
| DOLLAR_COVE_IRQREGMAP(QCBTO_IRQ), |
| DOLLAR_COVE_IRQREGMAP(CBTO_IRQ), |
| DOLLAR_COVE_IRQREGMAP(WL2_IRQ), |
| DOLLAR_COVE_IRQREGMAP(WL1_IRQ), |
| DOLLAR_COVE_IRQREGMAP(GPADC_IRQ), |
| DOLLAR_COVE_IRQREGMAP(OT_IRQ), |
| DOLLAR_COVE_IRQREGMAP(GPIO0_IRQ), |
| DOLLAR_COVE_IRQREGMAP(GPIO1_IRQ), |
| DOLLAR_COVE_IRQREGMAP(POKO_IRQ), |
| DOLLAR_COVE_IRQREGMAP(POKL_IRQ), |
| DOLLAR_COVE_IRQREGMAP(POKS_IRQ), |
| DOLLAR_COVE_IRQREGMAP(POKN_IRQ), |
| DOLLAR_COVE_IRQREGMAP(POKP_IRQ), |
| DOLLAR_COVE_IRQREGMAP(EVENT_IRQ), |
| DOLLAR_COVE_IRQREGMAP(MV_CHNG_IRQ), |
| DOLLAR_COVE_IRQREGMAP(BC_USB_CHNG_IRQ), |
| }; |
| |
| |
| static struct ps_batt_chg_prof ps_batt_chrg_prof; |
| static struct ps_pse_mod_prof *pse_mod_prof; |
| #ifdef CONFIG_POWER_SUPPLY_CHARGER |
| |
| #define DC_CHRG_CHRG_CUR_NOLIMIT 1800 |
| #define DC_CHRG_CHRG_CUR_MEDIUM 1400 |
| #define DC_CHRG_CHRG_CUR_LOW 1000 |
| |
| static struct power_supply_throttle dc_chrg_throttle_states[] = { |
| { |
| .throttle_action = PSY_THROTTLE_CC_LIMIT, |
| .throttle_val = DC_CHRG_CHRG_CUR_NOLIMIT, |
| }, |
| { |
| .throttle_action = PSY_THROTTLE_CC_LIMIT, |
| .throttle_val = DC_CHRG_CHRG_CUR_MEDIUM, |
| }, |
| { |
| .throttle_action = PSY_THROTTLE_CC_LIMIT, |
| .throttle_val = DC_CHRG_CHRG_CUR_LOW, |
| }, |
| { |
| .throttle_action = PSY_THROTTLE_DISABLE_CHARGING, |
| }, |
| }; |
| |
| static char *dc_chrg_supplied_to[] = { |
| "dollar_cove_battery" |
| }; |
| |
| static void *platform_get_batt_charge_profile(void) |
| { |
| int ret; |
| |
| ret = get_batt_prop(&ps_batt_chrg_prof); |
| pse_mod_prof = (struct ps_pse_mod_prof *) |
| ps_batt_chrg_prof.batt_prof; |
| if ((ret < 0 || ps_batt_chrg_prof.chrg_prof_type == CHRG_PROF_NONE) |
| && pse_mod_prof) |
| snprintf(pse_mod_prof->batt_id, (BATTID_STR_LEN + 1), |
| "%s", BATTID_UNKNOWN); |
| |
| return &ps_batt_chrg_prof; |
| } |
| |
| static void platform_init_chrg_params(struct dollarcove_chrg_pdata *pdata) |
| { |
| pdata->throttle_states = dc_chrg_throttle_states; |
| pdata->supplied_to = dc_chrg_supplied_to; |
| pdata->num_throttle_states = ARRAY_SIZE(dc_chrg_throttle_states); |
| pdata->num_supplicants = ARRAY_SIZE(dc_chrg_supplied_to); |
| pdata->supported_cables = POWER_SUPPLY_CHARGER_TYPE_USB; |
| pdata->chg_profile = (struct ps_batt_chg_prof *) |
| platform_get_batt_charge_profile(); |
| } |
| |
| static void platform_set_battery_data(struct dollarcove_fg_pdata *pdata, |
| struct ps_batt_chg_prof *chg_prof) |
| { |
| struct ps_pse_mod_prof *prof = (struct ps_pse_mod_prof *) |
| chg_prof->batt_prof; |
| |
| /* |
| * Get the data from ACPI Table OEM0 if it is available |
| * Also make sure we are not setting value of 0 as acpi table may |
| * sometimes incorrectly set them to 0. |
| */ |
| if (chg_prof->chrg_prof_type == PSE_MOD_CHRG_PROF) { |
| pdata->design_cap = prof->capacity ? prof->capacity : 4045; |
| pdata->design_max_volt = prof->voltage_max ? prof->voltage_max : 4350; |
| pdata->design_min_volt = prof->low_batt_mV ? prof->low_batt_mV : 3400; |
| } else { |
| pdata->design_cap = 4045; |
| pdata->design_max_volt = 4350; |
| pdata->design_min_volt = 3400; |
| } |
| } |
| |
| #else |
| |
| static void platform_init_chrg_params(struct dollarcove_chrg_pdata *pdata) |
| { |
| } |
| |
| static void platform_set_battery_data(struct dollarcove_fg_pdata *pdata, |
| struct ps_batt_chg_prof *chg_prof) |
| { |
| pdata->design_cap = 4045; |
| pdata->design_max_volt = 4350; |
| pdata->design_min_volt = 3400; |
| } |
| |
| #endif |
| |
| static void dc_xpwr_chrg_pdata(void) |
| { |
| static struct dollarcove_chrg_pdata pdata; |
| struct gpio_desc *gpio_desc; |
| struct ps_pse_mod_prof *prof; |
| int i, diff; |
| struct ps_temp_chg_table *entry; |
| |
| /* Default parameters */ |
| pdata.max_cc = 2000; |
| pdata.max_cv = 4350; |
| pdata.def_cc = 500; |
| pdata.def_cv = 4350; |
| pdata.def_ilim = 900; |
| pdata.def_iterm = 300; |
| pdata.def_max_temp = 55; |
| pdata.def_min_temp = 0; |
| |
| gpio_desc = devm_gpiod_get_index(dollar_cove_pmic.dev, |
| "pmic_res", GPIO_OTG_VBUS_INDEX); |
| if (IS_ERR(gpio_desc)) |
| pdata.otg_gpio = -1; |
| else { |
| pdata.otg_gpio = desc_to_gpio(gpio_desc); |
| gpiod_put(gpio_desc); |
| } |
| |
| platform_init_chrg_params(&pdata); |
| |
| /* Do some sanity checks */ |
| prof = (struct ps_pse_mod_prof *)pdata.chg_profile->batt_prof; |
| pdata.max_cv = min_t(u16, pdata.max_cv, prof->voltage_max); |
| pdata.def_cv = min_t(u16, pdata.def_cv, prof->voltage_max); |
| |
| for (i = 0; i < prof->temp_mon_ranges; i++) { |
| entry = &prof->temp_mon_range[i]; |
| |
| if (entry->full_chrg_vol > pdata.max_cv) |
| entry->full_chrg_vol = pdata.max_cv; |
| |
| if (entry->maint_chrg_vol_ul > pdata.max_cv) { |
| diff = entry->maint_chrg_vol_ul |
| - entry->maint_chrg_vol_ll; |
| |
| entry->maint_chrg_vol_ul = pdata.max_cv; |
| entry->maint_chrg_vol_ll = pdata.max_cv - diff; |
| } |
| } |
| |
| intel_soc_pmic_set_pdata("dollar_cove_charger", |
| (void *)&pdata, sizeof(pdata), 0); |
| } |
| |
| static u8 fg_bat_curve_4350mv[] = { |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, |
| 0x02, 0x03, 0x05, 0x09, 0x0f, 0x18, 0x24, 0x29, |
| 0x2e, 0x32, 0x35, 0x3b, 0x40, 0x45, 0x49, 0x4c, |
| 0x50, 0x53, 0x55, 0x57, 0x5a, 0x5d, 0x61, 0x64, |
| }; |
| |
| static u8 fg_bat_curve_4200mv[] = { |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, |
| 0x02, 0x02, 0x04, 0x0b, 0x12, 0x1b, 0x27, 0x2e, |
| 0x32, 0x36, 0x3a, 0x40, 0x45, 0x4a, 0x4e, 0x52, |
| 0x57, 0x5b, 0x5e, 0x61, 0x64, 0x64, 0x64, 0x64, |
| }; |
| |
| #ifdef CONFIG_ACPI |
| #define FGCONFIG_ACPI_TABLE_NAME "BCFG" |
| #define XPWR_FGCONFIG_NAME "XPOWER-0" |
| |
| static int |
| dc_xpwr_get_acpi_cdata(struct dollarcove_fg_pdata *pdata) |
| { |
| struct dc_xpwr_acpi_fg_config *acpi_tbl = NULL; |
| char *name = FGCONFIG_ACPI_TABLE_NAME; |
| acpi_size tbl_size; |
| acpi_status status; |
| |
| /* read the fg config table from acpi */ |
| status = acpi_get_table_with_size(name , 0, |
| (struct acpi_table_header **)&acpi_tbl, &tbl_size); |
| if (ACPI_FAILURE(status)) { |
| pr_err("%s:%s table not found!!\n", __func__, name); |
| return status; |
| } |
| pr_info("%s: %s table found, size=%d\n", |
| __func__, name, (int)tbl_size); |
| |
| /* validate the table size */ |
| if (tbl_size < sizeof(struct dc_xpwr_acpi_fg_config)) { |
| pr_err("%s:%s table incomplete!!\n", __func__, name); |
| pr_info("%s: table_size=%d, structure_size=%lu\n", |
| __func__, (int)tbl_size, |
| sizeof(struct dc_xpwr_acpi_fg_config)); |
| return -ENXIO; |
| } |
| |
| if (strncmp(acpi_tbl->cdata.fg_name, XPWR_FGCONFIG_NAME, |
| ACPI_FG_CONF_NAME_LEN) |
| || strncmp(acpi_tbl->cdata.battid, pdata->battid, |
| BATTID_STR_LEN)) { |
| pr_err("%s: battid and fg_name mismatch!!!\n", __func__); |
| return -EINVAL; |
| } |
| |
| memcpy(&pdata->cdata, &acpi_tbl->cdata, |
| sizeof(struct dc_xpwr_fg_config_data)); |
| |
| return 0; |
| } |
| #endif /* CONFIG_ACPI */ |
| |
| static void dc_xpwr_get_fg_config_data(struct dollarcove_fg_pdata *pdata) |
| { |
| int scaled_capacity; |
| int i; |
| u8 *fg_bat_curve; |
| |
| #ifdef CONFIG_ACPI |
| if (!dc_xpwr_get_acpi_cdata(pdata)) { |
| pr_info("%s: Loading fg config from acpi table\n", __func__); |
| pdata->fg_save_restore_enabled = 1; |
| return; |
| } |
| #endif /* CONFIG_ACPI */ |
| |
| pr_info("%s: Loading default fg config.\n", __func__); |
| /* |
| * Calculate cap1 and cap0. The value of a LSB is 1.456mAh. |
| * Using 1.5 as math friendly and close enough. |
| */ |
| |
| scaled_capacity = (pdata->design_cap >> 1) + |
| (pdata->design_cap >> 3) + |
| (pdata->design_cap >> 4); |
| |
| /* |
| * bit 7 of cap1 register is set to indicate battery maximum |
| * capacity is valid |
| */ |
| pdata->cdata.cap0 = scaled_capacity & 0xFF; |
| pdata->cdata.cap1 = (scaled_capacity >> 8) | 0x80; |
| |
| pdata->cdata.rdc1 = 0xc0; |
| pdata->cdata.rdc0 = 0x97; |
| |
| /* Donot update the entire fg data on every boot*/ |
| pdata->cdata.fco = 0x00; |
| /* copy curve data */ |
| if (pdata->design_max_volt == 4200) |
| fg_bat_curve = fg_bat_curve_4200mv; |
| else |
| fg_bat_curve = fg_bat_curve_4350mv; |
| |
| for (i = 0; i < XPWR_BAT_CURVE_SIZE; i++) |
| pdata->cdata.bat_curve[i] = fg_bat_curve[i]; |
| |
| pdata->fg_save_restore_enabled = 0; |
| return; |
| } |
| |
| static void dc_xpwr_fg_pdata(void) |
| { |
| static struct dollarcove_fg_pdata pdata; |
| int i, temp_mon_ranges; |
| int scaled_capacity; |
| |
| if (ps_batt_chrg_prof.chrg_prof_type == CHRG_PROF_NONE |
| || (!pse_mod_prof)) |
| snprintf(pdata.battid, (BATTID_STR_LEN + 1), |
| "%s", BATTID_UNKNOWN); |
| else { |
| memcpy(pdata.battid, pse_mod_prof->batt_id, |
| strlen(pse_mod_prof->batt_id)); |
| pdata.battid[BATTID_STR_LEN] = '\0'; |
| } |
| |
| platform_set_battery_data(&pdata, &ps_batt_chrg_prof); |
| pse_mod_prof = (struct ps_pse_mod_prof *) |
| ps_batt_chrg_prof.batt_prof; |
| temp_mon_ranges = min_t(u16, pse_mod_prof->temp_mon_ranges, |
| BATT_TEMP_NR_RNG); |
| for (i = 0; i < temp_mon_ranges; ++i) { |
| if (pse_mod_prof->temp_mon_range[i].full_chrg_cur) |
| break; |
| } |
| if (i < temp_mon_ranges) |
| pdata.max_temp = pse_mod_prof->temp_mon_range[i].temp_up_lim; |
| else |
| pdata.max_temp = XPOWER_DEFAULT_TEMP_MAX; |
| |
| pdata.min_temp = pse_mod_prof->temp_low_lim; |
| |
| /* Load FG config data to pdata */ |
| dc_xpwr_get_fg_config_data(&pdata); |
| |
| intel_soc_pmic_set_pdata("dollar_cove_battery", |
| (void *)&pdata, sizeof(pdata), 0); |
| } |
| |
| static void dc_xpwr_pwrsrc_pdata(void) |
| { |
| static struct dc_xpwr_pwrsrc_pdata pdata; |
| |
| /* |
| * set en_chrg_det to true if the |
| * D+/D- lines are connected to |
| * PMIC itself. |
| */ |
| pdata.en_chrg_det = true; |
| |
| /* Get the gpio based uab mux which will be used to switch usb D+/D- |
| * data line between SOC for data communication and PMIC for charger |
| * detection functionality. |
| */ |
| pdata.gpio_mux_cntl = devm_gpiod_get_index(dollar_cove_pmic.dev, |
| "pmic_res", GPIO_USB_MUX_INDEX); |
| if (IS_ERR(pdata.gpio_mux_cntl)) |
| pdata.gpio_mux_cntl = NULL; |
| else |
| gpiod_put(pdata.gpio_mux_cntl); |
| |
| intel_soc_pmic_set_pdata("dollar_cove_pwrsrc", |
| (void *)&pdata, sizeof(pdata), 0); |
| } |
| |
| static struct pmic_gpio_data dollar_cove_gpio_data = { |
| .type = DOLLAR_COVE, |
| .num_gpio = 2, |
| .num_vgpio = 0x5e, |
| }; |
| |
| static void dc_set_gpio_pdata(void) |
| { |
| intel_soc_pmic_set_pdata("dollar_cove_gpio", |
| (void *)&dollar_cove_gpio_data, |
| sizeof(dollar_cove_gpio_data), 0); |
| } |
| |
| |
| static int dollar_cove_init(void) |
| { |
| pr_info("Dollar Cove: IC_TYPE 0x%02X\n", intel_soc_pmic_readb(0x03)); |
| dc_xpwr_chrg_pdata(); |
| dc_xpwr_pwrsrc_pdata(); |
| dc_xpwr_fg_pdata(); |
| dc_set_gpio_pdata(); |
| |
| return 0; |
| } |
| |
| struct intel_soc_pmic dollar_cove_pmic = { |
| .label = "dollar cove", |
| .irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
| | IRQF_NO_SUSPEND, |
| .init = dollar_cove_init, |
| .cell_dev = dollar_cove_dev, |
| .irq_regmap = dollar_cove_irqregmap, |
| .irq_num = 48, |
| }; |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_AUTHOR("Yang Bin <bin.yang@intel.com"); |