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

Commit a543f526 authored by Ram Chandrasekar's avatar Ram Chandrasekar
Browse files

drivers: thermal: bcl_pmic5: Add multi peripheral support



The existing bcl pmic5 driver can handle only one peripheral. Any second
peripheral defined in devicetree will overwrite the first peripherals
data.

Add support for handling upto two bcl peripherals. These will be used in
cases where there is one peripheral in PM version of PMIC and one in PMI
version of PMIC.

Change-Id: Icce0dc4581ccff5b4a08e98e413a975dc34c68f8
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent 1529c90d
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);