int wcd9xxx_spmi_request_irq(int irq, irq_handler_t handler,
			const char *name, void *priv)
{
	int rc;
	map.linuxirq[irq] =
		spmi_get_irq_byname(map.spmi[BIT_BYTE(irq)], NULL,
				    irq_names[irq]);
	rc = devm_request_threaded_irq(&map.spmi[BIT_BYTE(irq)]->dev,
				map.linuxirq[irq], NULL,
				wcd9xxx_spmi_irq_handler,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
				| IRQF_ONESHOT,
				name, priv);
		if (rc < 0) {
			dev_err(&map.spmi[BIT_BYTE(irq)]->dev,
				"Can't request %d IRQ\n", irq);
			return rc;
		}

	dev_dbg(&map.spmi[BIT_BYTE(irq)]->dev,
			"irq %d linuxIRQ: %d\n", irq, map.linuxirq[irq]);
	map.mask[BIT_BYTE(irq)] &= ~BYTE_BIT_MASK(irq);
	map.handler[irq] = handler;
	enable_irq_wake(map.linuxirq[irq]);
	return 0;
}
int wcd9xxx_spmi_request_irq(int irq, irq_handler_t handler,
			const char *name, void *priv)
{
	int rc;
    #ifdef VENDOR_EDIT
    //[email protected], 2015/07/01, Add for system not reume when in sleep mode
	unsigned long irq_flags;
	if (strcmp(name, "mbhc sw intr")) {
        irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
            IRQF_ONESHOT;
    } else {
        irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
            IRQF_ONESHOT | IRQF_NO_SUSPEND;
    }
    #endif /* VENDOR_EDIT */

	map.linuxirq[irq] =
		spmi_get_irq_byname(map.spmi[BIT_BYTE(irq)], NULL,
				    irq_names[irq]);
    #ifndef VENDOR_EDIT
    //[email protected], 2015/07/01, Modify for system not reume when in sleep mode
    /*
	rc = devm_request_threaded_irq(&map.spmi[BIT_BYTE(irq)]->dev,
				map.linuxirq[irq], NULL,
				wcd9xxx_spmi_irq_handler,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
				| IRQF_ONESHOT,
				name, priv);
	*/
    #else /* VENDOR_EDIT */
	rc = devm_request_threaded_irq(&map.spmi[BIT_BYTE(irq)]->dev,
				map.linuxirq[irq], NULL,
				wcd9xxx_spmi_irq_handler,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
				| IRQF_ONESHOT,
				name, priv);
    #endif /* VENDOR_EDIT */

		if (rc < 0) {
			dev_err(&map.spmi[BIT_BYTE(irq)]->dev,
				"Can't request %d IRQ\n", irq);
			return rc;
		}

	dev_dbg(&map.spmi[BIT_BYTE(irq)]->dev,
			"irq %d linuxIRQ: %d\n", irq, map.linuxirq[irq]);
	map.mask[BIT_BYTE(irq)] &= ~BYTE_BIT_MASK(irq);
	map.handler[irq] = handler;
	enable_irq_wake(map.linuxirq[irq]);
	return 0;
}
Esempio n. 3
0
/* DT parsing api for buffer mode */
static int qpnp_hap_parse_buffer_dt(struct qpnp_hap *hap)
{
	struct spmi_device *spmi = hap->spmi;
	struct property *prop;
	u32 temp;
	int rc, i;

	hap->wave_rep_cnt = QPNP_HAP_WAV_REP_MIN;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,wave-rep-cnt", &temp);
	if (!rc) {
		hap->wave_rep_cnt = temp;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read rep cnt\n");
		return rc;
	}

	hap->wave_s_rep_cnt = QPNP_HAP_WAV_S_REP_MIN;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,wave-samp-rep-cnt", &temp);
	if (!rc) {
		hap->wave_s_rep_cnt = temp;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read samp rep cnt\n");
		return rc;
	}

	prop = of_find_property(spmi->dev.of_node,
			"qcom,wave-samples", &temp);
	if (!prop || temp != QPNP_HAP_WAV_SAMP_LEN) {
		dev_err(&spmi->dev, "Invalid wave samples, use default");
		for (i = 0; i < QPNP_HAP_WAV_SAMP_LEN; i++)
			hap->wave_samp[i] = QPNP_HAP_WAV_SAMP_MAX;
	} else {
		memcpy(hap->wave_samp, prop->value, QPNP_HAP_WAV_SAMP_LEN);
	}

	hap->use_play_irq = of_property_read_bool(spmi->dev.of_node,
				"qcom,use-play-irq");
	if (hap->use_play_irq) {
		hap->play_irq = spmi_get_irq_byname(hap->spmi,
					NULL, "play-irq");
		if (hap->play_irq < 0) {
			dev_err(&spmi->dev, "Unable to get play irq\n");
			return hap->play_irq;
		}
	}

	return 0;
}
Esempio n. 4
0
static int bcl_get_devicetree_data(struct spmi_device *spmi)
{
	int ret = 0, irq_num = 0, temp_val = 0;
	struct resource *resource = NULL;
	char *key = NULL;
	const __be32 *prop = NULL;
	struct device_node *dev_node = spmi->dev.of_node;

	/* Get SPMI peripheral address */
	resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
	if (!resource) {
		pr_err("No base address defined\n");
		return -EINVAL;
	}
	bcl_perph->slave_id = spmi->sid;
	prop = of_get_address_by_name(dev_node,
			"fg_user_adc", 0, 0);
	if (prop) {
		bcl_perph->base_addr = be32_to_cpu(*prop);
		pr_debug("fg_user_adc@%04x\n", bcl_perph->base_addr);
	} else {
		dev_err(&spmi->dev, "No fg_user_adc registers found\n");
		return -EINVAL;
	}

	prop = of_get_address_by_name(dev_node,
			"pon_spare", 0, 0);
	if (prop) {
		bcl_perph->pon_spare_addr = be32_to_cpu(*prop);
		pr_debug("pon_spare@%04x\n", bcl_perph->pon_spare_addr);
	}

	/* Register SPMI peripheral interrupt */
	irq_num = spmi_get_irq_byname(spmi, NULL,
			BCL_VBAT_INT_NAME);
	if (irq_num < 0) {
		pr_err("Invalid vbat IRQ\n");
		ret = -ENXIO;
		goto bcl_dev_exit;
	}
	bcl_perph->param[BCL_PARAM_VOLTAGE].irq_num = irq_num;
	irq_num = spmi_get_irq_byname(spmi, NULL,
			BCL_IBAT_INT_NAME);
	if (irq_num < 0) {
		pr_err("Invalid ibat IRQ\n");
		ret = -ENXIO;
		goto bcl_dev_exit;
	}
	bcl_perph->param[BCL_PARAM_CURRENT].irq_num = irq_num;

	/* Get VADC and IADC scaling factor */
	key = "qcom,vbat-scaling-factor";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_VOLTAGE].scaling_factor);
	key = "qcom,vbat-gain-numerator";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_VOLTAGE].gain_factor_num);
	key = "qcom,vbat-gain-denominator";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_VOLTAGE].gain_factor_den);
	key = "qcom,ibat-scaling-factor";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_CURRENT].scaling_factor);
	key = "qcom,ibat-offset-numerator";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_CURRENT].offset_factor_num);
	key = "qcom,ibat-offset-denominator";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_CURRENT].offset_factor_den);
	key = "qcom,ibat-gain-numerator";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_CURRENT].gain_factor_num);
	key = "qcom,ibat-gain-denominator";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_CURRENT].gain_factor_den);
	key = "qcom,vbat-polling-delay-ms";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_VOLTAGE].polling_delay_ms);
	key = "qcom,ibat-polling-delay-ms";
	READ_CONV_FACTOR(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_CURRENT].polling_delay_ms);
	key = "qcom,inhibit-derating-ua";
	READ_OPTIONAL_PROP(dev_node, key, temp_val, ret,
		bcl_perph->param[BCL_PARAM_CURRENT].inhibit_derating_ua);

bcl_dev_exit:
	return ret;
}
Esempio n. 5
0
/* DT parsing for haptics parameters */
static int qpnp_hap_parse_dt(struct qpnp_hap *hap)
{
	struct spmi_device *spmi = hap->spmi;
	struct property *prop;
	const char *temp_str;
	u32 temp;
	int rc;

	hap->timeout_ms = QPNP_HAP_TIMEOUT_MS_MAX;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,timeout-ms", &temp);
	if (!rc) {
		hap->timeout_ms = temp;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read timeout\n");
		return rc;
	}

	hap->act_type = QPNP_HAP_LRA;
	rc = of_property_read_string(spmi->dev.of_node,
			"qcom,actuator-type", &temp_str);
	if (!rc) {
		if (strcmp(temp_str, "erm") == 0)
			hap->act_type = QPNP_HAP_ERM;
		else if (strcmp(temp_str, "lra") == 0)
			hap->act_type = QPNP_HAP_LRA;
		else {
			dev_err(&spmi->dev, "Invalid actuator type\n");
			return -EINVAL;
		}
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read actuator type\n");
		return rc;
	}

	if (hap->act_type == QPNP_HAP_LRA) {
		hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP;
		rc = of_property_read_string(spmi->dev.of_node,
				"qcom,lra-auto-res-mode", &temp_str);
		if (!rc) {
			if (strcmp(temp_str, "none") == 0)
				hap->auto_res_mode = QPNP_HAP_AUTO_RES_NONE;
			else if (strcmp(temp_str, "zxd") == 0)
				hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD;
			else if (strcmp(temp_str, "qwd") == 0)
				hap->auto_res_mode = QPNP_HAP_AUTO_RES_QWD;
			else if (strcmp(temp_str, "max-qwd") == 0)
				hap->auto_res_mode = QPNP_HAP_AUTO_RES_MAX_QWD;
			else
				hap->auto_res_mode = QPNP_HAP_AUTO_RES_ZXD_EOP;
		} else if (rc != -EINVAL) {
			dev_err(&spmi->dev, "Unable to read auto res mode\n");
			return rc;
		}

		hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3;
		rc = of_property_read_string(spmi->dev.of_node,
				"qcom,lra-high-z", &temp_str);
		if (!rc) {
			if (strcmp(temp_str, "none") == 0)
				hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_NONE;
			else if (strcmp(temp_str, "opt1") == 0)
				hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT1;
			else if (strcmp(temp_str, "opt2") == 0)
				hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT2;
			else
				hap->lra_high_z = QPNP_HAP_LRA_HIGH_Z_OPT3;
		} else if (rc != -EINVAL) {
			dev_err(&spmi->dev, "Unable to read LRA high-z\n");
			return rc;
		}

		hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX;
		rc = of_property_read_u32(spmi->dev.of_node,
				"qcom,lra-res-cal-period", &temp);
		if (!rc) {
			hap->lra_res_cal_period = temp;
		} else if (rc != -EINVAL) {
			dev_err(&spmi->dev, "Unable to read cal period\n");
			return rc;
		}
	}

	rc = of_property_read_string(spmi->dev.of_node,
				"qcom,play-mode", &temp_str);
	if (!rc) {
		if (strcmp(temp_str, "direct") == 0)
			hap->play_mode = QPNP_HAP_DIRECT;
		else if (strcmp(temp_str, "buffer") == 0)
			hap->play_mode = QPNP_HAP_BUFFER;
		else if (strcmp(temp_str, "pwm") == 0)
			hap->play_mode = QPNP_HAP_PWM;
		else if (strcmp(temp_str, "audio") == 0)
			hap->play_mode = QPNP_HAP_AUDIO;
		else {
			dev_err(&spmi->dev, "Invalid play mode\n");
			return -EINVAL;
		}
	} else {
		dev_err(&spmi->dev, "Unable to read play mode\n");
		return rc;
	}

	hap->vmax_mv = QPNP_HAP_VMAX_MAX_MV;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,vmax-mv", &temp);
	if (!rc) {
		hap->vmax_mv = temp;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read vmax\n");
		return rc;
	}

	hap->ilim_ma = QPNP_HAP_ILIM_MIN_MV;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,ilim-ma", &temp);
	if (!rc) {
		hap->ilim_ma = temp;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read ILim\n");
		return rc;
	}

	hap->sc_deb_cycles = QPNP_HAP_DEF_SC_DEB_CYCLES;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,sc-deb-cycles", &temp);
	if (!rc) {
		hap->sc_deb_cycles = temp;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read sc debounce\n");
		return rc;
	}

	hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_505_KHZ;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,int-pwm-freq-khz", &temp);
	if (!rc) {
		hap->int_pwm_freq_khz = temp;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read int pwm freq\n");
		return rc;
	}

	hap->wave_shape = QPNP_HAP_WAV_SQUARE;
	rc = of_property_read_string(spmi->dev.of_node,
			"qcom,wave-shape", &temp_str);
	if (!rc) {
		if (strcmp(temp_str, "sine") == 0)
			hap->wave_shape = QPNP_HAP_WAV_SINE;
		else if (strcmp(temp_str, "square") == 0)
			hap->wave_shape = QPNP_HAP_WAV_SQUARE;
		else {
			dev_err(&spmi->dev, "Unsupported wav shape\n");
			return -EINVAL;
		}
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read wav shape\n");
		return rc;
	}

	hap->wave_play_rate_us = QPNP_HAP_DEF_WAVE_PLAY_RATE_US;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,wave-play-rate-us", &temp);
	if (!rc) {
		hap->wave_play_rate_us = temp;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read play rate\n");
		return rc;
	}

	if (hap->play_mode == QPNP_HAP_BUFFER)
		rc = qpnp_hap_parse_buffer_dt(hap);
	else if (hap->play_mode == QPNP_HAP_PWM)
		rc = qpnp_hap_parse_pwm_dt(hap);

	if (rc < 0)
		return rc;

	hap->en_brake = of_property_read_bool(spmi->dev.of_node,
				"qcom,en-brake");

	if (hap->en_brake) {
		prop = of_find_property(spmi->dev.of_node,
				"qcom,brake-pattern", &temp);
		if (!prop) {
			dev_info(&spmi->dev, "brake pattern not found");
		} else if (temp != QPNP_HAP_BRAKE_PAT_LEN) {
			dev_err(&spmi->dev, "Invalid len of brake pattern\n");
			return -EINVAL;
		} else {
			hap->sup_brake_pat = true;
			memcpy(hap->brake_pat, prop->value,
					QPNP_HAP_BRAKE_PAT_LEN);
		}
	}

	hap->use_sc_irq = of_property_read_bool(spmi->dev.of_node,
				"qcom,use-sc-irq");
	if (hap->use_sc_irq) {
		hap->sc_irq = spmi_get_irq_byname(hap->spmi,
					NULL, "sc-irq");
		if (hap->sc_irq < 0) {
			dev_err(&spmi->dev, "Unable to get sc irq\n");
			return hap->sc_irq;
		}
	}

	return 0;
}
Esempio n. 6
0
static int __devinit qpnp_pon_config_init(struct qpnp_pon *pon)
{
	int rc = 0, i = 0;
	struct device_node *pp = NULL;
	struct qpnp_pon_config *cfg;

	/* iterate through the list of pon configs */
	while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {

		cfg = &pon->pon_cfg[i++];

		rc = of_property_read_u32(pp, "qcom,pon-type", &cfg->pon_type);
		if (rc) {
			dev_err(&pon->spmi->dev, "PON type not specified\n");
			return rc;
		}

		switch (cfg->pon_type) {
		case PON_KPDPWR:
			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
							NULL, "kpdpwr");
			if (cfg->state_irq < 0) {
				dev_err(&pon->spmi->dev,
					"Unable to get kpdpwr irq\n");
				return cfg->state_irq;
			}

			rc = of_property_read_u32(pp, "qcom,support-reset",
							&cfg->support_reset);
			if (rc && rc != -EINVAL) {
				dev_err(&pon->spmi->dev,
					"Unable to read 'support-reset'\n");
				return rc;
			}

			if (cfg->support_reset) {
				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
							NULL, "kpdpwr-bark");
				if (cfg->bark_irq < 0) {
					dev_err(&pon->spmi->dev,
					"Unable to get kpdpwr-bark irq\n");
					return cfg->bark_irq;
				}
			}
			break;
		case PON_RESIN:
			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
							NULL, "resin");
			if (cfg->state_irq < 0) {
				dev_err(&pon->spmi->dev,
					"Unable to get resin irq\n");
				return cfg->bark_irq;
			}

			rc = of_property_read_u32(pp, "qcom,support-reset",
							&cfg->support_reset);
			if (rc && rc != -EINVAL) {
				dev_err(&pon->spmi->dev,
					"Unable to read 'support-reset'\n");
				return rc;
			}

			if (cfg->support_reset) {
				cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
							NULL, "resin-bark");
				if (cfg->bark_irq < 0) {
					dev_err(&pon->spmi->dev,
					"Unable to get resin-bark irq\n");
					return cfg->bark_irq;
				}
			}
			break;
		case PON_CBLPWR:
			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
							NULL, "cblpwr");
			if (cfg->state_irq < 0) {
				dev_err(&pon->spmi->dev,
						"Unable to get cblpwr irq\n");
				return rc;
			}
			break;
		default:
			dev_err(&pon->spmi->dev, "PON RESET %d not supported",
								cfg->pon_type);
			return -EINVAL;
		}

		if (cfg->support_reset) {
			/*
			 * Get the reset parameters (bark debounce time and
			 * reset debounce time) for the reset line.
			 */
			rc = of_property_read_u32(pp, "qcom,s1-timer",
							&cfg->s1_timer);
			if (rc) {
				dev_err(&pon->spmi->dev,
					"Unable to read s1-timer\n");
				return rc;
			}
			if (cfg->s1_timer > QPNP_PON_S1_TIMER_MAX) {
				dev_err(&pon->spmi->dev,
					"Incorrect S1 debounce time\n");
				return -EINVAL;
			}
			rc = of_property_read_u32(pp, "qcom,s2-timer",
							&cfg->s2_timer);
			if (rc) {
				dev_err(&pon->spmi->dev,
					"Unable to read s2-timer\n");
				return rc;
			}
			if (cfg->s2_timer > QPNP_PON_S2_TIMER_MAX) {
				dev_err(&pon->spmi->dev,
					"Incorrect S2 debounce time\n");
				return -EINVAL;
			}
			rc = of_property_read_u32(pp, "qcom,s2-type",
							&cfg->s2_type);
			if (rc) {
				dev_err(&pon->spmi->dev,
					"Unable to read s2-type\n");
				return rc;
			}
			if (cfg->s2_type > QPNP_PON_RESET_TYPE_MAX) {
				dev_err(&pon->spmi->dev,
					"Incorrect reset type specified\n");
				return -EINVAL;
			}
		}
		/*
		 * Get the standard-key parameters. This might not be
		 * specified if there is no key mapping on the reset line.
		 */
		rc = of_property_read_u32(pp, "linux,code", &cfg->key_code);

		#ifdef CONFIG_MACH_MONTBLANC
		cfg->key_code = 107;
		dev_err(&pon->spmi->dev, "montblanc power key code changed, %d (116)\n", cfg->key_code);
		#else
		if (rc && rc == -EINVAL) {
			dev_err(&pon->spmi->dev,
				"Unable to read key-code\n");
			return rc;
		}
		#endif
		
		/* Register key configuration */
		if (cfg->key_code) {
			rc = qpnp_pon_config_input(pon, cfg);
			if (rc < 0)
				return rc;
		}
		/* get the pull-up configuration */
		rc = of_property_read_u32(pp, "qcom,pull-up", &cfg->pull_up);
		if (rc && rc != -EINVAL) {
			dev_err(&pon->spmi->dev, "Unable to read pull-up\n");
			return rc;
		}
	}

	/* register the input device */
	if (pon->pon_input) {
		rc = input_register_device(pon->pon_input);
		if (rc) {
			dev_err(&pon->spmi->dev,
				"Can't register pon key: %d\n", rc);
			goto free_input_dev;
		}
	}

	for (i = 0; i < pon->num_pon_config; i++) {
		cfg = &pon->pon_cfg[i];
		/* Configure the pull-up */
		rc = qpnp_config_pull(pon, cfg);
		if (rc) {
			dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
			goto unreg_input_dev;
		}
		/* Configure the reset-configuration */
		if (cfg->support_reset) {
			rc = qpnp_config_reset(pon, cfg);
			if (rc) {
				dev_err(&pon->spmi->dev,
					"Unable to config pon reset\n");
				goto unreg_input_dev;
			}
		}
		rc = qpnp_pon_request_irqs(pon, cfg);
		if (rc) {
			dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
			goto unreg_input_dev;
		}
	}

	device_init_wakeup(&pon->spmi->dev, 1);

	return rc;

unreg_input_dev:
	if (pon->pon_input)
		input_unregister_device(pon->pon_input);
free_input_dev:
	if (pon->pon_input)
		input_free_device(pon->pon_input);
	return rc;
}
Esempio n. 7
0
/* parse wled dtsi parameters */
static int qpnp_wled_parse_dt(struct qpnp_wled *wled)
{
	struct spmi_device *spmi = wled->spmi;
	struct property *prop;
	const char *temp_str;
	u32 temp_val;
	int rc, i;

	wled->cdev.name = "wled";
	rc = of_property_read_string(spmi->dev.of_node,
			"linux,name", &wled->cdev.name);
	if (rc && (rc != -EINVAL)) {
		dev_err(&spmi->dev, "Unable to read led name\n");
		return rc;
	}

	wled->cdev.default_trigger = QPNP_WLED_TRIGGER_NONE;
	rc = of_property_read_string(spmi->dev.of_node, "linux,default-trigger",
					&wled->cdev.default_trigger);
	if (rc && (rc != -EINVAL)) {
		dev_err(&spmi->dev, "Unable to read led trigger\n");
		return rc;
	}

	wled->disp_type_amoled = of_property_read_bool(spmi->dev.of_node,
				"qcom,disp-type-amoled");

	wled->fdbk_op = QPNP_WLED_FDBK_AUTO;
	rc = of_property_read_string(spmi->dev.of_node,
			"qcom,fdbk-output", &temp_str);
	if (!rc) {
		if (strcmp(temp_str, "wled1") == 0)
			wled->fdbk_op = QPNP_WLED_FDBK_WLED1;
		else if (strcmp(temp_str, "wled2") == 0)
			wled->fdbk_op = QPNP_WLED_FDBK_WLED2;
		else if (strcmp(temp_str, "wled3") == 0)
			wled->fdbk_op = QPNP_WLED_FDBK_WLED3;
		else if (strcmp(temp_str, "wled4") == 0)
			wled->fdbk_op = QPNP_WLED_FDBK_WLED4;
		else
			wled->fdbk_op = QPNP_WLED_FDBK_AUTO;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read feedback output\n");
		return rc;
	}

	wled->vref_mv = QPNP_WLED_DFLT_VREF_MV;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,vref-mv", &temp_val);
	if (!rc) {
		wled->vref_mv = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read vref\n");
		return rc;
	}

	wled->switch_freq_khz = QPNP_WLED_SWITCH_FREQ_800_KHZ;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,switch-freq-khz", &temp_val);
	if (!rc) {
		wled->switch_freq_khz = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read switch freq\n");
		return rc;
	}

	wled->ovp_mv = QPNP_WLED_OVP_29500_MV;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,ovp-mv", &temp_val);
	if (!rc) {
		wled->ovp_mv = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read vref\n");
		return rc;
	}

	wled->ilim_ma = QPNP_WLED_DFLT_ILIM_MA;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,ilim-ma", &temp_val);
	if (!rc) {
		wled->ilim_ma = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read ilim\n");
		return rc;
	}

	wled->boost_duty_ns = QPNP_WLED_DEF_BOOST_DUTY_NS;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,boost-duty-ns", &temp_val);
	if (!rc) {
		wled->boost_duty_ns = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read boost duty\n");
		return rc;
	}

	wled->mod_freq_khz = QPNP_WLED_MOD_FREQ_9600_KHZ;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,mod-freq-khz", &temp_val);
	if (!rc) {
		wled->mod_freq_khz = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read modulation freq\n");
		return rc;
	}

	wled->dim_mode = QPNP_WLED_DIM_HYBRID;
	rc = of_property_read_string(spmi->dev.of_node,
			"qcom,dim-mode", &temp_str);
	if (!rc) {
		if (strcmp(temp_str, "analog") == 0)
			wled->dim_mode = QPNP_WLED_DIM_ANALOG;
		else if (strcmp(temp_str, "digital") == 0)
			wled->dim_mode = QPNP_WLED_DIM_DIGITAL;
		else
			wled->dim_mode = QPNP_WLED_DIM_HYBRID;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read dim mode\n");
		return rc;
	}

	if (wled->dim_mode == QPNP_WLED_DIM_HYBRID) {
		wled->hyb_thres = QPNP_WLED_DEF_HYB_THRES;
		rc = of_property_read_u32(spmi->dev.of_node,
				"qcom,hyb-thres", &temp_val);
		if (!rc) {
			wled->hyb_thres = temp_val;
		} else if (rc != -EINVAL) {
			dev_err(&spmi->dev, "Unable to read hyb threshold\n");
			return rc;
		}
	}

	wled->sync_dly_us = QPNP_WLED_DEF_SYNC_DLY_US;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,sync-dly-us", &temp_val);
	if (!rc) {
		wled->sync_dly_us = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read sync delay\n");
		return rc;
	}

	wled->fs_curr_ua = QPNP_WLED_FS_CURR_MAX_UA;
	rc = of_property_read_u32(spmi->dev.of_node,
			"qcom,fs-curr-ua", &temp_val);
	if (!rc) {
		wled->fs_curr_ua = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read full scale current\n");
		return rc;
	}

	wled->en_9b_dim_res = of_property_read_bool(spmi->dev.of_node,
			"qcom,en-9b-dim-res");
	wled->en_phase_stag = of_property_read_bool(spmi->dev.of_node,
			"qcom,en-phase-stag");
	wled->en_cabc = of_property_read_bool(spmi->dev.of_node,
			"qcom,en-cabc");

	prop = of_find_property(spmi->dev.of_node,
			"qcom,led-strings-list", &temp_val);
	if (!prop || !temp_val || temp_val > QPNP_WLED_MAX_STRINGS) {
		dev_err(&spmi->dev, "Invalid strings info, use default");
		wled->num_strings = QPNP_WLED_MAX_STRINGS;
		for (i = 0; i < wled->num_strings; i++)
			wled->strings[i] = i;
	} else {
		wled->num_strings = temp_val;
		memcpy(wled->strings, prop->value, temp_val);
	}

	wled->ibb_bias_active = of_property_read_bool(spmi->dev.of_node,
				"qcom,ibb-bias-active");

	wled->ibb_pwrup_dly_ms = QPNP_WLED_IBB_PWRUP_DLY_MIN_MS;
	rc = of_property_read_u32(spmi->dev.of_node,
				"qcom,ibb-pwrup-dly", &temp_val);
	if (!rc) {
		wled->ibb_pwrup_dly_ms = temp_val;
	} else if (rc != -EINVAL) {
		dev_err(&spmi->dev, "Unable to read ibb pwrup delay\n");
		return rc;
	}

	wled->lab_fast_precharge = of_property_read_bool(spmi->dev.of_node,
				"qcom,lab-fast-precharge");

	wled->ovp_irq = spmi_get_irq_byname(spmi, NULL, "ovp-irq");
	if (wled->ovp_irq < 0)
		dev_dbg(&spmi->dev, "ovp irq is not used\n");

	wled->sc_irq = spmi_get_irq_byname(spmi, NULL, "sc-irq");
	if (wled->sc_irq < 0)
		dev_dbg(&spmi->dev, "sc irq is not used\n");

	wled->en_ext_pfet_sc_pro = of_property_read_bool(spmi->dev.of_node,
					"qcom,en-ext-pfet-sc-pro");

	return 0;
}
Esempio n. 8
0
static int __devinit qpnp_tm_probe(struct spmi_device *spmi)
{
	struct device_node *node;
	struct resource *res;
	struct qpnp_tm_chip *chip;
	struct thermal_zone_device_ops *tz_ops;
	char *tm_name;
	u32 default_temperature;
	int rc = 0;
	u8 raw_type[2], type, subtype;
#ifdef CONFIG_LGE_PM
	struct spmi_resource *spmi_resource;
	u8 batt_pres_rt_sts;
#endif
	if (!spmi || !(&spmi->dev) || !spmi->dev.of_node) {
		dev_err(&spmi->dev, "%s: device tree node not found\n",
			__func__);
		return -EINVAL;
	}

	node = spmi->dev.of_node;

	chip = kzalloc(sizeof(struct qpnp_tm_chip), GFP_KERNEL);
	if (!chip) {
		dev_err(&spmi->dev, "%s: Can't allocate qpnp_tm_chip\n",
			__func__);
		return -ENOMEM;
	}

	dev_set_drvdata(&spmi->dev, chip);

	res = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&spmi->dev, "%s: node is missing base address\n",
			__func__);
		rc = -EINVAL;
		goto free_chip;
	}
	chip->base_addr	= res->start;
	chip->spmi_dev	= spmi;

	chip->irq = spmi_get_irq(spmi, NULL, 0);
	if (chip->irq < 0) {
		rc = chip->irq;
		dev_err(&spmi->dev, "%s: node is missing irq, rc=%d\n",
			__func__, rc);
		goto free_chip;
	}

	chip->tm_name = of_get_property(node, "label", NULL);
	if (chip->tm_name == NULL) {
		dev_err(&spmi->dev, "%s: node is missing label\n",
			__func__);
		rc = -EINVAL;
		goto free_chip;
	}

	tm_name = kstrdup(chip->tm_name, GFP_KERNEL);
	if (tm_name == NULL) {
		dev_err(&spmi->dev, "%s: could not allocate memory for label\n",
			__func__);
		rc = -ENOMEM;
		goto free_chip;
	}
	chip->tm_name = tm_name;

	INIT_DELAYED_WORK(&chip->irq_work, qpnp_tm_work);

	/* These bindings are optional, so it is okay if they are not found. */
	chip->thresh = THRESH_MAX + 1;
	rc = of_property_read_u32(node, "qcom,threshold-set", &chip->thresh);
	if (!rc && (chip->thresh < THRESH_MIN || chip->thresh > THRESH_MAX))
		dev_err(&spmi->dev, "%s: invalid qcom,threshold-set=%u specified\n",
			__func__, chip->thresh);

	chip->adc_type = QPNP_TM_ADC_NONE;
	rc = of_property_read_u32(node, "qcom,channel-num", &chip->adc_channel);
	if (!rc) {
		if (chip->adc_channel < 0 || chip->adc_channel >= ADC_MAX_NUM) {
			dev_err(&spmi->dev, "%s: invalid qcom,channel-num=%d specified\n",
				__func__, chip->adc_channel);
		} else {
			chip->adc_type = QPNP_TM_ADC_QPNP_ADC;
			chip->vadc_dev = qpnp_get_vadc(&spmi->dev,
							"temp_alarm");
			if (IS_ERR(chip->vadc_dev)) {
				rc = PTR_ERR(chip->vadc_dev);
				if (rc != -EPROBE_DEFER)
					pr_err("vadc property missing\n");
				goto err_cancel_work;
			}
		}
	}

	if (chip->adc_type == QPNP_TM_ADC_QPNP_ADC)
		tz_ops = &qpnp_thermal_zone_ops_qpnp_adc;
	else
		tz_ops = &qpnp_thermal_zone_ops_no_adc;

	chip->allow_software_override
		= of_property_read_bool(node, "qcom,allow-override");

	default_temperature = DEFAULT_NO_ADC_TEMP;
	rc = of_property_read_u32(node, "qcom,default-temp",
					&default_temperature);
	chip->temperature = default_temperature;

	rc = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, raw_type, 2);
	if (rc) {
		dev_err(&spmi->dev, "%s: could not read type register, rc=%d\n",
			__func__, rc);
		goto err_cancel_work;
	}
	type = raw_type[0];
	subtype = raw_type[1];

	if (type != QPNP_TM_TYPE || subtype != QPNP_TM_SUBTYPE) {
		dev_err(&spmi->dev, "%s: invalid type=%02X or subtype=%02X register value\n",
			__func__, type, subtype);
		rc = -ENODEV;
		goto err_cancel_work;
	}

	rc = qpnp_tm_init_reg(chip);
	if (rc) {
		dev_err(&spmi->dev, "%s: qpnp_tm_init_reg() failed, rc=%d\n",
			__func__, rc);
		goto err_cancel_work;
	}

	if (chip->adc_type == QPNP_TM_ADC_NONE) {
		rc = qpnp_tm_init_temp_no_adc(chip);
		if (rc) {
			dev_err(&spmi->dev, "%s: qpnp_tm_init_temp_no_adc() failed, rc=%d\n",
				__func__, rc);
			goto err_cancel_work;
		}
	}

	/* Start in HW control; switch to SW control when user changes mode. */
	chip->mode = THERMAL_DEVICE_DISABLED;
	rc = qpnp_tm_shutdown_override(chip, SOFTWARE_OVERRIDE_DISABLED);
	if (rc) {
		dev_err(&spmi->dev, "%s: qpnp_tm_shutdown_override() failed, rc=%d\n",
			__func__, rc);
		goto err_cancel_work;
	}

	chip->tz_dev = thermal_zone_device_register(tm_name, TRIP_NUM, chip,
			tz_ops, 0, 0, 0, 0);
	if (chip->tz_dev == NULL) {
		dev_err(&spmi->dev, "%s: thermal_zone_device_register() failed.\n",
			__func__);
		rc = -ENODEV;
		goto err_cancel_work;
	}

	rc = request_irq(chip->irq, qpnp_tm_isr, IRQF_TRIGGER_RISING, tm_name,
			chip);
	if (rc < 0) {
		dev_err(&spmi->dev, "%s: request_irq(%d) failed: %d\n",
			__func__, chip->irq, rc);
		goto err_free_tz;
	}

#ifdef CONFIG_LGE_PM
	spmi_for_each_container_dev(spmi_resource, spmi) {
		if (!spmi_resource) {
			pr_err("qpnp temp alarm : spmi resource absent\n");
			goto fail_bat_if;
		}

		res = spmi_get_resource(spmi, spmi_resource,
						IORESOURCE_MEM, 0);
		if (!(res && res->start)) {
			pr_err("node %s IO resource absent!\n",
				spmi->dev.of_node->full_name);
			goto fail_bat_if;
		}

		rc = qpnp_register_read(chip, &subtype,
				res->start + REG_OFFSET_PERP_SUBTYPE, 1);
		if (rc) {
			pr_err("Peripheral subtype read failed rc=%d\n", rc);
			goto fail_bat_if;
		}

		switch (subtype) {
		case SMBB_BAT_IF_SUBTYPE:
			pr_err("qpnp bat_if block enable for batt insert remove irq.\n");
			chip->bat_if_base = res->start;
			chip->batt_present_irq = spmi_get_irq_byname(chip->spmi_dev,
					spmi_resource, "batt-pres");

			if (chip->batt_present_irq < 0) {
				pr_err("Unable to get batt_present_irq\n");
				goto fail_bat_if;
			}

			rc = devm_request_irq(&(chip->spmi_dev->dev),
				chip->batt_present_irq,
				qpnp_batif_batt_inserted_removed_irq_handler,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
				"batt_remove_insert", chip);

			if (rc < 0) {
				pr_err("Can't request %d batt irq for insert, remove : %d\n",
						chip->batt_present_irq, rc);
				goto fail_bat_if;
			}

			rc = qpnp_register_masked_write(chip,
				INT_EN_SET(chip->bat_if_base),
				BATT_PRES_EN_BIT, BATT_PRES_EN_BIT, 1);

			if (rc) {
				pr_err("failed to enable BAT_IF_INT_EN_SET rc=%d\n", rc);
				goto fail_bat_if;
			}

			/* smb349 charger battery present W/A */
			rc = qpnp_register_read(chip, &batt_pres_rt_sts,
					INT_RT_STS(chip->bat_if_base), 1);
			if (rc) {
				pr_err("spmi read failed: addr=%03X, rc=%d\n",
						INT_RT_STS(chip->bat_if_base), rc);
				pr_err("assume that battery is present\n");

				/* battery present */
				pm_batt_rt_sts = 1;
			} else {
				pm_batt_rt_sts =
					(int)(batt_pres_rt_sts & BATT_IF_PRES_RT_STATUS);
				pr_err("%s : init PMIC battery RTS = %d\n",
						__func__, pm_batt_rt_sts);
			}

			enable_irq_wake(chip->batt_present_irq);
			break;
		default:
			break;
		}
	}

	INIT_WORK(&chip->batt_insert_remove_worker, batt_insert_remove_work);
	INIT_DELAYED_WORK(&chip->batt_insert_remove_worker_second,
				batt_insert_remove_work_second);
	wake_lock_init(&chip->battgone_wake_lock,
				WAKE_LOCK_SUSPEND, "batt removed");
#endif
	return 0;

err_free_tz:
	thermal_zone_device_unregister(chip->tz_dev);
err_cancel_work:
	cancel_delayed_work_sync(&chip->irq_work);
	kfree(chip->tm_name);
free_chip:
	dev_set_drvdata(&spmi->dev, NULL);
	kfree(chip);
	return rc;
#ifdef CONFIG_LGE_PM
fail_bat_if:
	pr_err("Cannot enable qpnp bat_if block.\n");
	return 0;
#endif
}
static int qpnp_regulator_get_dt_config(struct spmi_device *spmi,
				struct qpnp_regulator_platform_data *pdata)
{
	struct resource *res;
	struct device_node *node = spmi->dev.of_node;
	int rc = 0;

	pdata->init_data.constraints.input_uV
		= pdata->init_data.constraints.max_uV;

	res = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&spmi->dev, "%s: node is missing base address\n",
			__func__);
		return -EINVAL;
	}
	pdata->base_addr = res->start;

	
	pdata->ocp_irq = spmi_get_irq_byname(spmi, NULL, "ocp");
	if (pdata->ocp_irq < 0)
		pdata->ocp_irq = 0;

	pdata->auto_mode_enable		= QPNP_REGULATOR_USE_HW_DEFAULT;
	pdata->bypass_mode_enable	= QPNP_REGULATOR_USE_HW_DEFAULT;
	pdata->ocp_enable		= QPNP_REGULATOR_USE_HW_DEFAULT;
	pdata->pull_down_enable		= QPNP_REGULATOR_USE_HW_DEFAULT;
	pdata->soft_start_enable	= QPNP_REGULATOR_USE_HW_DEFAULT;
	pdata->boost_current_limit	= QPNP_BOOST_CURRENT_LIMIT_HW_DEFAULT;
	pdata->pin_ctrl_enable	    = QPNP_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT;
	pdata->pin_ctrl_hpm	    = QPNP_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT;
	pdata->vs_soft_start_strength	= QPNP_VS_SOFT_START_STR_HW_DEFAULT;
	pdata->hpm_enable		= QPNP_REGULATOR_USE_HW_DEFAULT;

	
	of_property_read_u32(node, "qcom,auto-mode-enable",
		&pdata->auto_mode_enable);
	of_property_read_u32(node, "qcom,bypass-mode-enable",
		&pdata->bypass_mode_enable);
	of_property_read_u32(node, "qcom,ocp-enable", &pdata->ocp_enable);
	of_property_read_u32(node, "qcom,ocp-max-retries",
		&pdata->ocp_max_retries);
	of_property_read_u32(node, "qcom,ocp-retry-delay",
		&pdata->ocp_retry_delay_ms);
	of_property_read_u32(node, "qcom,pull-down-enable",
		&pdata->pull_down_enable);
	of_property_read_u32(node, "qcom,soft-start-enable",
		&pdata->soft_start_enable);
	of_property_read_u32(node, "qcom,boost-current-limit",
		&pdata->boost_current_limit);
	of_property_read_u32(node, "qcom,pin-ctrl-enable",
		&pdata->pin_ctrl_enable);
	of_property_read_u32(node, "qcom,pin-ctrl-hpm", &pdata->pin_ctrl_hpm);
	of_property_read_u32(node, "qcom,hpm-enable", &pdata->hpm_enable);
	of_property_read_u32(node, "qcom,vs-soft-start-strength",
		&pdata->vs_soft_start_strength);
	of_property_read_u32(node, "qcom,system-load", &pdata->system_load);
	of_property_read_u32(node, "qcom,enable-time", &pdata->enable_time);

	return rc;
}