brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · 34c9be4 Raw
171 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (C) 2022 Microchip Technology Inc.3 4#include <linux/mfd/core.h>5#include <linux/module.h>6#include <linux/pci.h>7#include <linux/spinlock.h>8#include <linux/gpio/driver.h>9#include <linux/interrupt.h>10#include <linux/io.h>11#include <linux/idr.h>12#include "mchp_pci1xxxx_gp.h"13 14struct aux_bus_device {15	struct auxiliary_device_wrapper *aux_device_wrapper[2];16};17 18static DEFINE_IDA(gp_client_ida);19static const char aux_dev_otp_e2p_name[15] = "gp_otp_e2p";20static const char aux_dev_gpio_name[15] = "gp_gpio";21 22static void gp_auxiliary_device_release(struct device *dev)23{24	struct auxiliary_device_wrapper *aux_device_wrapper =25		(struct auxiliary_device_wrapper *)container_of(dev,26				struct auxiliary_device_wrapper, aux_dev.dev);27 28	ida_free(&gp_client_ida, aux_device_wrapper->aux_dev.id);29	kfree(aux_device_wrapper);30}31 32static int gp_aux_bus_probe(struct pci_dev *pdev, const struct pci_device_id *id)33{34	struct aux_bus_device *aux_bus;35	int retval;36 37	retval = pcim_enable_device(pdev);38	if (retval)39		return retval;40 41	aux_bus = devm_kzalloc(&pdev->dev, sizeof(*aux_bus), GFP_KERNEL);42	if (!aux_bus)43		return -ENOMEM;44 45	aux_bus->aux_device_wrapper[0] = kzalloc(sizeof(*aux_bus->aux_device_wrapper[0]),46						 GFP_KERNEL);47	if (!aux_bus->aux_device_wrapper[0])48		return -ENOMEM;49 50	retval = ida_alloc(&gp_client_ida, GFP_KERNEL);51	if (retval < 0)52		goto err_ida_alloc_0;53 54	aux_bus->aux_device_wrapper[0]->aux_dev.name = aux_dev_otp_e2p_name;55	aux_bus->aux_device_wrapper[0]->aux_dev.dev.parent = &pdev->dev;56	aux_bus->aux_device_wrapper[0]->aux_dev.dev.release = gp_auxiliary_device_release;57	aux_bus->aux_device_wrapper[0]->aux_dev.id = retval;58 59	aux_bus->aux_device_wrapper[0]->gp_aux_data.region_start = pci_resource_start(pdev, 0);60	aux_bus->aux_device_wrapper[0]->gp_aux_data.region_length = pci_resource_end(pdev, 0);61 62	retval = auxiliary_device_init(&aux_bus->aux_device_wrapper[0]->aux_dev);63	if (retval < 0)64		goto err_aux_dev_init_0;65 66	retval = auxiliary_device_add(&aux_bus->aux_device_wrapper[0]->aux_dev);67	if (retval)68		goto err_aux_dev_add_0;69 70	aux_bus->aux_device_wrapper[1] = kzalloc(sizeof(*aux_bus->aux_device_wrapper[1]),71						 GFP_KERNEL);72	if (!aux_bus->aux_device_wrapper[1]) {73		retval =  -ENOMEM;74		goto err_aux_dev_add_0;75	}76 77	retval = ida_alloc(&gp_client_ida, GFP_KERNEL);78	if (retval < 0)79		goto err_ida_alloc_1;80 81	aux_bus->aux_device_wrapper[1]->aux_dev.name = aux_dev_gpio_name;82	aux_bus->aux_device_wrapper[1]->aux_dev.dev.parent = &pdev->dev;83	aux_bus->aux_device_wrapper[1]->aux_dev.dev.release = gp_auxiliary_device_release;84	aux_bus->aux_device_wrapper[1]->aux_dev.id = retval;85 86	aux_bus->aux_device_wrapper[1]->gp_aux_data.region_start = pci_resource_start(pdev, 0);87	aux_bus->aux_device_wrapper[1]->gp_aux_data.region_length = pci_resource_end(pdev, 0);88 89	retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);90 91	if (retval < 0)92		goto err_aux_dev_init_1;93 94	retval = pci_irq_vector(pdev, 0);95	if (retval < 0)96		goto err_aux_dev_init_1;97 98	pdev->irq = retval;99	aux_bus->aux_device_wrapper[1]->gp_aux_data.irq_num = pdev->irq;100 101	retval = auxiliary_device_init(&aux_bus->aux_device_wrapper[1]->aux_dev);102	if (retval < 0)103		goto err_aux_dev_init_1;104 105	retval = auxiliary_device_add(&aux_bus->aux_device_wrapper[1]->aux_dev);106	if (retval)107		goto err_aux_dev_add_1;108 109	pci_set_drvdata(pdev, aux_bus);110	pci_set_master(pdev);111 112	return 0;113 114err_aux_dev_add_1:115	auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);116	goto err_aux_dev_add_0;117 118err_aux_dev_init_1:119	ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[1]->aux_dev.id);120 121err_ida_alloc_1:122	kfree(aux_bus->aux_device_wrapper[1]);123 124err_aux_dev_add_0:125	auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);126	goto err_ret;127 128err_aux_dev_init_0:129	ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[0]->aux_dev.id);130 131err_ida_alloc_0:132	kfree(aux_bus->aux_device_wrapper[0]);133 134err_ret:135	return retval;136}137 138static void gp_aux_bus_remove(struct pci_dev *pdev)139{140	struct aux_bus_device *aux_bus = pci_get_drvdata(pdev);141 142	auxiliary_device_delete(&aux_bus->aux_device_wrapper[0]->aux_dev);143	auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);144	auxiliary_device_delete(&aux_bus->aux_device_wrapper[1]->aux_dev);145	auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);146}147 148static const struct pci_device_id pci1xxxx_tbl[] = {149	{ PCI_DEVICE(0x1055, 0xA005) },150	{ PCI_DEVICE(0x1055, 0xA015) },151	{ PCI_DEVICE(0x1055, 0xA025) },152	{ PCI_DEVICE(0x1055, 0xA035) },153	{ PCI_DEVICE(0x1055, 0xA045) },154	{ PCI_DEVICE(0x1055, 0xA055) },155	{0,}156};157MODULE_DEVICE_TABLE(pci, pci1xxxx_tbl);158 159static struct pci_driver pci1xxxx_gp_driver = {160	.name = "PCI1xxxxGP",161	.id_table = pci1xxxx_tbl,162	.probe = gp_aux_bus_probe,163	.remove = gp_aux_bus_remove,164};165 166module_pci_driver(pci1xxxx_gp_driver);167 168MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx GP expander");169MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");170MODULE_LICENSE("GPL");171