Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6fa6fb27 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: thermal: bcl_pmic5: Add multi peripheral support" into msm-4.14

parents 873ee8df a543f526
Loading
Loading
Loading
Loading
+77 −45
Original line number Diff line number Diff line
@@ -56,6 +56,8 @@
#define BCL_VBAT_INC_MV       25
#define BCL_VBAT_MAX_MV       3600

#define MAX_PERPH_COUNT       2

enum bcl_dev_type {
	BCL_IBAT_LVL0,
	BCL_IBAT_LVL1,
@@ -73,6 +75,8 @@ static char bcl_int_names[BCL_TYPE_MAX][25] = {
	"bcl-vbat-lvl2",
};

struct bcl_device;

struct bcl_peripheral_data {
	int                     irq_num;
	long int		trip_thresh;
@@ -82,6 +86,7 @@ struct bcl_peripheral_data {
	enum bcl_dev_type	type;
	struct thermal_zone_of_device_ops ops;
	struct thermal_zone_device *tz_dev;
	struct bcl_device	*dev;
};

struct bcl_device {
@@ -90,9 +95,11 @@ struct bcl_device {
	struct bcl_peripheral_data	param[BCL_TYPE_MAX];
};

static struct bcl_device *bcl_perph;
static struct bcl_device *bcl_devices[MAX_PERPH_COUNT];
static int bcl_device_ct;

static int bcl_read_register(int16_t reg_offset, unsigned int *data)
static int bcl_read_register(struct bcl_device *bcl_perph, int16_t reg_offset,
				unsigned int *data)
{
	int ret = 0;

@@ -104,26 +111,32 @@ static int bcl_read_register(int16_t reg_offset, unsigned int *data)
			       (bcl_perph->fg_bcl_addr + reg_offset),
			       data);
	if (ret < 0)
		pr_err("Error reading register %d. err:%d\n",
				reg_offset, ret);
		pr_err("Error reading register 0x%04x err:%d\n",
				bcl_perph->fg_bcl_addr + reg_offset, ret);
	else
		pr_debug("Read register:0x%04x value:0x%02x\n",
				bcl_perph->fg_bcl_addr + reg_offset,
				*data);

	return ret;
}

static int bcl_write_general_register(int16_t reg_offset,
					uint16_t base, uint8_t data)
static int bcl_write_register(struct bcl_device *bcl_perph,
				int16_t reg_offset, uint8_t data)
{
	int  ret = 0;
	uint8_t *write_buf = &data;
	uint16_t base;

	if (!bcl_perph) {
		pr_err("BCL device not initialized\n");
		return -EINVAL;
	}
	base = bcl_perph->fg_bcl_addr;
	ret = regmap_write(bcl_perph->regmap, (base + reg_offset), *write_buf);
	if (ret < 0) {
		pr_err("Error reading register %d. err:%d\n",
				reg_offset, ret);
		pr_err("Error reading register:0x%04x val:0x%02x err:%d\n",
				base + reg_offset, data, ret);
		return ret;
	}
	pr_debug("wrote 0x%02x to 0x%04x\n", data, base + reg_offset);
@@ -131,12 +144,6 @@ static int bcl_write_general_register(int16_t reg_offset,
	return ret;
}

static int bcl_write_register(int16_t reg_offset, uint8_t data)
{
	return bcl_write_general_register(reg_offset,
			bcl_perph->fg_bcl_addr, data);
}

static void convert_adc_to_vbat_thresh_val(int *val)
{
	/*
@@ -190,18 +197,21 @@ static int bcl_set_ibat(void *data, int low, int high)
	ibat_ua = thresh_value;
	convert_ibat_to_adc_val(&thresh_value);
	val = (int8_t)thresh_value;
	if (&bcl_perph->param[BCL_IBAT_LVL0] == bat_data) {
	switch (bat_data->type) {
	case BCL_IBAT_LVL0:
		addr = BCL_IBAT_HIGH;
		pr_debug("ibat high threshold:%d mA ADC:0x%02x\n",
				ibat_ua, val);
	} else if (&bcl_perph->param[BCL_IBAT_LVL1] == bat_data) {
		break;
	case BCL_IBAT_LVL1:
		addr = BCL_IBAT_TOO_HIGH;
		pr_debug("ibat too high threshold:%d mA ADC:0x%02x\n",
				ibat_ua, val);
	} else {
		break;
	default:
		goto set_trip_exit;
	}
	ret = bcl_write_register(addr, val);
	ret = bcl_write_register(bat_data->dev, addr, val);
	if (ret)
		goto set_trip_exit;
	bat_data->trip_thresh = ibat_ua;
@@ -225,7 +235,7 @@ static int bcl_read_ibat(void *data, int *adc_value)
		(struct bcl_peripheral_data *)data;

	*adc_value = val;
	ret = bcl_read_register(BCL_IBAT_READ, &val);
	ret = bcl_read_register(bat_data->dev, BCL_IBAT_READ, &val);
	if (ret)
		goto bcl_read_exit;
	/* IBat ADC reading is in 2's compliment form */
@@ -255,16 +265,21 @@ static int bcl_get_vbat_trip(void *data, int type, int *trip)
	int16_t addr;

	*trip = 0;
	if (&bcl_perph->param[BCL_VBAT_LVL0] == bat_data)
	switch (bat_data->type) {
	case BCL_VBAT_LVL0:
		addr = BCL_VBAT_ADC_LOW;
	else if (&bcl_perph->param[BCL_VBAT_LVL1] == bat_data)
		break;
	case BCL_VBAT_LVL1:
		addr = BCL_VBAT_COMP_LOW;
	else if (&bcl_perph->param[BCL_VBAT_LVL2] == bat_data)
		break;
	case BCL_VBAT_LVL2:
		addr = BCL_VBAT_COMP_TLOW;
	else
		break;
	default:
		return -ENODEV;
	}

	ret = bcl_read_register(addr, &val);
	ret = bcl_read_register(bat_data->dev, addr, &val);
	if (ret)
		return ret;

@@ -321,7 +336,7 @@ static int bcl_read_vbat(void *data, int *adc_value)
		(struct bcl_peripheral_data *)data;

	*adc_value = val;
	ret = bcl_read_register(BCL_VBAT_READ, &val);
	ret = bcl_read_register(bat_data->dev, BCL_VBAT_READ, &val);
	if (ret)
		goto bcl_read_exit;
	*adc_value = val;
@@ -344,6 +359,7 @@ static irqreturn_t bcl_handle_irq(int irq, void *data)
	unsigned int irq_status = 0;
	int ret;
	bool notify = false;
	struct bcl_device *bcl_perph;

	mutex_lock(&perph_data->state_trans_lock);
	if (!perph_data->irq_enabled) {
@@ -354,7 +370,8 @@ static irqreturn_t bcl_handle_irq(int irq, void *data)
	}
	mutex_unlock(&perph_data->state_trans_lock);

	ret = bcl_read_register(BCL_IRQ_STATUS, &irq_status);
	bcl_perph = perph_data->dev;
	ret = bcl_read_register(bcl_perph, BCL_IRQ_STATUS, &irq_status);
	if (ret) {
		disable_irq_nosync(irq);
		perph_data->irq_enabled = false;
@@ -415,7 +432,8 @@ static irqreturn_t bcl_handle_irq(int irq, void *data)
	return IRQ_HANDLED;
}

static int bcl_get_devicetree_data(struct platform_device *pdev)
static int bcl_get_devicetree_data(struct platform_device *pdev,
					struct bcl_device *bcl_perph)
{
	int ret = 0;
	const __be32 *prop = NULL;
@@ -466,13 +484,14 @@ static void bcl_fetch_trip(struct platform_device *pdev, enum bcl_dev_type type,
}

static void bcl_vbat_init(struct platform_device *pdev,
		enum bcl_dev_type type)
		enum bcl_dev_type type, struct bcl_device *bcl_perph)
{
	struct bcl_peripheral_data *vbat = &bcl_perph->param[type];
	irqreturn_t (*handle)(int, void *) = bcl_handle_irq;

	mutex_init(&vbat->state_trans_lock);
	vbat->type = type;
	vbat->dev = bcl_perph;
	bcl_fetch_trip(pdev, type, vbat, handle);
	vbat->ops.get_temp = bcl_read_vbat;
	vbat->ops.set_trips = bcl_set_vbat;
@@ -489,20 +508,22 @@ static void bcl_vbat_init(struct platform_device *pdev,
	thermal_zone_device_update(vbat->tz_dev, THERMAL_DEVICE_UP);
}

static void bcl_probe_vbat(struct platform_device *pdev)
static void bcl_probe_vbat(struct platform_device *pdev,
					struct bcl_device *bcl_perph)
{
	bcl_vbat_init(pdev, BCL_VBAT_LVL0);
	bcl_vbat_init(pdev, BCL_VBAT_LVL1);
	bcl_vbat_init(pdev, BCL_VBAT_LVL2);
	bcl_vbat_init(pdev, BCL_VBAT_LVL0, bcl_perph);
	bcl_vbat_init(pdev, BCL_VBAT_LVL1, bcl_perph);
	bcl_vbat_init(pdev, BCL_VBAT_LVL2, bcl_perph);
}

static void bcl_ibat_init(struct platform_device *pdev,
				enum bcl_dev_type type)
			enum bcl_dev_type type, struct bcl_device *bcl_perph)
{
	struct bcl_peripheral_data *ibat = &bcl_perph->param[type];

	mutex_init(&ibat->state_trans_lock);
	ibat->type = type;
	ibat->dev = bcl_perph;
	bcl_fetch_trip(pdev, type, ibat, NULL);
	ibat->ops.get_temp = bcl_read_ibat;
	ibat->ops.set_trips = bcl_set_ibat;
@@ -541,20 +562,23 @@ static void bcl_ibat_init(struct platform_device *pdev,
	thermal_zone_device_update(ibat->tz_dev, THERMAL_DEVICE_UP);
}

static void bcl_probe_ibat(struct platform_device *pdev)
static void bcl_probe_ibat(struct platform_device *pdev,
					struct bcl_device *bcl_perph)
{
	bcl_ibat_init(pdev, BCL_IBAT_LVL0);
	bcl_ibat_init(pdev, BCL_IBAT_LVL1);
	bcl_ibat_init(pdev, BCL_IBAT_LVL0, bcl_perph);
	bcl_ibat_init(pdev, BCL_IBAT_LVL1, bcl_perph);
}

static void bcl_configure_bcl_peripheral(void)
static void bcl_configure_bcl_peripheral(struct bcl_device *bcl_perph)
{
	bcl_write_register(BCL_MONITOR_EN, BIT(7));
	bcl_write_register(bcl_perph, BCL_MONITOR_EN, BIT(7));
}

static int bcl_remove(struct platform_device *pdev)
{
	int i = 0;
	struct bcl_device *bcl_perph =
		(struct bcl_device *)dev_get_drvdata(&pdev->dev);

	for (; i < BCL_TYPE_MAX; i++) {
		if (!bcl_perph->param[i].tz_dev)
@@ -562,16 +586,23 @@ static int bcl_remove(struct platform_device *pdev)
		thermal_zone_of_sensor_unregister(&pdev->dev,
				bcl_perph->param[i].tz_dev);
	}
	bcl_perph = NULL;

	return 0;
}

static int bcl_probe(struct platform_device *pdev)
{
	bcl_perph = devm_kzalloc(&pdev->dev, sizeof(*bcl_perph), GFP_KERNEL);
	if (!bcl_perph)
	struct bcl_device *bcl_perph = NULL;

	if (bcl_device_ct >= MAX_PERPH_COUNT) {
		dev_err(&pdev->dev, "Max bcl peripheral supported already.\n");
		return -EINVAL;
	}
	bcl_devices[bcl_device_ct] = devm_kzalloc(&pdev->dev,
					sizeof(*bcl_devices[0]), GFP_KERNEL);
	if (!bcl_devices[bcl_device_ct])
		return -ENOMEM;
	bcl_perph = bcl_devices[bcl_device_ct];

	bcl_perph->regmap = dev_get_regmap(pdev->dev.parent, NULL);
	if (!bcl_perph->regmap) {
@@ -579,10 +610,11 @@ static int bcl_probe(struct platform_device *pdev)
		return -EINVAL;
	}

	bcl_get_devicetree_data(pdev);
	bcl_probe_vbat(pdev);
	bcl_probe_ibat(pdev);
	bcl_configure_bcl_peripheral();
	bcl_device_ct++;
	bcl_get_devicetree_data(pdev, bcl_perph);
	bcl_probe_vbat(pdev, bcl_perph);
	bcl_probe_ibat(pdev, bcl_perph);
	bcl_configure_bcl_peripheral(bcl_perph);

	dev_set_drvdata(&pdev->dev, bcl_perph);