static ssize_t max8997_muic_show_status(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{
	struct max8997_muic_info *info = dev_get_drvdata(dev);
	u8 devid, int_value[3], status[3], intmask[3], ctrl[3], cdetctrl;

	max8997_read_reg(info->muic, MAX8997_MUIC_REG_ID, &devid);
	max8997_bulk_read(info->muic, MAX8997_MUIC_REG_INT1, 3, int_value);
	max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, 3, status);
	max8997_bulk_read(info->muic, MAX8997_MUIC_REG_INTMASK1, 3, intmask);
	max8997_bulk_read(info->muic, MAX8997_MUIC_REG_CTRL1, 3, ctrl);
	max8997_read_reg(info->muic, MAX8997_MUIC_REG_CDETCTRL, &cdetctrl);

	return sprintf(buf,
		       "Device ID(0x%02x)\n"
			   "INT1(0x%02x), INT2(0x%02x), INT3(0x%02x)\n"
		       "STATUS1(0x%02x), STATUS2(0x%02x), STATUS3(0x%02x)\n"
		       "INTMASK1(0x%02x), INTMASK2(0x%02x), INTMASK3(0x%02x)\n"
		       "CTRL1(0x%02x), CTRL2(0x%02x), CTRL3(0x%02x)\n"
		       "CDETCTRL(0x%02x)\n",
		       devid, int_value[0], int_value[1], int_value[2],
		       status[0], status[1], status[2],
		       intmask[0], intmask[1], intmask[2],
		       ctrl[0], ctrl[1], ctrl[2],
		       cdetctrl);
}
Example #2
0
static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info)
{
	u8 data[RTC_NR_TIME];
	int ret, i;

	if (!mutex_is_locked(&info->lock))
		dev_warn(info->dev, "%s: should have mutex locked\n", __func__);

	ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
				data);
	if (ret < 0) {
		dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
				__func__, ret);
		goto out;
	}

	for (i = 0; i < RTC_NR_TIME; i++)
		data[i] &= ~ALARM_ENABLE_MASK;

	ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
				 data);
	if (ret < 0) {
		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
				__func__, ret);
		goto out;
	}

	ret = max8997_rtc_set_update_reg(info);
out:
	return ret;
}
Example #3
0
static void max8997_muic_irq_work(struct work_struct *work)
{
	struct max8997_muic_info *info = container_of(work,
			struct max8997_muic_info, irq_work);
	int irq_type = 0;
	int i, ret;

	if (!info->edev)
		return;

	mutex_lock(&info->mutex);

	for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
		if (info->irq == muic_irqs[i].virq)
			irq_type = muic_irqs[i].irq;

	ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
				2, info->status);
	if (ret) {
		dev_err(info->dev, "failed to read muic register\n");
		mutex_unlock(&info->mutex);
		return;
	}

	switch (irq_type) {
	case MAX8997_MUICIRQ_ADCError:
	case MAX8997_MUICIRQ_ADCLow:
	case MAX8997_MUICIRQ_ADC:
		/* Handle all of cable except for charger cable */
		ret = max8997_muic_adc_handler(info);
		break;
	case MAX8997_MUICIRQ_VBVolt:
	case MAX8997_MUICIRQ_DBChg:
	case MAX8997_MUICIRQ_DCDTmr:
	case MAX8997_MUICIRQ_ChgDetRun:
	case MAX8997_MUICIRQ_ChgTyp:
		/* Handle charger cable */
		ret = max8997_muic_chg_handler(info);
		break;
	case MAX8997_MUICIRQ_OVP:
		break;
	default:
		dev_info(info->dev, "misc interrupt: irq %d occurred\n",
				irq_type);
		mutex_unlock(&info->mutex);
		return;
	}

	if (ret < 0)
		dev_err(info->dev, "failed to handle MUIC interrupt\n");

	mutex_unlock(&info->mutex);
}
static void max8997_muic_detect_dev(struct max8997_muic_info *info)
{
	struct i2c_client *client = info->muic;
	u8 status[2];
	u8 adc, chgtyp, adcerr;
	int intr = INT_ATTACH;
	int ret;

	ret = max8997_bulk_read(client, MAX8997_MUIC_REG_STATUS1, 2, status);
	if (ret) {
		dev_err(info->dev, "%s: fail to read muic reg(%d)\n", __func__,
				ret);
		return;
	}

	dev_info(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
			status[0], status[1]);

	if (max8997_muic_handle_dock_vol_key(info, status[0]))
		return;

	adc = status[0] & STATUS1_ADC_MASK;
	adcerr = status[0] & STATUS1_ADCERR_MASK;
	chgtyp = status[1] & STATUS2_CHGTYP_MASK;

	if (!adcerr && adc == ADC_OPEN) {
		if (chgtyp == CHGTYP_NO_VOLTAGE)
			intr = INT_DETACH;
		else if (chgtyp == CHGTYP_USB ||
				chgtyp == CHGTYP_DOWNSTREAM_PORT ||
				chgtyp == CHGTYP_DEDICATED_CHGR ||
				chgtyp == CHGTYP_500MA	||
				chgtyp == CHGTYP_1A) {
			if (info->cable_type == CABLE_TYPE_OTG ||
			    info->cable_type == CABLE_TYPE_DESKDOCK ||
			    info->cable_type == CABLE_TYPE_CARDOCK)
				intr = INT_DETACH;
		}
	}

	if (intr == INT_ATTACH) {
		dev_info(info->dev, "%s: ATTACHED\n", __func__);
		max8997_muic_handle_attach(info, status[0], status[1]);
	} else {
		dev_info(info->dev, "%s: DETACHED\n", __func__);
		max8997_muic_handle_detach(info);
	}
	return;
}
static void max8997_muic_irq_work(struct work_struct *work)
{
	struct max8997_muic_info *info = container_of(work,
			struct max8997_muic_info, irq_work);
	struct max8997_platform_data *pdata =
				dev_get_platdata(info->iodev->dev);
	u8 status[3];
	u8 adc, chg_type;

	int irq_type = info->irq - pdata->irq_base;
	int ret;

	mutex_lock(&info->mutex);

	ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
				3, status);
	if (ret) {
		dev_err(info->dev, "failed to read muic register\n");
		mutex_unlock(&info->mutex);
		return;
	}

	dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
			status[0], status[1]);

	switch (irq_type) {
	case MAX8997_MUICIRQ_ADC:
		adc = status[0] & STATUS1_ADC_MASK;
		adc >>= STATUS1_ADC_SHIFT;

		max8997_muic_handle_adc(info, adc);
		break;
	case MAX8997_MUICIRQ_ChgTyp:
		chg_type = status[1] & STATUS2_CHGTYP_MASK;
		chg_type >>= STATUS2_CHGTYP_SHIFT;

		max8997_muic_handle_charger_type(info, chg_type);
		break;
	default:
		dev_info(info->dev, "misc interrupt: %s occurred\n",
			 muic_irqs[irq_type].name);
		break;
	}

	mutex_unlock(&info->mutex);

	return;
}
Example #6
0
static int max8997_muic_detect_dev(struct max8997_muic_info *info)
{
	int ret = 0;
	int adc;
	int chg_type;
	bool attached;

	mutex_lock(&info->mutex);

	/* Read STATUSx register to detect accessory */
	ret = max8997_bulk_read(info->muic,
			MAX8997_MUIC_REG_STATUS1, 2, info->status);
	if (ret) {
		dev_err(info->dev, "failed to read MUIC register\n");
		mutex_unlock(&info->mutex);
		return ret;
	}

	adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC,
					&attached);
	if (attached && adc != MAX8997_MUIC_ADC_OPEN) {
		ret = max8997_muic_adc_handler(info);
		if (ret < 0) {
			dev_err(info->dev, "Cannot detect ADC cable\n");
			mutex_unlock(&info->mutex);
			return ret;
		}
	}

	chg_type = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_CHG,
					&attached);
	if (attached && chg_type != MAX8997_CHARGER_TYPE_NONE) {
		ret = max8997_muic_chg_handler(info);
		if (ret < 0) {
			dev_err(info->dev, "Cannot detect charger cable\n");
			mutex_unlock(&info->mutex);
			return ret;
		}
	}

	mutex_unlock(&info->mutex);

	return 0;
}
Example #7
0
static int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct max8997_rtc_info *info = dev_get_drvdata(dev);
	u8 data[RTC_NR_TIME];
	u8 val;
	int i, ret;

	mutex_lock(&info->lock);

	ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
			data);
	if (ret < 0) {
		dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
				__func__, __LINE__, ret);
		goto out;
	}

	max8997_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);

	alrm->enabled = 0;
	for (i = 0; i < RTC_NR_TIME; i++) {
		if (data[i] & ALARM_ENABLE_MASK) {
			alrm->enabled = 1;
			break;
		}
	}

	alrm->pending = 0;
	ret = max8997_read_reg(info->max8997->i2c, MAX8997_REG_STATUS1, &val);
	if (ret < 0) {
		dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n",
				__func__, __LINE__, ret);
		goto out;
	}

	if (val & (1 << 4)) /* RTCA1 */
		alrm->pending = 1;

out:
	mutex_unlock(&info->lock);
	return 0;
}
Example #8
0
static int max8997_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	struct max8997_rtc_info *info = dev_get_drvdata(dev);
	u8 data[RTC_NR_TIME];
	int ret;

	mutex_lock(&info->lock);
	ret = max8997_bulk_read(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data);
	mutex_unlock(&info->lock);

	if (ret < 0) {
		dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
				ret);
		return ret;
	}

	max8997_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);

	return rtc_valid_tm(tm);
}
Example #9
0
static int max8997_rtc_start_alarm(struct max8997_rtc_info *info)
{
	u8 data[RTC_NR_TIME];
	int ret;

	if (!mutex_is_locked(&info->lock))
		dev_warn(info->dev, "%s: should have mutex locked\n", __func__);

	ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
				data);
	if (ret < 0) {
		dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
				__func__, ret);
		goto out;
	}

	data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
	data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
	data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
	data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
	if (data[RTC_MONTH] & 0xf)
		data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
	if (data[RTC_YEAR] & 0x7f)
		data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
	if (data[RTC_DATE] & 0x1f)
		data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);

	ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
				 data);
	if (ret < 0) {
		dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
				__func__, ret);
		goto out;
	}

	ret = max8997_rtc_set_update_reg(info);
out:
	return ret;
}
static void max8997_muic_detect_dev(struct max8997_muic_info *info)
{
	int ret;
	u8 status[2], adc, chg_type;

	ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
				2, status);
	if (ret) {
		dev_err(info->dev, "failed to read muic register\n");
		return;
	}

	dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n",
			status[0], status[1]);

	adc = status[0] & STATUS1_ADC_MASK;
	adc >>= STATUS1_ADC_SHIFT;

	chg_type = status[1] & STATUS2_CHGTYP_MASK;
	chg_type >>= STATUS2_CHGTYP_SHIFT;

	max8997_muic_handle_adc(info, adc);
	max8997_muic_handle_charger_type(info, chg_type);
}
static void max8997_muic_detect_dev(struct max8997_muic_info *info, int irq)
{
	struct i2c_client *client = info->muic;
	u8 status[2];
	u8 adc, chgtyp, adcerr;
	int intr = INT_ATTACH;
	int ret;

	ret = max8997_bulk_read(client, MAX8997_MUIC_REG_STATUS1, 2, status);
	if (ret) {
		dev_err(info->dev, "%s: fail to read muic reg(%d)\n", __func__,
				ret);
		return;
	}

	dev_info(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
			status[0], status[1]);

	if ((irq == info->irq_adc) &&
			max8997_muic_handle_dock_vol_key(info, status[0]))
		return;

	adc = status[0] & STATUS1_ADC_MASK;
	adcerr = status[0] & STATUS1_ADCERR_MASK;
	chgtyp = status[1] & STATUS2_CHGTYP_MASK;

	switch (adc) {
	case ADC_MHL:
#if defined(CONFIG_MACH_U1)
		break;
#endif
	case (ADC_MHL + 1):
	case (ADC_DOCK_VOL_DN - 1):
	case (ADC_DOCK_PLAY_PAUSE_KEY + 2) ... (ADC_CEA936ATYPE1_CHG - 1):
	case (ADC_CARDOCK + 1):
		dev_warn(info->dev, "%s: unsupported ADC(0x%02x)\n", __func__, adc);
		intr = INT_DETACH;
		break;
	case ADC_OPEN:
		if (!adcerr) {
			if (chgtyp == CHGTYP_NO_VOLTAGE)
				intr = INT_DETACH;
			else if (chgtyp == CHGTYP_USB ||
					chgtyp == CHGTYP_DOWNSTREAM_PORT ||
					chgtyp == CHGTYP_DEDICATED_CHGR ||
					chgtyp == CHGTYP_500MA	||
					chgtyp == CHGTYP_1A) {
				if (info->cable_type == CABLE_TYPE_OTG ||
					info->cable_type == CABLE_TYPE_DESKDOCK ||
					info->cable_type == CABLE_TYPE_CARDOCK)
					intr = INT_DETACH;
			}
		}
		break;
	default:
		break;
	}

#if defined(CONFIG_MUIC_MAX8997_OVPUI)
	if (intr == INT_ATTACH) {
		if (irq == info->irq_chgins) {
			if (info->is_ovp_state) {
				max8997_muic_handle_attach(info, status[0],
					status[1]);
				info->is_ovp_state = false;
				dev_info(info->dev, "OVP recovered\n");
				return;
			} else {
				dev_info(info->dev, "Just inserted TA/USB\n");
				return;
			}
		} else if (irq == info->irq_chgrm) {
			max8997_muic_handle_detach(info);
			info->is_ovp_state = true;
			dev_info(info->dev, "OVP occured\n");
			return;
		}

	} else	{
		info->is_ovp_state = false;

		if (irq == info->irq_chgrm) {
			dev_info(info->dev, "Just removed TA/USB\n");
			return;
		}
	}
#endif

	if (intr == INT_ATTACH) {
		dev_info(info->dev, "%s: ATTACHED\n", __func__);
		max8997_muic_handle_attach(info, status[0], status[1]);
	} else {
		dev_info(info->dev, "%s: DETACHED\n", __func__);
		max8997_muic_handle_detach(info);
	}
	return;
}
Example #12
0
static irqreturn_t max8997_irq_thread(int irq, void *data)
{
	struct max8997_dev *max8997 = data;
	u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {};
	u8 irq_src;
	int ret;
	int i, cur_irq;

	ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src);
	if (ret < 0) {
		dev_err(max8997->dev, "Failed to read interrupt source: %d\n",
				ret);
		return IRQ_NONE;
	}

	if (irq_src & MAX8997_IRQSRC_PMIC) {
		/* PMIC INT1 ~ INT4 */
		max8997_bulk_read(max8997->i2c, MAX8997_REG_INT1, 4,
				&irq_reg[PMIC_INT1]);
	}
	if (irq_src & MAX8997_IRQSRC_FUELGAUGE) {
		/*
		 * TODO: FUEL GAUGE
		 *
		 * This is to be supported by Max17042 driver. When
		 * an interrupt incurs here, it should be relayed to a
		 * Max17042 device that is connected (probably by
		 * platform-data). However, we do not have interrupt
		 * handling in Max17042 driver currently. The Max17042 IRQ
		 * driver should be ready to be used as a stand-alone device and
		 * a Max8997-dependent device. Because it is not ready in
		 * Max17042-side and it is not too critical in operating
		 * Max8997, we do not implement this in initial releases.
		 */
		irq_reg[FUEL_GAUGE] = 0;
	}
	if (irq_src & MAX8997_IRQSRC_MUIC) {
		/* MUIC INT1 ~ INT3 */
		max8997_bulk_read(max8997->muic, MAX8997_MUIC_REG_INT1, 3,
				&irq_reg[MUIC_INT1]);
	}
	if (irq_src & MAX8997_IRQSRC_GPIO) {
		/* GPIO Interrupt */
		u8 gpio_info[MAX8997_NUM_GPIO];

		irq_reg[GPIO_LOW] = 0;
		irq_reg[GPIO_HI] = 0;

		max8997_bulk_read(max8997->i2c, MAX8997_REG_GPIOCNTL1,
				MAX8997_NUM_GPIO, gpio_info);
		for (i = 0; i < MAX8997_NUM_GPIO; i++) {
			bool interrupt = false;

			switch (gpio_info[i] & MAX8997_GPIO_INT_MASK) {
			case MAX8997_GPIO_INT_BOTH:
				if (max8997->gpio_status[i] != gpio_info[i])
					interrupt = true;
				break;
			case MAX8997_GPIO_INT_RISE:
				if ((max8997->gpio_status[i] != gpio_info[i]) &&
				    (gpio_info[i] & MAX8997_GPIO_DATA_MASK))
					interrupt = true;
				break;
			case MAX8997_GPIO_INT_FALL:
				if ((max8997->gpio_status[i] != gpio_info[i]) &&
				    !(gpio_info[i] & MAX8997_GPIO_DATA_MASK))
					interrupt = true;
				break;
			default:
				break;
			}

			if (interrupt) {
				if (i < 8)
					irq_reg[GPIO_LOW] |= (1 << i);
				else
					irq_reg[GPIO_HI] |= (1 << (i - 8));
			}

		}
	}
	if (irq_src & MAX8997_IRQSRC_FLASH) {
		/* Flash Status Interrupt */
		ret = max8997_read_reg(max8997->i2c, MAX8997_REG_FLASHSTATUS,
				&irq_reg[FLASH_STATUS]);
	}

	/* Apply masking */
	for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++)
		irq_reg[i] &= ~max8997->irq_masks_cur[i];

	/* Report */
	for (i = 0; i < MAX8997_IRQ_NR; i++) {
		if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) {
			cur_irq = irq_find_mapping(max8997->irq_domain, i);
			if (cur_irq)
				handle_nested_irq(cur_irq);
		}
	}

	return IRQ_HANDLED;
}