示例#1
0
文件: platform.c 项目: avagin/linux
/**
 * platform_get_irq_byname - get an IRQ for a device by name
 * @dev: platform device
 * @name: IRQ name
 */
int platform_get_irq_byname(struct platform_device *dev, const char *name)
{
	struct resource *r;

	if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
		int ret;

		ret = of_irq_get_byname(dev->dev.of_node, name);
		if (ret > 0 || ret == -EPROBE_DEFER)
			return ret;
	}

	r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
	return r ? r->start : -ENXIO;
}
示例#2
0
/**
 * timer_of_irq_init - Request the interrupt
 * @np: a device tree node pointer
 * @of_irq: an of_timer_irq structure pointer
 *
 * Get the interrupt number from the DT from its definition and
 * request it. The interrupt is gotten by falling back the following way:
 *
 * - Get interrupt number by name
 * - Get interrupt number by index
 *
 * When the interrupt is per CPU, 'request_percpu_irq()' is called,
 * otherwise 'request_irq()' is used.
 *
 * Returns 0 on success, < 0 otherwise
 */
static __init int timer_of_irq_init(struct device_node *np,
				    struct of_timer_irq *of_irq)
{
	int ret;
	struct timer_of *to = container_of(of_irq, struct timer_of, of_irq);
	struct clock_event_device *clkevt = &to->clkevt;

	if (of_irq->name) {
		of_irq->irq = ret = of_irq_get_byname(np, of_irq->name);
		if (ret < 0) {
			pr_err("Failed to get interrupt %s for %s\n",
			       of_irq->name, np->full_name);
			return ret;
		}
	} else	{
		of_irq->irq = irq_of_parse_and_map(np, of_irq->index);
	}
	if (!of_irq->irq) {
		pr_err("Failed to map interrupt for %pOF\n", np);
		return -EINVAL;
	}

	ret = of_irq->percpu ?
		request_percpu_irq(of_irq->irq, of_irq->handler,
				   np->full_name, clkevt) :
		request_irq(of_irq->irq, of_irq->handler,
			    of_irq->flags ? of_irq->flags : IRQF_TIMER,
			    np->full_name, clkevt);
	if (ret) {
		pr_err("Failed to request irq %d for %pOF\n", of_irq->irq, np);
		return ret;
	}

	clkevt->irq = of_irq->irq;

	return 0;
}
示例#3
0
static int mma8452_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
{
    struct mma8452_data *data;
    struct iio_dev *indio_dev;
    int ret;
    const struct of_device_id *match;

    match = of_match_device(mma8452_dt_ids, &client->dev);
    if (!match) {
        dev_err(&client->dev, "unknown device model\n");
        return -ENODEV;
    }

    indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    if (!indio_dev)
        return -ENOMEM;

    data = iio_priv(indio_dev);
    data->client = client;
    mutex_init(&data->lock);
    data->chip_info = match->data;

    ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I);
    if (ret < 0)
        return ret;

    switch (ret) {
    case MMA8452_DEVICE_ID:
    case MMA8453_DEVICE_ID:
    case MMA8652_DEVICE_ID:
    case MMA8653_DEVICE_ID:
        if (ret == data->chip_info->chip_id)
            break;
    default:
        return -ENODEV;
    }

    dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
             match->compatible, data->chip_info->chip_id);

    i2c_set_clientdata(client, indio_dev);
    indio_dev->info = &mma8452_info;
    indio_dev->name = id->name;
    indio_dev->dev.parent = &client->dev;
    indio_dev->modes = INDIO_DIRECT_MODE;
    indio_dev->channels = data->chip_info->channels;
    indio_dev->num_channels = data->chip_info->num_channels;
    indio_dev->available_scan_masks = mma8452_scan_masks;

    ret = mma8452_reset(client);
    if (ret < 0)
        return ret;

    data->data_cfg = MMA8452_DATA_CFG_FS_2G;
    ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
                                    data->data_cfg);
    if (ret < 0)
        return ret;

    /*
     * By default set transient threshold to max to avoid events if
     * enabling without configuring threshold.
     */
    ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS,
                                    MMA8452_TRANSIENT_THS_MASK);
    if (ret < 0)
        return ret;

    if (client->irq) {
        /*
         * Although we enable the interrupt sources once and for
         * all here the event detection itself is not enabled until
         * userspace asks for it by mma8452_write_event_config()
         */
        int supported_interrupts = MMA8452_INT_DRDY |
                                   MMA8452_INT_TRANS |
                                   MMA8452_INT_FF_MT;
        int enabled_interrupts = MMA8452_INT_TRANS |
                                 MMA8452_INT_FF_MT;
        int irq2;

        irq2 = of_irq_get_byname(client->dev.of_node, "INT2");

        if (irq2 == client->irq) {
            dev_dbg(&client->dev, "using interrupt line INT2\n");
        } else {
            ret = i2c_smbus_write_byte_data(client,
                                            MMA8452_CTRL_REG5,
                                            supported_interrupts);
            if (ret < 0)
                return ret;

            dev_dbg(&client->dev, "using interrupt line INT1\n");
        }

        ret = i2c_smbus_write_byte_data(client,
                                        MMA8452_CTRL_REG4,
                                        enabled_interrupts);
        if (ret < 0)
            return ret;

        ret = mma8452_trigger_setup(indio_dev);
        if (ret < 0)
            return ret;
    }

    data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
                      (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
    ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
                                    data->ctrl_reg1);
    if (ret < 0)
        goto trigger_cleanup;

    ret = iio_triggered_buffer_setup(indio_dev, NULL,
                                     mma8452_trigger_handler, NULL);
    if (ret < 0)
        goto trigger_cleanup;

    if (client->irq) {
        ret = devm_request_threaded_irq(&client->dev,
                                        client->irq,
                                        NULL, mma8452_interrupt,
                                        IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                        client->name, indio_dev);
        if (ret)
            goto buffer_cleanup;
    }

    ret = iio_device_register(indio_dev);
    if (ret < 0)
        goto buffer_cleanup;

    return 0;

buffer_cleanup:
    iio_triggered_buffer_cleanup(indio_dev);

trigger_cleanup:
    mma8452_trigger_cleanup(indio_dev);

    return ret;
}
示例#4
0
文件: stm32-ipcc.c 项目: Lyude/linux
static int stm32_ipcc_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct stm32_ipcc *ipcc;
	struct resource *res;
	unsigned int i;
	int ret;
	u32 ip_ver;
	static const char * const irq_name[] = {"rx", "tx"};
	irq_handler_t irq_thread[] = {stm32_ipcc_rx_irq, stm32_ipcc_tx_irq};

	if (!np) {
		dev_err(dev, "No DT found\n");
		return -ENODEV;
	}

	ipcc = devm_kzalloc(dev, sizeof(*ipcc), GFP_KERNEL);
	if (!ipcc)
		return -ENOMEM;

	/* proc_id */
	if (of_property_read_u32(np, "st,proc-id", &ipcc->proc_id)) {
		dev_err(dev, "Missing st,proc-id\n");
		return -ENODEV;
	}

	if (ipcc->proc_id >= STM32_MAX_PROCS) {
		dev_err(dev, "Invalid proc_id (%d)\n", ipcc->proc_id);
		return -EINVAL;
	}

	/* regs */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	ipcc->reg_base = devm_ioremap_resource(dev, res);
	if (IS_ERR(ipcc->reg_base))
		return PTR_ERR(ipcc->reg_base);

	ipcc->reg_proc = ipcc->reg_base + ipcc->proc_id * IPCC_PROC_OFFST;

	/* clock */
	ipcc->clk = devm_clk_get(dev, NULL);
	if (IS_ERR(ipcc->clk))
		return PTR_ERR(ipcc->clk);

	ret = clk_prepare_enable(ipcc->clk);
	if (ret) {
		dev_err(dev, "can not enable the clock\n");
		return ret;
	}

	/* irq */
	for (i = 0; i < IPCC_IRQ_NUM; i++) {
		ipcc->irqs[i] = of_irq_get_byname(dev->of_node, irq_name[i]);
		if (ipcc->irqs[i] < 0) {
			dev_err(dev, "no IRQ specified %s\n", irq_name[i]);
			ret = ipcc->irqs[i];
			goto err_clk;
		}

		ret = devm_request_threaded_irq(dev, ipcc->irqs[i], NULL,
						irq_thread[i], IRQF_ONESHOT,
						dev_name(dev), ipcc);
		if (ret) {
			dev_err(dev, "failed to request irq %d (%d)\n", i, ret);
			goto err_clk;
		}
	}

	/* mask and enable rx/tx irq */
	stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR,
			    RX_BIT_MASK | TX_BIT_MASK);
	stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XCR, XCR_RXOIE | XCR_TXOIE);

	/* wakeup */
	if (of_property_read_bool(np, "wakeup-source")) {
		ipcc->wkp = of_irq_get_byname(dev->of_node, "wakeup");
		if (ipcc->wkp < 0) {
			dev_err(dev, "could not get wakeup IRQ\n");
			ret = ipcc->wkp;
			goto err_clk;
		}

		device_init_wakeup(dev, true);
		ret = dev_pm_set_dedicated_wake_irq(dev, ipcc->wkp);
		if (ret) {
			dev_err(dev, "Failed to set wake up irq\n");
			goto err_init_wkp;
		}
	} else {
		device_init_wakeup(dev, false);
	}

	/* mailbox controller */
	ipcc->n_chans = readl_relaxed(ipcc->reg_base + IPCC_HWCFGR);
	ipcc->n_chans &= IPCFGR_CHAN_MASK;

	ipcc->controller.dev = dev;
	ipcc->controller.txdone_irq = true;
	ipcc->controller.ops = &stm32_ipcc_ops;
	ipcc->controller.num_chans = ipcc->n_chans;
	ipcc->controller.chans = devm_kcalloc(dev, ipcc->controller.num_chans,
					      sizeof(*ipcc->controller.chans),
					      GFP_KERNEL);
	if (!ipcc->controller.chans) {
		ret = -ENOMEM;
		goto err_irq_wkp;
	}

	for (i = 0; i < ipcc->controller.num_chans; i++)
		ipcc->controller.chans[i].con_priv = (void *)i;

	ret = mbox_controller_register(&ipcc->controller);
	if (ret)
		goto err_irq_wkp;

	platform_set_drvdata(pdev, ipcc);

	ip_ver = readl_relaxed(ipcc->reg_base + IPCC_VER);

	dev_info(dev, "ipcc rev:%ld.%ld enabled, %d chans, proc %d\n",
		 FIELD_GET(VER_MAJREV_MASK, ip_ver),
		 FIELD_GET(VER_MINREV_MASK, ip_ver),
		 ipcc->controller.num_chans, ipcc->proc_id);

	clk_disable_unprepare(ipcc->clk);
	return 0;

err_irq_wkp:
	if (ipcc->wkp)
		dev_pm_clear_wake_irq(dev);
err_init_wkp:
	device_init_wakeup(dev, false);
err_clk:
	clk_disable_unprepare(ipcc->clk);
	return ret;
}