예제 #1
0
파일: sun4i-ts.c 프로젝트: 513855417/linux
static int sun4i_ts_probe(struct platform_device *pdev)
{
	struct sun4i_ts_data *ts;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct device *hwmon;
	int error;
	u32 reg;
	bool ts_attached;
	u32 tp_sensitive_adjust = 15;
	u32 filter_type = 1;

	ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
	if (!ts)
		return -ENOMEM;

	ts->dev = dev;
	ts->ignore_fifo_data = true;
	ts->temp_data = -1;
	if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) {
		/* Allwinner SDK has temperature (C) = (value / 6) - 271 */
		ts->temp_offset = 271000;
		ts->temp_step = 167;
	} else if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) {
		/*
		 * The A10 temperature sensor has quite a wide spread, these
		 * parameters are based on the averaging of the calibration
		 * results of 4 completely different boards, with a spread of
		 * temp_step from 0.096 - 0.170 and temp_offset from 176 - 331.
		 */
		ts->temp_offset = 257000;
		ts->temp_step = 133;
	} else {
		/*
		 * The user manuals do not contain the formula for calculating
		 * the temperature. The formula used here is from the AXP209,
		 * which is designed by X-Powers, an affiliate of Allwinner:
		 *
		 *     temperature (C) = (value * 0.1) - 144.7
		 *
		 * Allwinner does not have any documentation whatsoever for
		 * this hardware. Moreover, it is claimed that the sensor
		 * is inaccurate and cannot work properly.
		 */
		ts->temp_offset = 144700;
		ts->temp_step = 100;
	}

	ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
	if (ts_attached) {
		ts->input = devm_input_allocate_device(dev);
		if (!ts->input)
			return -ENOMEM;

		ts->input->name = pdev->name;
		ts->input->phys = "sun4i_ts/input0";
		ts->input->open = sun4i_ts_open;
		ts->input->close = sun4i_ts_close;
		ts->input->id.bustype = BUS_HOST;
		ts->input->id.vendor = 0x0001;
		ts->input->id.product = 0x0001;
		ts->input->id.version = 0x0100;
		ts->input->evbit[0] =  BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
		__set_bit(BTN_TOUCH, ts->input->keybit);
		input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
		input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
		input_set_drvdata(ts->input, ts);
	}

	ts->base = devm_ioremap_resource(dev,
			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
	if (IS_ERR(ts->base))
		return PTR_ERR(ts->base);

	ts->irq = platform_get_irq(pdev, 0);
	error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
	if (error)
		return error;

	/*
	 * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
	 * t_acq = clkin / (16 * 64)
	 */
	writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
	       ts->base + TP_CTRL0);

	/*
	 * tp_sensitive_adjust is an optional property
	 * tp_mode = 0 : only x and y coordinates, as we don't use dual touch
	 */
	of_property_read_u32(np, "allwinner,tp-sensitive-adjust",
			     &tp_sensitive_adjust);
	writel(TP_SENSITIVE_ADJUST(tp_sensitive_adjust) | TP_MODE_SELECT(0),
	       ts->base + TP_CTRL2);

	/*
	 * Enable median and averaging filter, optional property for
	 * filter type.
	 */
	of_property_read_u32(np, "allwinner,filter-type", &filter_type);
	writel(FILTER_EN(1) | FILTER_TYPE(filter_type), ts->base + TP_CTRL3);

	/* Enable temperature measurement, period 1953 (2 seconds) */
	writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);

	/*
	 * Set stylus up debounce to aprox 10 ms, enable debounce, and
	 * finally enable tp mode.
	 */
	reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1);
	if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts"))
		reg |= SUN6I_TP_MODE_EN(1);
	else
		reg |= TP_MODE_EN(1);
	writel(reg, ts->base + TP_CTRL1);

	/*
	 * The thermal core does not register hwmon devices for DT-based
	 * thermal zone sensors, such as this one.
	 */
	hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
						       ts, sun4i_ts_groups);
	if (IS_ERR(hwmon))
		return PTR_ERR(hwmon);

	devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops);

	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);

	if (ts_attached) {
		error = input_register_device(ts->input);
		if (error) {
			writel(0, ts->base + TP_INT_FIFOC);
			return error;
		}
	}

	platform_set_drvdata(pdev, ts);
	return 0;
}
예제 #2
0
파일: sun4i-ts.c 프로젝트: 383530895/linux
static int sun4i_ts_probe(struct platform_device *pdev)
{
	struct sun4i_ts_data *ts;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct device *hwmon;
	int error;
	bool ts_attached;

	ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
	if (!ts)
		return -ENOMEM;

	ts->dev = dev;
	ts->ignore_fifo_data = true;
	ts->temp_data = -1;

	ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
	if (ts_attached) {
		ts->input = devm_input_allocate_device(dev);
		if (!ts->input)
			return -ENOMEM;

		ts->input->name = pdev->name;
		ts->input->phys = "sun4i_ts/input0";
		ts->input->open = sun4i_ts_open;
		ts->input->close = sun4i_ts_close;
		ts->input->id.bustype = BUS_HOST;
		ts->input->id.vendor = 0x0001;
		ts->input->id.product = 0x0001;
		ts->input->id.version = 0x0100;
		ts->input->evbit[0] =  BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
		__set_bit(BTN_TOUCH, ts->input->keybit);
		input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
		input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
		input_set_drvdata(ts->input, ts);
	}

	ts->base = devm_ioremap_resource(dev,
			      platform_get_resource(pdev, IORESOURCE_MEM, 0));
	if (IS_ERR(ts->base))
		return PTR_ERR(ts->base);

	ts->irq = platform_get_irq(pdev, 0);
	error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
	if (error)
		return error;

	/*
	 * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
	 * t_acq = clkin / (16 * 64)
	 */
	writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
	       ts->base + TP_CTRL0);

	/*
	 * sensitive_adjust = 15 : max, which is not all that sensitive,
	 * tp_mode = 0 : only x and y coordinates, as we don't use dual touch
	 */
	writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0),
	       ts->base + TP_CTRL2);

	/* Enable median filter, type 1 : 5/3 */
	writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3);

	/* Enable temperature measurement, period 1953 (2 seconds) */
	writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);

	/*
	 * Set stylus up debounce to aprox 10 ms, enable debounce, and
	 * finally enable tp mode.
	 */
	writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
	       ts->base + TP_CTRL1);

	hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
						       ts, sun4i_ts_groups);
	if (IS_ERR(hwmon))
		return PTR_ERR(hwmon);

	writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);

	if (ts_attached) {
		error = input_register_device(ts->input);
		if (error) {
			writel(0, ts->base + TP_INT_FIFOC);
			return error;
		}
	}

	platform_set_drvdata(pdev, ts);
	return 0;
}