]> Git Repo - linux.git/blob - drivers/media/pci/mgb4/mgb4_i2c.c
Linux 6.14-rc3
[linux.git] / drivers / media / pci / mgb4 / mgb4_i2c.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021-2023 Digiteq Automotive
4  *     author: Martin Tuma <[email protected]>
5  *
6  * The i2c module unifies the I2C access to the serializes/deserializes. The I2C
7  * chips on the GMSL module use 16b addressing, the FPDL3 chips use standard
8  * 8b addressing.
9  */
10
11 #include "mgb4_i2c.h"
12
13 static int read_r16(struct i2c_client *client, u16 reg, u8 *val, int len)
14 {
15         int ret;
16         u8 buf[2];
17         struct i2c_msg msg[2] = {
18                 {
19                         .addr = client->addr,
20                         .flags = 0,
21                         .len = 2,
22                         .buf = buf,
23                 }, {
24                         .addr = client->addr,
25                         .flags = I2C_M_RD,
26                         .len = len,
27                         .buf = val,
28                 }
29         };
30
31         buf[0] = (reg >> 8) & 0xff;
32         buf[1] = (reg >> 0) & 0xff;
33
34         ret = i2c_transfer(client->adapter, msg, 2);
35         if (ret < 0)
36                 return ret;
37         else if (ret != 2)
38                 return -EREMOTEIO;
39         else
40                 return 0;
41 }
42
43 static int write_r16(struct i2c_client *client, u16 reg, const u8 *val, int len)
44 {
45         int ret;
46         u8 buf[4];
47         struct i2c_msg msg[1] = {
48                 {
49                         .addr = client->addr,
50                         .flags = 0,
51                         .len = 2 + len,
52                         .buf = buf,
53                 }
54         };
55
56         if (2 + len > sizeof(buf))
57                 return -EINVAL;
58
59         buf[0] = (reg >> 8) & 0xff;
60         buf[1] = (reg >> 0) & 0xff;
61         memcpy(&buf[2], val, len);
62
63         ret = i2c_transfer(client->adapter, msg, 1);
64         if (ret < 0)
65                 return ret;
66         else if (ret != 1)
67                 return -EREMOTEIO;
68         else
69                 return 0;
70 }
71
72 int mgb4_i2c_init(struct mgb4_i2c_client *client, struct i2c_adapter *adap,
73                   struct i2c_board_info const *info, int addr_size)
74 {
75         client->client = i2c_new_client_device(adap, info);
76         if (IS_ERR(client->client))
77                 return PTR_ERR(client->client);
78
79         client->addr_size = addr_size;
80
81         return 0;
82 }
83
84 void mgb4_i2c_free(struct mgb4_i2c_client *client)
85 {
86         i2c_unregister_device(client->client);
87 }
88
89 s32 mgb4_i2c_read_byte(struct mgb4_i2c_client *client, u16 reg)
90 {
91         int ret;
92         u8 b;
93
94         if (client->addr_size == 8)
95                 return i2c_smbus_read_byte_data(client->client, reg);
96
97         ret = read_r16(client->client, reg, &b, 1);
98         if (ret < 0)
99                 return ret;
100
101         return (s32)b;
102 }
103
104 s32 mgb4_i2c_write_byte(struct mgb4_i2c_client *client, u16 reg, u8 val)
105 {
106         if (client->addr_size == 8)
107                 return i2c_smbus_write_byte_data(client->client, reg, val);
108         else
109                 return write_r16(client->client, reg, &val, 1);
110 }
111
112 s32 mgb4_i2c_mask_byte(struct mgb4_i2c_client *client, u16 reg, u8 mask, u8 val)
113 {
114         s32 ret;
115
116         if (mask != 0xFF) {
117                 ret = mgb4_i2c_read_byte(client, reg);
118                 if (ret < 0)
119                         return ret;
120                 val |= (u8)ret & ~mask;
121         }
122
123         return mgb4_i2c_write_byte(client, reg, val);
124 }
125
126 int mgb4_i2c_configure(struct mgb4_i2c_client *client,
127                        const struct mgb4_i2c_kv *values, size_t count)
128 {
129         size_t i;
130         s32 res;
131
132         for (i = 0; i < count; i++) {
133                 res = mgb4_i2c_mask_byte(client, values[i].reg, values[i].mask,
134                                          values[i].val);
135                 if (res < 0)
136                         return res;
137         }
138
139         return 0;
140 }
This page took 0.038062 seconds and 4 git commands to generate.