Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2// 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");
v6.8
  1// SPDX-License-Identifier: GPL-2.0
  2// 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		return -ENOMEM;
 
 
 74
 75	retval = ida_alloc(&gp_client_ida, GFP_KERNEL);
 76	if (retval < 0)
 77		goto err_ida_alloc_1;
 78
 79	aux_bus->aux_device_wrapper[1]->aux_dev.name = aux_dev_gpio_name;
 80	aux_bus->aux_device_wrapper[1]->aux_dev.dev.parent = &pdev->dev;
 81	aux_bus->aux_device_wrapper[1]->aux_dev.dev.release = gp_auxiliary_device_release;
 82	aux_bus->aux_device_wrapper[1]->aux_dev.id = retval;
 83
 84	aux_bus->aux_device_wrapper[1]->gp_aux_data.region_start = pci_resource_start(pdev, 0);
 85	aux_bus->aux_device_wrapper[1]->gp_aux_data.region_length = pci_resource_end(pdev, 0);
 86
 87	retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
 88
 89	if (retval < 0)
 90		goto err_aux_dev_init_1;
 91
 92	retval = pci_irq_vector(pdev, 0);
 93	if (retval < 0)
 94		goto err_aux_dev_init_1;
 95
 96	pdev->irq = retval;
 97	aux_bus->aux_device_wrapper[1]->gp_aux_data.irq_num = pdev->irq;
 98
 99	retval = auxiliary_device_init(&aux_bus->aux_device_wrapper[1]->aux_dev);
100	if (retval < 0)
101		goto err_aux_dev_init_1;
102
103	retval = auxiliary_device_add(&aux_bus->aux_device_wrapper[1]->aux_dev);
104	if (retval)
105		goto err_aux_dev_add_1;
106
107	pci_set_drvdata(pdev, aux_bus);
108	pci_set_master(pdev);
109
110	return 0;
111
112err_aux_dev_add_1:
113	auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);
 
114
115err_aux_dev_init_1:
116	ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[1]->aux_dev.id);
117
118err_ida_alloc_1:
119	kfree(aux_bus->aux_device_wrapper[1]);
120
121err_aux_dev_add_0:
122	auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);
 
123
124err_aux_dev_init_0:
125	ida_free(&gp_client_ida, aux_bus->aux_device_wrapper[0]->aux_dev.id);
126
127err_ida_alloc_0:
128	kfree(aux_bus->aux_device_wrapper[0]);
129
 
130	return retval;
131}
132
133static void gp_aux_bus_remove(struct pci_dev *pdev)
134{
135	struct aux_bus_device *aux_bus = pci_get_drvdata(pdev);
136
137	auxiliary_device_delete(&aux_bus->aux_device_wrapper[0]->aux_dev);
138	auxiliary_device_uninit(&aux_bus->aux_device_wrapper[0]->aux_dev);
139	auxiliary_device_delete(&aux_bus->aux_device_wrapper[1]->aux_dev);
140	auxiliary_device_uninit(&aux_bus->aux_device_wrapper[1]->aux_dev);
141}
142
143static const struct pci_device_id pci1xxxx_tbl[] = {
144	{ PCI_DEVICE(0x1055, 0xA005) },
145	{ PCI_DEVICE(0x1055, 0xA015) },
146	{ PCI_DEVICE(0x1055, 0xA025) },
147	{ PCI_DEVICE(0x1055, 0xA035) },
148	{ PCI_DEVICE(0x1055, 0xA045) },
149	{ PCI_DEVICE(0x1055, 0xA055) },
150	{0,}
151};
152MODULE_DEVICE_TABLE(pci, pci1xxxx_tbl);
153
154static struct pci_driver pci1xxxx_gp_driver = {
155	.name = "PCI1xxxxGP",
156	.id_table = pci1xxxx_tbl,
157	.probe = gp_aux_bus_probe,
158	.remove = gp_aux_bus_remove,
159};
160
161module_pci_driver(pci1xxxx_gp_driver);
162
163MODULE_DESCRIPTION("Microchip Technology Inc. PCI1xxxx GP expander");
164MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
165MODULE_LICENSE("GPL");