static int sccnxp_probe()

in serial/sccnxp.c [881:1033]


static int sccnxp_probe(struct platform_device *pdev)
{
	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev);
	int i, ret, uartclk;
	struct sccnxp_port *s;
	void __iomem *membase;
	struct clk *clk;

	membase = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(membase))
		return PTR_ERR(membase);

	s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
	if (!s) {
		dev_err(&pdev->dev, "Error allocating port structure\n");
		return -ENOMEM;
	}
	platform_set_drvdata(pdev, s);

	spin_lock_init(&s->lock);

	s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data;

	s->regulator = devm_regulator_get(&pdev->dev, "vcc");
	if (!IS_ERR(s->regulator)) {
		ret = regulator_enable(s->regulator);
		if (ret) {
			dev_err(&pdev->dev,
				"Failed to enable regulator: %i\n", ret);
			return ret;
		}
	} else if (PTR_ERR(s->regulator) == -EPROBE_DEFER)
		return -EPROBE_DEFER;

	clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(clk)) {
		ret = PTR_ERR(clk);
		if (ret == -EPROBE_DEFER)
			goto err_out;
		uartclk = 0;
	} else {
		ret = clk_prepare_enable(clk);
		if (ret)
			goto err_out;

		ret = devm_add_action_or_reset(&pdev->dev,
				(void(*)(void *))clk_disable_unprepare,
				clk);
		if (ret)
			goto err_out;

		uartclk = clk_get_rate(clk);
	}

	if (!uartclk) {
		dev_notice(&pdev->dev, "Using default clock frequency\n");
		uartclk = s->chip->freq_std;
	}

	/* Check input frequency */
	if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
		dev_err(&pdev->dev, "Frequency out of bounds\n");
		ret = -EINVAL;
		goto err_out;
	}

	if (pdata)
		memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata));

	if (s->pdata.poll_time_us) {
		dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n",
			 s->pdata.poll_time_us);
		s->poll = 1;
	}

	if (!s->poll) {
		s->irq = platform_get_irq(pdev, 0);
		if (s->irq < 0) {
			ret = -ENXIO;
			goto err_out;
		}
	}

	s->uart.owner		= THIS_MODULE;
	s->uart.dev_name	= "ttySC";
	s->uart.major		= SCCNXP_MAJOR;
	s->uart.minor		= SCCNXP_MINOR;
	s->uart.nr		= s->chip->nr;
#ifdef CONFIG_SERIAL_SCCNXP_CONSOLE
	s->uart.cons		= &s->console;
	s->uart.cons->device	= uart_console_device;
	s->uart.cons->write	= sccnxp_console_write;
	s->uart.cons->setup	= sccnxp_console_setup;
	s->uart.cons->flags	= CON_PRINTBUFFER;
	s->uart.cons->index	= -1;
	s->uart.cons->data	= s;
	strcpy(s->uart.cons->name, "ttySC");
#endif
	ret = uart_register_driver(&s->uart);
	if (ret) {
		dev_err(&pdev->dev, "Registering UART driver failed\n");
		goto err_out;
	}

	for (i = 0; i < s->uart.nr; i++) {
		s->port[i].line		= i;
		s->port[i].dev		= &pdev->dev;
		s->port[i].irq		= s->irq;
		s->port[i].type		= PORT_SC26XX;
		s->port[i].fifosize	= s->chip->fifosize;
		s->port[i].flags	= UPF_SKIP_TEST | UPF_FIXED_TYPE;
		s->port[i].iotype	= UPIO_MEM;
		s->port[i].mapbase	= res->start;
		s->port[i].membase	= membase;
		s->port[i].regshift	= s->pdata.reg_shift;
		s->port[i].uartclk	= uartclk;
		s->port[i].ops		= &sccnxp_ops;
		s->port[i].has_sysrq = IS_ENABLED(CONFIG_SERIAL_SCCNXP_CONSOLE);
		uart_add_one_port(&s->uart, &s->port[i]);
		/* Set direction to input */
		if (s->chip->flags & SCCNXP_HAVE_IO)
			sccnxp_set_bit(&s->port[i], DIR_OP, 0);
	}

	/* Disable interrupts */
	s->imr = 0;
	sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0);

	if (!s->poll) {
		ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL,
						sccnxp_ist,
						IRQF_TRIGGER_FALLING |
						IRQF_ONESHOT,
						dev_name(&pdev->dev), s);
		if (!ret)
			return 0;

		dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq);
	} else {
		timer_setup(&s->timer, sccnxp_timer, 0);
		mod_timer(&s->timer, jiffies +
			  usecs_to_jiffies(s->pdata.poll_time_us));
		return 0;
	}

	uart_unregister_driver(&s->uart);
err_out:
	if (!IS_ERR(s->regulator))
		regulator_disable(s->regulator);

	return ret;
}