/* * Summit Microelectronics SMB347 Battery Charger Driver * * Copyright (C) 2011, Intel Corporation * * Authors: Bruce E. Robertson * Mika Westerberg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include /* * Configuration registers. These are mirrored to volatile RAM and can be * written once %CMD_A_ALLOW_WRITE is set in %CMD_A register. They will be * reloaded from non-volatile registers after POR. */ #define CFG_CHARGE_CURRENT 0x00 #define CFG_CHARGE_CURRENT_FCC_MASK 0xe0 #define CFG_CHARGE_CURRENT_FCC_SHIFT 5 #define CFG_CHARGE_CURRENT_PCC_MASK 0x18 #define CFG_CHARGE_CURRENT_PCC_SHIFT 3 #define CFG_CHARGE_CURRENT_TC_MASK 0x07 #define CFG_CURRENT_LIMIT 0x01 #define CFG_CURRENT_LIMIT_DC_MASK 0xf0 #define CFG_CURRENT_LIMIT_DC_SHIFT 4 #define CFG_CURRENT_LIMIT_USB_MASK 0x0f #define CFG_FLOAT_VOLTAGE 0x03 #define CFG_FLOAT_VOLTAGE_FLOAT_MASK 0x3f #define CFG_FLOAT_VOLTAGE_THRESHOLD_MASK 0xc0 #define CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT 6 #define CFG_STAT 0x05 #define CFG_STAT_DISABLED BIT(5) #define CFG_STAT_ACTIVE_HIGH BIT(7) #define CFG_PIN 0x06 #define CFG_PIN_EN_CTRL_MASK 0x60 #define CFG_PIN_EN_CTRL_ACTIVE_HIGH 0x40 #define CFG_PIN_EN_CTRL_ACTIVE_LOW 0x60 #define CFG_PIN_EN_APSD_IRQ BIT(1) #define CFG_PIN_EN_CHARGER_ERROR BIT(2) #define CFG_THERM 0x07 #define CFG_THERM_SOFT_HOT_COMPENSATION_MASK 0x03 #define CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT 0 #define CFG_THERM_SOFT_COLD_COMPENSATION_MASK 0x0c #define CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT 2 #define CFG_THERM_MONITOR_DISABLED BIT(4) #define CFG_SYSOK 0x08 #define CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED BIT(2) #define CFG_OTHER 0x09 #define CFG_OTHER_RID_MASK 0xc0 #define CFG_OTHER_RID_ENABLED_AUTO_OTG 0xc0 #define CFG_OTG 0x0a #define CFG_OTG_TEMP_THRESHOLD_MASK 0x30 #define CFG_OTG_TEMP_THRESHOLD_SHIFT 4 #define CFG_OTG_CC_COMPENSATION_MASK 0xc0 #define CFG_OTG_CC_COMPENSATION_SHIFT 6 #define CFG_TEMP_LIMIT 0x0b #define CFG_TEMP_LIMIT_SOFT_HOT_MASK 0x03 #define CFG_TEMP_LIMIT_SOFT_HOT_SHIFT 0 #define CFG_TEMP_LIMIT_SOFT_COLD_MASK 0x0c #define CFG_TEMP_LIMIT_SOFT_COLD_SHIFT 2 #define CFG_TEMP_LIMIT_HARD_HOT_MASK 0x30 #define CFG_TEMP_LIMIT_HARD_HOT_SHIFT 4 #define CFG_TEMP_LIMIT_HARD_COLD_MASK 0xc0 #define CFG_TEMP_LIMIT_HARD_COLD_SHIFT 6 #define CFG_FAULT_IRQ 0x0c #define CFG_FAULT_IRQ_DCIN_UV BIT(2) #define CFG_STATUS_IRQ 0x0d #define CFG_STATUS_IRQ_TERMINATION_OR_TAPER BIT(4) #define CFG_STATUS_IRQ_CHARGE_TIMEOUT BIT(7) #define CFG_ADDRESS 0x0e /* Command registers */ #define CMD_A 0x30 #define CMD_A_CHG_ENABLED BIT(1) #define CMD_A_SUSPEND_ENABLED BIT(2) #define CMD_A_ALLOW_WRITE BIT(7) #define CMD_B 0x31 #define CMD_C 0x33 /* Interrupt Status registers */ #define IRQSTAT_A 0x35 #define IRQSTAT_C 0x37 #define IRQSTAT_C_TERMINATION_STAT BIT(0) #define IRQSTAT_C_TERMINATION_IRQ BIT(1) #define IRQSTAT_C_TAPER_IRQ BIT(3) #define IRQSTAT_D 0x38 #define IRQSTAT_D_CHARGE_TIMEOUT_STAT BIT(2) #define IRQSTAT_D_CHARGE_TIMEOUT_IRQ BIT(3) #define IRQSTAT_E 0x39 #define IRQSTAT_E_USBIN_UV_STAT BIT(0) #define IRQSTAT_E_USBIN_UV_IRQ BIT(1) #define IRQSTAT_E_DCIN_UV_STAT BIT(4) #define IRQSTAT_E_DCIN_UV_IRQ BIT(5) #define IRQSTAT_F 0x3a /* Status registers */ #define STAT_A 0x3b #define STAT_A_FLOAT_VOLTAGE_MASK 0x3f #define STAT_B 0x3c #define STAT_C 0x3d #define STAT_C_CHG_ENABLED BIT(0) #define STAT_C_HOLDOFF_STAT BIT(3) #define STAT_C_CHG_MASK 0x06 #define STAT_C_CHG_SHIFT 1 #define STAT_C_CHG_TERM BIT(5) #define STAT_C_CHARGER_ERROR BIT(6) #define STAT_E 0x3f #define SMB347_MAX_REGISTER 0x3f /** * struct smb347_charger - smb347 charger instance * @lock: protects concurrent access to online variables * @dev: pointer to device * @regmap: pointer to driver regmap * @mains: power_supply instance for AC/DC power * @usb: power_supply instance for USB power * @battery: power_supply instance for battery * @mains_online: is AC/DC input connected * @usb_online: is USB input connected * @charging_enabled: is charging enabled * @pdata: pointer to platform data */ struct smb347_charger { struct mutex lock; struct device *dev; struct regmap *regmap; struct power_supply *mains; struct power_supply *usb; struct power_supply *battery; bool mains_online; bool usb_online; bool charging_enabled; const struct smb347_charger_platform_data *pdata; }; /* Fast charge current in uA */ static const unsigned int fcc_tbl[] = { 700000, 900000, 1200000, 1500000, 1800000, 2000000, 2200000, 2500000, }; /* Pre-charge current in uA */ static const unsigned int pcc_tbl[] = { 100000, 150000, 200000, 250000, }; /* Termination current in uA */ static const unsigned int tc_tbl[] = { 37500, 50000, 100000, 150000, 200000, 250000, 500000, 600000, }; /* Input current limit in uA */ static const unsigned int icl_tbl[] = { 300000, 500000, 700000, 900000, 1200000, 1500000, 1800000, 2000000, 2200000, 2500000, }; /* Charge current compensation in uA */ static const unsigned int ccc_tbl[] = { 250000, 700000, 900000, 1200000, }; /* Convert register value to current using lookup table */ static int hw_to_current(const unsigned int *tbl, size_t size, unsigned int val) { if (val >= size) return -EINVAL; return tbl[val]; } /* Convert current to register value using lookup table */ static int current_to_hw(const unsigned int *tbl, size_t size, unsigned int val) { size_t i; for (i = 0; i < size; i++) if (val < tbl[i]) break; return i > 0 ? i - 1 : -EINVAL; } /** * smb347_update_ps_status - refreshes the power source status * @smb: pointer to smb347 charger instance * * Function checks whether any power source is connected to the charger and * updates internal state accordingly. If there is a change to previous state * function returns %1, otherwise %0 and negative errno in case of errror. */ static int smb347_update_ps_status(struct smb347_charger *smb) { bool usb = false; bool dc = false; unsigned int val; int ret; ret = regmap_read(smb->regmap, IRQSTAT_E, &val); if (ret < 0) return ret; /* * Dc and usb are set depending on whether they are enabled in * platform data _and_ whether corresponding undervoltage is set. */ if (smb->pdata->use_mains) dc = !(val & IRQSTAT_E_DCIN_UV_STAT); if (smb->pdata->use_usb) usb = !(val & IRQSTAT_E_USBIN_UV_STAT); mutex_lock(&smb->lock); ret = smb->mains_online != dc || smb->usb_online != usb; smb->mains_online = dc; smb->usb_online = usb; mutex_unlock(&smb->lock); return ret; } /* * smb347_is_ps_online - returns whether input power source is connected * @smb: pointer to smb347 charger instance * * Returns %true if input power source is connected. Note that this is * dependent on what platform has configured for usable power sources. For * example if USB is disabled, this will return %false even if the USB cable * is connected. */ static bool smb347_is_ps_online(struct smb347_charger *smb) { bool ret; mutex_lock(&smb->lock); ret = smb->usb_online || smb->mains_online; mutex_unlock(&smb->lock); return ret; } /** * smb347_charging_status - returns status of charging * @smb: pointer to smb347 charger instance * * Function returns charging status. %0 means no charging is in progress, * %1 means pre-charging, %2 fast-charging and %3 taper-charging. */ static int smb347_charging_status(struct smb347_charger *smb) { unsigned int val; int ret; if (!smb347_is_ps_online(smb)) return 0; ret = regmap_read(smb->regmap, STAT_C, &val); if (ret < 0) return 0; return (val & STAT_C_CHG_MASK) >> STAT_C_CHG_SHIFT; } static int smb347_charging_set(struct smb347_charger *smb, bool enable) { int ret = 0; if (smb->pdata->enable_control != SMB347_CHG_ENABLE_SW) { dev_dbg(smb->dev, "charging enable/disable in SW disabled\n"); return 0; } mutex_lock(&smb->lock); if (smb->charging_enabled != enable) { ret = regmap_update_bits(smb->regmap, CMD_A, CMD_A_CHG_ENABLED, enable ? CMD_A_CHG_ENABLED : 0); if (!ret) smb->charging_enabled = enable; } mutex_unlock(&smb->lock); return ret; } static inline int smb347_charging_enable(struct smb347_charger *smb) { return smb347_charging_set(smb, true); } static inline int smb347_charging_disable(struct smb347_charger *smb) { return smb347_charging_set(smb, false); } static int smb347_start_stop_charging(struct smb347_charger *smb) { int ret; /* * Depending on whether valid power source is connected or not, we * disable or enable the charging. We do it manually because it * depends on how the platform has configured the valid inputs. */ if (smb347_is_ps_online(smb)) { ret = smb347_charging_enable(smb); if (ret < 0) dev_err(smb->dev, "failed to enable charging\n"); } else { ret = smb347_charging_disable(smb); if (ret < 0) dev_err(smb->dev, "failed to disable charging\n"); } return ret; } static int smb347_set_charge_current(struct smb347_charger *smb) { int ret; if (smb->pdata->max_charge_current) { ret = current_to_hw(fcc_tbl, ARRAY_SIZE(fcc_tbl), smb->pdata->max_charge_current); if (ret < 0) return ret; ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT, CFG_CHARGE_CURRENT_FCC_MASK, ret << CFG_CHARGE_CURRENT_FCC_SHIFT); if (ret < 0) return ret; } if (smb->pdata->pre_charge_current) { ret = current_to_hw(pcc_tbl, ARRAY_SIZE(pcc_tbl), smb->pdata->pre_charge_current); if (ret < 0) return ret; ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT, CFG_CHARGE_CURRENT_PCC_MASK, ret << CFG_CHARGE_CURRENT_PCC_SHIFT); if (ret < 0) return ret; } if (smb->pdata->termination_current) { ret = current_to_hw(tc_tbl, ARRAY_SIZE(tc_tbl), smb->pdata->termination_current); if (ret < 0) return ret; ret = regmap_update_bits(smb->regmap, CFG_CHARGE_CURRENT, CFG_CHARGE_CURRENT_TC_MASK, ret); if (ret < 0) return ret; } return 0; } static int smb347_set_current_limits(struct smb347_charger *smb) { int ret; if (smb->pdata->mains_current_limit) { ret = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), smb->pdata->mains_current_limit); if (ret < 0) return ret; ret = regmap_update_bits(smb->regmap, CFG_CURRENT_LIMIT, CFG_CURRENT_LIMIT_DC_MASK, ret << CFG_CURRENT_LIMIT_DC_SHIFT); if (ret < 0) return ret; } if (smb->pdata->usb_hc_current_limit) { ret = current_to_hw(icl_tbl, ARRAY_SIZE(icl_tbl), smb->pdata->usb_hc_current_limit); if (ret < 0) return ret; ret = regmap_update_bits(smb->regmap, CFG_CURRENT_LIMIT, CFG_CURRENT_LIMIT_USB_MASK, ret); if (ret < 0) return ret; } return 0; } static int smb347_set_voltage_limits(struct smb347_charger *smb) { int ret; if (smb->pdata->pre_to_fast_voltage) { ret = smb->pdata->pre_to_fast_voltage; /* uV */ ret = clamp_val(ret, 2400000, 3000000) - 2400000; ret /= 200000; ret = regmap_update_bits(smb->regmap, CFG_FLOAT_VOLTAGE, CFG_FLOAT_VOLTAGE_THRESHOLD_MASK, ret << CFG_FLOAT_VOLTAGE_THRESHOLD_SHIFT); if (ret < 0) return ret; } if (smb->pdata->max_charge_voltage) { ret = smb->pdata->max_charge_voltage; /* uV */ ret = clamp_val(ret, 3500000, 4500000) - 3500000; ret /= 20000; ret = regmap_update_bits(smb->regmap, CFG_FLOAT_VOLTAGE, CFG_FLOAT_VOLTAGE_FLOAT_MASK, ret); if (ret < 0) return ret; } return 0; } static int smb347_set_temp_limits(struct smb347_charger *smb) { bool enable_therm_monitor = false; int ret = 0; int val; if (smb->pdata->chip_temp_threshold) { val = smb->pdata->chip_temp_threshold; /* degree C */ val = clamp_val(val, 100, 130) - 100; val /= 10; ret = regmap_update_bits(smb->regmap, CFG_OTG, CFG_OTG_TEMP_THRESHOLD_MASK, val << CFG_OTG_TEMP_THRESHOLD_SHIFT); if (ret < 0) return ret; } if (smb->pdata->soft_cold_temp_limit != SMB347_TEMP_USE_DEFAULT) { val = smb->pdata->soft_cold_temp_limit; val = clamp_val(val, 0, 15); val /= 5; /* this goes from higher to lower so invert the value */ val = ~val & 0x3; ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT, CFG_TEMP_LIMIT_SOFT_COLD_MASK, val << CFG_TEMP_LIMIT_SOFT_COLD_SHIFT); if (ret < 0) return ret; enable_therm_monitor = true; } if (smb->pdata->soft_hot_temp_limit != SMB347_TEMP_USE_DEFAULT) { val = smb->pdata->soft_hot_temp_limit; val = clamp_val(val, 40, 55) - 40; val /= 5; ret = regmap_update_bits(smb->regmap, CFG_TEMP_LIMIT, CFG_TEMP_LIMIT_SOFT_HOT_MASK, val << CFG_TEMP_LIMIT_SOFT_HOT_SHIFT); if (ret < 0) return ret; enable_therm_monitor = true; } if (smb->pdata->hard_cold_temp_limit != SMB347_TEMP_USE_DEFAULT) { val = smb->pdata->hard_cold_temp_limit;
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_CPU_SUBTYPE_SH7751R=y
CONFIG_MEMORY_START=0x08030000
CONFIG_MEMORY_SIZE=0x7fd0000
CONFIG_FLATMEM_MANUAL=y
CONFIG_SH_TITAN=y
CONFIG_SH_PCLK_FREQ=30000000
CONFIG_SH_DMA=y
CONFIG_SH_DMA_API=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_CMDLINE_OVERWRITE=y
CONFIG_CMDLINE="console=ttySC1,38400N81 root=/dev/nfs ip=:::::eth1:autoconf rw"
CONFIG_PCI=y
CONFIG_HOTPLUG_PCI=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
CONFIG_NET_IPIP=y
CONFIG_NET_IPGRE=y
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
CONFIG_INET_IPCOMP=y
# CONFIG_INET_LRO is not set
CONFIG_INET_DIAG=m
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
CONFIG_INET6_AH=y
CONFIG_INET6_ESP=y
CONFIG_INET6_IPCOMP=y
CONFIG_IPV6_SIT=m
CONFIG_IPV6_TUNNEL=y
CONFIG_NETFILTER=y
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
CONFIG_NETFILTER_XT_MATCH_MAC=m
CONFIG_NETFILTER_XT_MATCH_MARK=m
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
CONFIG_NETFILTER_XT_MATCH_POLICY=m
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_SCTP=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
CONFIG_IP_NF_QUEUE=m
CONFIG_IP_NF_IPTABLES=m
CONFIG_IP_NF_MATCH_ADDRTYPE=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_ECN=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_FILTER=m
CONFIG_IP_NF_TARGET_REJECT=m
CONFIG_IP_NF_TARGET_LOG=m
CONFIG_IP_NF_TARGET_ULOG=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_RAW=m
CONFIG_IP_NF_ARPTABLES=m
CONFIG_IP_NF_ARPFILTER=m
CONFIG_IP_NF_ARP_MANGLE=m
CONFIG_IP6_NF_QUEUE=m
CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP6_NF_MATCH_AH=m
CONFIG_IP6_NF_MATCH_EUI64=m
CONFIG_IP6_NF_MATCH_FRAG=m
CONFIG_IP6_NF_MATCH_OPTS=m
CONFIG_IP6_NF_MATCH_HL=m
CONFIG_IP6_NF_MATCH_IPV6HEADER=m
CONFIG_IP6_NF_MATCH_RT=m
CONFIG_IP6_NF_TARGET_HL=m
CONFIG_IP6_NF_TARGET_LOG=m
CONFIG_IP6_NF_FILTER=m
CONFIG_IP6_NF_TARGET_REJECT=m
CONFIG_IP6_NF_MANGLE=m
CONFIG_IP6_NF_RAW=m
CONFIG_BRIDGE=y
CONFIG_VLAN_8021Q=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_CBQ=m
CONFIG_NET_SCH_HTB=m
CONFIG_NET_SCH_HFSC=m
CONFIG_NET_SCH_PRIO=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
CONFIG_NET_SCH_TBF=m
CONFIG_NET_SCH_GRED=m
CONFIG_NET_SCH_DSMARK=m
CONFIG_NET_SCH_NETEM=m
CONFIG_NET_SCH_INGRESS=m
CONFIG_NET_CLS_BASIC=m
CONFIG_NET_CLS_TCINDEX=m
CONFIG_NET_CLS_ROUTE4=m
CONFIG_NET_CLS_FW=m
CONFIG_NET_CLS_U32=m
CONFIG_CLS_U32_PERF=y
CONFIG_CLS_U32_MARK=y
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_EMATCH=y
CONFIG_NET_EMATCH_CMP=m
CONFIG_NET_EMATCH_NBYTE=m
CONFIG_NET_EMATCH_U32=m
CONFIG_NET_EMATCH_META=m
CONFIG_NET_EMATCH_TEXT=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
CONFIG_NET_ACT_GACT=m
CONFIG_GACT_PROB=y
CONFIG_NET_ACT_MIRRED=m
CONFIG_NET_ACT_IPT=m
CONFIG_NET_ACT_PEDIT=m
CONFIG_NET_CLS_IND=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_FW_LOADER=m
CONFIG_CONNECTOR=m
CONFIG_MTD=m
CONFIG_MTD_DEBUG=y
CONFIG_MTD_CHAR=m
CONFIG_MTD_BLOCK=m
CONFIG_FTL=m
CONFIG_NFTL=m
CONFIG_INFTL=m
CONFIG_RFD_FTL=m
CONFIG_MTD_CFI=m
CONFIG_MTD_JEDECPROBE=m
CONFIG_MTD_NAND=m
CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_RAM=y
CONFIG_ATA_OVER_ETH=m
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=m
CONFIG_BLK_DEV_SR=m
CONFIG_CHR_DEV_SG=m
CONFIG_NETDEVICES=y
CONFIG_TUN=m
CONFIG_PHYLIB=m
CONFIG_MARVELL_PHY=m
CONFIG_DAVICOM_PHY=m
CONFIG_QSEMI_PHY=m
CONFIG_LXT_PHY=m
CONFIG_CICADA_PHY=m
CONFIG_NET_ETHERNET=y
CONFIG_NET_PCI=y
CONFIG_8139TOO=y
# CONFIG_8139TOO_PIO is not set
CONFIG_8139TOO_TUNE_TWISTER=y
CONFIG_8139_OLD_RX_RESET=y
CONFIG_USB_CATC=m
CONFIG_USB_KAWETH=m
CONFIG_USB_PEGASUS=m
CONFIG_USB_RTL8150=m
CONFIG_USB_USBNET=m
CONFIG_USB_NET_PLUSB=m
# CONFIG_USB_NET_CDC_SUBSET is not set
CONFIG_PPP=m
CONFIG_PPP_MULTILINK=y
CONFIG_PPP_FILTER=y
CONFIG_PPP_ASYNC=m
CONFIG_PPP_SYNC_TTY=m
CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_MPPE=m
CONFIG_PPPOE=m
CONFIG_SLIP=m
CONFIG_SLIP_COMPRESSED=y
CONFIG_SLIP_SMART=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_WATCHDOG=y
CONFIG_SH_WDT=m
# CONFIG_USB_HID is not set
CONFIG_USB=y
CONFIG_USB_MON=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_ACM=m
CONFIG_USB_PRINTER=m
CONFIG_USB_STORAGE=y
CONFIG_USB_SERIAL=m
CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_ARK3116=m
CONFIG_USB_SERIAL_PL2303=m
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_SH=m
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
# CONFIG_EXT3_FS_XATTR is not set
CONFIG_REISERFS_FS=m
CONFIG_XFS_FS=m
CONFIG_FUSE_FS=m
CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
CONFIG_CONFIGFS_FS=m
CONFIG_ROMFS_FS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
CONFIG_SMB_FS=m
CONFIG_CIFS=m
CONFIG_CIFS_WEAK_PW_HASH=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_ASCII=m
CONFIG_NLS_ISO8859_1=m
CONFIG_NLS_UTF8=m
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_MD4=m
CONFIG_CRYPTO_MICHAEL_MIC=y
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRC16=m
CONFIG_LIBCRC32C=m
EINVAL; smb = devm_kzalloc(dev, sizeof(*smb), GFP_KERNEL); if (!smb) return -ENOMEM; i2c_set_clientdata(client, smb); mutex_init(&smb->lock); smb->dev = &client->dev; smb->pdata = pdata; smb->regmap = devm_regmap_init_i2c(client, &smb347_regmap); if (IS_ERR(smb->regmap)) return PTR_ERR(smb->regmap); ret = smb347_hw_init(smb); if (ret < 0) return ret; mains_usb_cfg.supplied_to = battery; mains_usb_cfg.num_supplicants = ARRAY_SIZE(battery); mains_usb_cfg.drv_data = smb; if (smb->pdata->use_mains) { smb->mains = power_supply_register(dev, &smb347_mains_desc, &mains_usb_cfg); if (IS_ERR(smb->mains)) return PTR_ERR(smb->mains); } if (smb->pdata->use_usb) { smb->usb = power_supply_register(dev, &smb347_usb_desc, &mains_usb_cfg); if (IS_ERR(smb->usb)) { if (smb->pdata->use_mains) power_supply_unregister(smb->mains); return PTR_ERR(smb->usb); } } battery_cfg.drv_data = smb; smb->battery = power_supply_register(dev, &smb347_battery_desc, &battery_cfg); if (IS_ERR(smb->battery)) { if (smb->pdata->use_usb) power_supply_unregister(smb->usb); if (smb->pdata->use_mains) power_supply_unregister(smb->mains); return PTR_ERR(smb->battery); } /* * Interrupt pin is optional. If it is connected, we setup the * interrupt support here. */ if (pdata->irq_gpio >= 0) { ret = smb347_irq_init(smb, client); if (ret < 0) { dev_warn(dev, "failed to initialize IRQ: %d\n", ret); dev_warn(dev, "disabling IRQ support\n"); } else { smb347_irq_enable(smb); } } return 0; } static int smb347_remove(struct i2c_client *client) { struct smb347_charger *smb = i2c_get_clientdata(client); if (client->irq) { smb347_irq_disable(smb); free_irq(client->irq, smb); gpio_free(smb->pdata->irq_gpio); } power_supply_unregister(smb->battery); if (smb->pdata->use_usb) power_supply_unregister(smb->usb); if (smb->pdata->use_mains) power_supply_unregister(smb->mains); return 0; } static const struct i2c_device_id smb347_id[] = { { "smb347", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, smb347_id); static struct i2c_driver smb347_driver = { .driver = { .name = "smb347", }, .probe = smb347_probe, .remove = smb347_remove, .id_table = smb347_id, }; module_i2c_driver(smb347_driver); MODULE_AUTHOR("Bruce E. Robertson "); MODULE_AUTHOR("Mika Westerberg "); MODULE_DESCRIPTION("SMB347 battery charger driver"); MODULE_LICENSE("GPL");