@@ -65,10 +65,6 @@ enum {
6565 STATE_WRITE ,
6666};
6767
68- struct meson_i2c_data {
69- unsigned char div_factor ;
70- };
71-
7268/**
7369 * struct meson_i2c - Meson I2C device private data
7470 *
@@ -109,6 +105,10 @@ struct meson_i2c {
109105 const struct meson_i2c_data * data ;
110106};
111107
108+ struct meson_i2c_data {
109+ void (* set_clk_div )(struct meson_i2c * i2c , unsigned int freq );
110+ };
111+
112112static void meson_i2c_set_mask (struct meson_i2c * i2c , int reg , u32 mask ,
113113 u32 val )
114114{
@@ -137,14 +137,62 @@ static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
137137 i2c -> num_tokens ++ ;
138138}
139139
140- static void meson_i2c_set_clk_div (struct meson_i2c * i2c , unsigned int freq )
140+ static void meson_gxbb_axg_i2c_set_clk_div (struct meson_i2c * i2c , unsigned int freq )
141+ {
142+ unsigned long clk_rate = clk_get_rate (i2c -> clk );
143+ unsigned int div_h , div_l ;
144+
145+ /* According to I2C-BUS Spec 2.1, in FAST-MODE, the minimum LOW period is 1.3uS, and
146+ * minimum HIGH is least 0.6us.
147+ * For 400000 freq, the period is 2.5us. To keep within the specs, give 40% of period to
148+ * HIGH and 60% to LOW. This means HIGH at 1.0us and LOW 1.5us.
149+ * The same applies for Fast-mode plus, where LOW is 0.5us and HIGH is 0.26us.
150+ * Duty = H/(H + L) = 2/5
151+ */
152+ if (freq <= I2C_MAX_STANDARD_MODE_FREQ ) {
153+ div_h = DIV_ROUND_UP (clk_rate , freq );
154+ div_l = DIV_ROUND_UP (div_h , 4 );
155+ div_h = DIV_ROUND_UP (div_h , 2 ) - FILTER_DELAY ;
156+ } else {
157+ div_h = DIV_ROUND_UP (clk_rate * 2 , freq * 5 ) - FILTER_DELAY ;
158+ div_l = DIV_ROUND_UP (clk_rate * 3 , freq * 5 * 2 );
159+ }
160+
161+ /* clock divider has 12 bits */
162+ if (div_h > GENMASK (11 , 0 )) {
163+ dev_err (i2c -> dev , "requested bus frequency too low\n" );
164+ div_h = GENMASK (11 , 0 );
165+ }
166+ if (div_l > GENMASK (11 , 0 )) {
167+ dev_err (i2c -> dev , "requested bus frequency too low\n" );
168+ div_l = GENMASK (11 , 0 );
169+ }
170+
171+ meson_i2c_set_mask (i2c , REG_CTRL , REG_CTRL_CLKDIV_MASK ,
172+ FIELD_PREP (REG_CTRL_CLKDIV_MASK , div_h & GENMASK (9 , 0 )));
173+
174+ meson_i2c_set_mask (i2c , REG_CTRL , REG_CTRL_CLKDIVEXT_MASK ,
175+ FIELD_PREP (REG_CTRL_CLKDIVEXT_MASK , div_h >> 10 ));
176+
177+ /* set SCL low delay */
178+ meson_i2c_set_mask (i2c , REG_SLAVE_ADDR , REG_SLV_SCL_LOW_MASK ,
179+ FIELD_PREP (REG_SLV_SCL_LOW_MASK , div_l ));
180+
181+ /* Enable HIGH/LOW mode */
182+ meson_i2c_set_mask (i2c , REG_SLAVE_ADDR , REG_SLV_SCL_LOW_EN , REG_SLV_SCL_LOW_EN );
183+
184+ dev_dbg (i2c -> dev , "%s: clk %lu, freq %u, divh %u, divl %u\n" , __func__ ,
185+ clk_rate , freq , div_h , div_l );
186+ }
187+
188+ static void meson6_i2c_set_clk_div (struct meson_i2c * i2c , unsigned int freq )
141189{
142190 unsigned long clk_rate = clk_get_rate (i2c -> clk );
143191 unsigned int div ;
144192
145193 div = DIV_ROUND_UP (clk_rate , freq );
146194 div -= FILTER_DELAY ;
147- div = DIV_ROUND_UP (div , i2c -> data -> div_factor );
195+ div = DIV_ROUND_UP (div , 4 );
148196
149197 /* clock divider has 12 bits */
150198 if (div > GENMASK (11 , 0 )) {
@@ -472,7 +520,9 @@ static int meson_i2c_probe(struct platform_device *pdev)
472520 meson_i2c_set_mask (i2c , REG_SLAVE_ADDR ,
473521 REG_SLV_SDA_FILTER_MASK | REG_SLV_SCL_FILTER_MASK , 0 );
474522
475- meson_i2c_set_clk_div (i2c , timings .bus_freq_hz );
523+ if (!i2c -> data -> set_clk_div )
524+ return - EINVAL ;
525+ i2c -> data -> set_clk_div (i2c , timings .bus_freq_hz );
476526
477527 ret = i2c_add_adapter (& i2c -> adap );
478528 if (ret < 0 ) {
@@ -494,15 +544,15 @@ static int meson_i2c_remove(struct platform_device *pdev)
494544}
495545
496546static const struct meson_i2c_data i2c_meson6_data = {
497- .div_factor = 4 ,
547+ .set_clk_div = meson6_i2c_set_clk_div ,
498548};
499549
500550static const struct meson_i2c_data i2c_gxbb_data = {
501- .div_factor = 4 ,
551+ .set_clk_div = meson_gxbb_axg_i2c_set_clk_div ,
502552};
503553
504554static const struct meson_i2c_data i2c_axg_data = {
505- .div_factor = 3 ,
555+ .set_clk_div = meson_gxbb_axg_i2c_set_clk_div ,
506556};
507557
508558static const struct of_device_id meson_i2c_match [] = {
0 commit comments